Added name + year lookups
New: Support series lookup when year has been appended to the release name
This commit is contained in:
parent
da0f04d4c8
commit
436644318b
|
@ -169,7 +169,9 @@
|
||||||
<Compile Include="NotificationTests\Xbmc\Json\UpdateFixture.cs" />
|
<Compile Include="NotificationTests\Xbmc\Json\UpdateFixture.cs" />
|
||||||
<Compile Include="OrganizerTests\BuildFilePathFixture.cs" />
|
<Compile Include="OrganizerTests\BuildFilePathFixture.cs" />
|
||||||
<Compile Include="ParserTests\ParsingServiceTests\GetEpisodesFixture.cs" />
|
<Compile Include="ParserTests\ParsingServiceTests\GetEpisodesFixture.cs" />
|
||||||
|
<Compile Include="ParserTests\ParsingServiceTests\GetSeriesFixture.cs" />
|
||||||
<Compile Include="ParserTests\ParsingServiceTests\MapFixture.cs" />
|
<Compile Include="ParserTests\ParsingServiceTests\MapFixture.cs" />
|
||||||
|
<Compile Include="ParserTests\SeriesTitleInfoFixture.cs" />
|
||||||
<Compile Include="Providers\XemProxyFixture.cs" />
|
<Compile Include="Providers\XemProxyFixture.cs" />
|
||||||
<Compile Include="Qualities\QualitySizeRepositoryFixture.cs" />
|
<Compile Include="Qualities\QualitySizeRepositoryFixture.cs" />
|
||||||
<Compile Include="Qualities\QualityProfileRepositoryFixture.cs" />
|
<Compile Include="Qualities\QualityProfileRepositoryFixture.cs" />
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using Moq;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using NzbDrone.Core.Parser;
|
||||||
|
using NzbDrone.Core.Test.Framework;
|
||||||
|
using NzbDrone.Core.Tv;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Test.ParserTests.ParsingServiceTests
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class GetSeriesFixture : CoreTest<ParsingService>
|
||||||
|
{
|
||||||
|
[Test]
|
||||||
|
public void should_use_passed_in_title_when_it_cannot_be_parsed()
|
||||||
|
{
|
||||||
|
const string title = "30 Rock";
|
||||||
|
|
||||||
|
Subject.GetSeries(title);
|
||||||
|
|
||||||
|
Mocker.GetMock<ISeriesService>()
|
||||||
|
.Verify(s => s.FindByTitle(title), Times.Once());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_use_parsed_series_title()
|
||||||
|
{
|
||||||
|
const string title = "30.Rock.S01E01.720p.hdtv";
|
||||||
|
|
||||||
|
Subject.GetSeries(title);
|
||||||
|
|
||||||
|
Mocker.GetMock<ISeriesService>()
|
||||||
|
.Verify(s => s.FindByTitle(Parser.Parser.ParseTitle(title).SeriesTitle), Times.Once());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_fallback_to_title_without_year_and_year_when_title_lookup_fails()
|
||||||
|
{
|
||||||
|
const string title = "House.2004.S01E01.720p.hdtv";
|
||||||
|
var parsedEpisodeInfo = Parser.Parser.ParseTitle(title);
|
||||||
|
|
||||||
|
Subject.GetSeries(title);
|
||||||
|
|
||||||
|
Mocker.GetMock<ISeriesService>()
|
||||||
|
.Verify(s => s.FindByTitle(parsedEpisodeInfo.SeriesTitleInfo.TitleWithoutYear,
|
||||||
|
parsedEpisodeInfo.SeriesTitleInfo.Year), Times.Once());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,64 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using FluentAssertions;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using NzbDrone.Core.Test.Framework;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Test.ParserTests
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class SeriesTitleInfoFixture : CoreTest
|
||||||
|
{
|
||||||
|
[Test]
|
||||||
|
public void should_have_year_zero_when_title_doesnt_have_a_year()
|
||||||
|
{
|
||||||
|
const string title = "House.S01E01.pilot.720p.hdtv";
|
||||||
|
|
||||||
|
var result = Parser.Parser.ParseTitle(title).SeriesTitleInfo;
|
||||||
|
|
||||||
|
result.Year.Should().Be(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_have_same_title_for_title_and_title_without_year_when_title_doesnt_have_a_year()
|
||||||
|
{
|
||||||
|
const string title = "House.S01E01.pilot.720p.hdtv";
|
||||||
|
|
||||||
|
var result = Parser.Parser.ParseTitle(title).SeriesTitleInfo;
|
||||||
|
|
||||||
|
result.Title.Should().Be(result.TitleWithoutYear);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_have_year_when_title_has_a_year()
|
||||||
|
{
|
||||||
|
const string title = "House.2004.S01E01.pilot.720p.hdtv";
|
||||||
|
|
||||||
|
var result = Parser.Parser.ParseTitle(title).SeriesTitleInfo;
|
||||||
|
|
||||||
|
result.Year.Should().Be(2004);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_have_year_in_title_when_title_has_a_year()
|
||||||
|
{
|
||||||
|
const string title = "House.2004.S01E01.pilot.720p.hdtv";
|
||||||
|
|
||||||
|
var result = Parser.Parser.ParseTitle(title).SeriesTitleInfo;
|
||||||
|
|
||||||
|
result.Title.Should().Be("house2004");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_title_without_year_should_not_contain_year()
|
||||||
|
{
|
||||||
|
const string title = "House.2004.S01E01.pilot.720p.hdtv";
|
||||||
|
|
||||||
|
var result = Parser.Parser.ParseTitle(title).SeriesTitleInfo;
|
||||||
|
|
||||||
|
result.TitleWithoutYear.Should().Be("house");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -319,6 +319,7 @@
|
||||||
<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="Parser\InvalidDateException.cs" />
|
||||||
|
<Compile Include="Parser\Model\SeriesTitleInfo.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" />
|
||||||
|
|
|
@ -7,6 +7,7 @@ namespace NzbDrone.Core.Parser.Model
|
||||||
public class ParsedEpisodeInfo
|
public class ParsedEpisodeInfo
|
||||||
{
|
{
|
||||||
public string SeriesTitle { get; set; }
|
public string SeriesTitle { get; set; }
|
||||||
|
public SeriesTitleInfo SeriesTitleInfo { get; set; }
|
||||||
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; }
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Parser.Model
|
||||||
|
{
|
||||||
|
public class SeriesTitleInfo
|
||||||
|
{
|
||||||
|
public string Title { get; set; }
|
||||||
|
public string TitleWithoutYear { get; set; }
|
||||||
|
public int Year { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -76,6 +76,9 @@ namespace NzbDrone.Core.Parser
|
||||||
private static readonly Regex LanguageRegex = new Regex(@"(?:\W|_)(?<italian>ita|italian)|(?<german>german\b)|(?<flemish>flemish)|(?<greek>greek)|(?<french>(?:\W|_)FR)(?:\W|_)",
|
private static readonly Regex LanguageRegex = new Regex(@"(?:\W|_)(?<italian>ita|italian)|(?<german>german\b)|(?<flemish>flemish)|(?<greek>greek)|(?<french>(?:\W|_)FR)(?:\W|_)",
|
||||||
RegexOptions.IgnoreCase | RegexOptions.Compiled);
|
RegexOptions.IgnoreCase | RegexOptions.Compiled);
|
||||||
|
|
||||||
|
private static readonly Regex YearInTitleRegex = new Regex(@"^(?<title>.+?)(?:\W|_)?(?<year>\d{4})",
|
||||||
|
RegexOptions.IgnoreCase | RegexOptions.Compiled);
|
||||||
|
|
||||||
public static ParsedEpisodeInfo ParsePath(string path)
|
public static ParsedEpisodeInfo ParsePath(string path)
|
||||||
{
|
{
|
||||||
var fileInfo = new FileInfo(path);
|
var fileInfo = new FileInfo(path);
|
||||||
|
@ -139,6 +142,58 @@ namespace NzbDrone.Core.Parser
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static string ParseSeriesName(string title)
|
||||||
|
{
|
||||||
|
Logger.Trace("Parsing string '{0}'", title);
|
||||||
|
|
||||||
|
var parseResult = ParseTitle(title);
|
||||||
|
|
||||||
|
if (parseResult == null)
|
||||||
|
{
|
||||||
|
return CleanSeriesTitle(title);
|
||||||
|
}
|
||||||
|
|
||||||
|
return parseResult.SeriesTitle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string CleanSeriesTitle(this string title)
|
||||||
|
{
|
||||||
|
long number = 0;
|
||||||
|
|
||||||
|
//If Title only contains numbers return it as is.
|
||||||
|
if (Int64.TryParse(title, out number))
|
||||||
|
return title;
|
||||||
|
|
||||||
|
return NormalizeRegex.Replace(title, String.Empty).ToLower();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string CleanupEpisodeTitle(string title)
|
||||||
|
{
|
||||||
|
//this will remove (1),(2) from the end of multi part episodes.
|
||||||
|
return MultiPartCleanupRegex.Replace(title, string.Empty).Trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static SeriesTitleInfo GetSeriesTitleInfo(string title)
|
||||||
|
{
|
||||||
|
var seriesTitleInfo = new SeriesTitleInfo();
|
||||||
|
seriesTitleInfo.Title = title;
|
||||||
|
|
||||||
|
var match = YearInTitleRegex.Match(title);
|
||||||
|
|
||||||
|
if (!match.Success)
|
||||||
|
{
|
||||||
|
seriesTitleInfo.TitleWithoutYear = title;
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
seriesTitleInfo.TitleWithoutYear = match.Groups["title"].Value;
|
||||||
|
seriesTitleInfo.Year = Convert.ToInt32(match.Groups["year"].Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return seriesTitleInfo;
|
||||||
|
}
|
||||||
|
|
||||||
private static ParsedEpisodeInfo ParseMatchCollection(MatchCollection matchCollection)
|
private static ParsedEpisodeInfo ParseMatchCollection(MatchCollection matchCollection)
|
||||||
{
|
{
|
||||||
var seriesName = matchCollection[0].Groups["title"].Value.Replace('.', ' ');
|
var seriesName = matchCollection[0].Groups["title"].Value.Replace('.', ' ');
|
||||||
|
@ -168,10 +223,10 @@ namespace NzbDrone.Core.Parser
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
result = new ParsedEpisodeInfo
|
result = new ParsedEpisodeInfo
|
||||||
{
|
{
|
||||||
SeasonNumber = seasons.First(),
|
SeasonNumber = seasons.First(),
|
||||||
EpisodeNumbers = new int[0],
|
EpisodeNumbers = new int[0],
|
||||||
};
|
};
|
||||||
|
|
||||||
foreach (Match matchGroup in matchCollection)
|
foreach (Match matchGroup in matchCollection)
|
||||||
{
|
{
|
||||||
|
@ -226,32 +281,19 @@ namespace NzbDrone.Core.Parser
|
||||||
}
|
}
|
||||||
|
|
||||||
result = new ParsedEpisodeInfo
|
result = new ParsedEpisodeInfo
|
||||||
{
|
{
|
||||||
AirDate = airDate.ToString(Episode.AIR_DATE_FORMAT),
|
AirDate = airDate.ToString(Episode.AIR_DATE_FORMAT),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
result.SeriesTitle = CleanSeriesTitle(seriesName);
|
result.SeriesTitle = CleanSeriesTitle(seriesName);
|
||||||
|
result.SeriesTitleInfo = GetSeriesTitleInfo(result.SeriesTitle);
|
||||||
|
|
||||||
Logger.Trace("Episode Parsed. {0}", result);
|
Logger.Trace("Episode Parsed. {0}", result);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string ParseSeriesName(string title)
|
|
||||||
{
|
|
||||||
Logger.Trace("Parsing string '{0}'", title);
|
|
||||||
|
|
||||||
var parseResult = ParseTitle(title);
|
|
||||||
|
|
||||||
if (parseResult == null)
|
|
||||||
{
|
|
||||||
return CleanSeriesTitle(title);
|
|
||||||
}
|
|
||||||
|
|
||||||
return parseResult.SeriesTitle;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Language ParseLanguage(string title)
|
private static Language ParseLanguage(string title)
|
||||||
{
|
{
|
||||||
var lowerTitle = title.ToLower();
|
var lowerTitle = title.ToLower();
|
||||||
|
@ -345,22 +387,5 @@ namespace NzbDrone.Core.Parser
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string CleanSeriesTitle(this string title)
|
|
||||||
{
|
|
||||||
long number = 0;
|
|
||||||
|
|
||||||
//If Title only contains numbers return it as is.
|
|
||||||
if (Int64.TryParse(title, out number))
|
|
||||||
return title;
|
|
||||||
|
|
||||||
return NormalizeRegex.Replace(title, String.Empty).ToLower();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string CleanupEpisodeTitle(string title)
|
|
||||||
{
|
|
||||||
//this will remove (1),(2) from the end of multi part episodes.
|
|
||||||
return MultiPartCleanupRegex.Replace(title, string.Empty).Trim();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -68,15 +68,22 @@ namespace NzbDrone.Core.Parser
|
||||||
|
|
||||||
public Series GetSeries(string title)
|
public Series GetSeries(string title)
|
||||||
{
|
{
|
||||||
var searchTitle = title;
|
|
||||||
var parsedEpisodeInfo = Parser.ParseTitle(title);
|
var parsedEpisodeInfo = Parser.ParseTitle(title);
|
||||||
|
|
||||||
if (parsedEpisodeInfo != null)
|
if (parsedEpisodeInfo == null)
|
||||||
{
|
{
|
||||||
searchTitle = parsedEpisodeInfo.SeriesTitle;
|
return _seriesService.FindByTitle(title);
|
||||||
}
|
}
|
||||||
|
|
||||||
return _seriesService.FindByTitle(searchTitle);
|
var series = _seriesService.FindByTitle(parsedEpisodeInfo.SeriesTitle);
|
||||||
|
|
||||||
|
if (series == null)
|
||||||
|
{
|
||||||
|
series = _seriesService.FindByTitle(parsedEpisodeInfo.SeriesTitleInfo.TitleWithoutYear,
|
||||||
|
parsedEpisodeInfo.SeriesTitleInfo.Year);
|
||||||
|
}
|
||||||
|
|
||||||
|
return series;
|
||||||
}
|
}
|
||||||
|
|
||||||
public RemoteEpisode Map(ParsedEpisodeInfo parsedEpisodeInfo, int tvRageId, SearchCriteriaBase searchCriteria = null)
|
public RemoteEpisode Map(ParsedEpisodeInfo parsedEpisodeInfo, int tvRageId, SearchCriteriaBase searchCriteria = null)
|
||||||
|
|
|
@ -10,6 +10,7 @@ namespace NzbDrone.Core.Tv
|
||||||
{
|
{
|
||||||
bool SeriesPathExists(string path);
|
bool SeriesPathExists(string path);
|
||||||
Series FindByTitle(string cleanTitle);
|
Series FindByTitle(string cleanTitle);
|
||||||
|
Series FindByTitle(string cleanTitle, int year);
|
||||||
Series FindByTvdbId(int tvdbId);
|
Series FindByTvdbId(int tvdbId);
|
||||||
Series FindByTvRageId(int tvRageId);
|
Series FindByTvRageId(int tvRageId);
|
||||||
void SetSeriesType(int seriesId, SeriesTypes seriesTypes);
|
void SetSeriesType(int seriesId, SeriesTypes seriesTypes);
|
||||||
|
@ -32,6 +33,12 @@ namespace NzbDrone.Core.Tv
|
||||||
return Query.SingleOrDefault(s => s.CleanTitle.Equals(cleanTitle, StringComparison.InvariantCultureIgnoreCase));
|
return Query.SingleOrDefault(s => s.CleanTitle.Equals(cleanTitle, StringComparison.InvariantCultureIgnoreCase));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Series FindByTitle(string cleanTitle, int year)
|
||||||
|
{
|
||||||
|
return Query.SingleOrDefault(s => s.CleanTitle.Equals(cleanTitle, StringComparison.InvariantCultureIgnoreCase) &&
|
||||||
|
s.Year == year);
|
||||||
|
}
|
||||||
|
|
||||||
public Series FindByTvdbId(int tvdbId)
|
public Series FindByTvdbId(int tvdbId)
|
||||||
{
|
{
|
||||||
return Query.SingleOrDefault(s => s.TvdbId.Equals(tvdbId));
|
return Query.SingleOrDefault(s => s.TvdbId.Equals(tvdbId));
|
||||||
|
|
|
@ -19,6 +19,7 @@ namespace NzbDrone.Core.Tv
|
||||||
Series FindByTvdbId(int tvdbId);
|
Series FindByTvdbId(int tvdbId);
|
||||||
Series FindByTvRageId(int tvRageId);
|
Series FindByTvRageId(int tvRageId);
|
||||||
Series FindByTitle(string title);
|
Series FindByTitle(string title);
|
||||||
|
Series FindByTitle(string title, int year);
|
||||||
void SetSeriesType(int seriesId, SeriesTypes seriesTypes);
|
void SetSeriesType(int seriesId, SeriesTypes seriesTypes);
|
||||||
void DeleteSeries(int seriesId, bool deleteFiles);
|
void DeleteSeries(int seriesId, bool deleteFiles);
|
||||||
List<Series> GetAllSeries();
|
List<Series> GetAllSeries();
|
||||||
|
@ -100,6 +101,11 @@ namespace NzbDrone.Core.Tv
|
||||||
return _seriesRepository.FindByTitle(Parser.Parser.CleanSeriesTitle(title));
|
return _seriesRepository.FindByTitle(Parser.Parser.CleanSeriesTitle(title));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Series FindByTitle(string title, int year)
|
||||||
|
{
|
||||||
|
return _seriesRepository.FindByTitle(title, year);
|
||||||
|
}
|
||||||
|
|
||||||
public void SetSeriesType(int seriesId, SeriesTypes seriesTypes)
|
public void SetSeriesType(int seriesId, SeriesTypes seriesTypes)
|
||||||
{
|
{
|
||||||
_seriesRepository.SetSeriesType(seriesId, seriesTypes);
|
_seriesRepository.SetSeriesType(seriesId, seriesTypes);
|
||||||
|
|
Loading…
Reference in New Issue