diff --git a/src/NzbDrone.Core.Test/DataAugmentation/Scene/SceneMappingServiceFixture.cs b/src/NzbDrone.Core.Test/DataAugmentation/Scene/SceneMappingServiceFixture.cs index b94578c32..42b0156ff 100644 --- a/src/NzbDrone.Core.Test/DataAugmentation/Scene/SceneMappingServiceFixture.cs +++ b/src/NzbDrone.Core.Test/DataAugmentation/Scene/SceneMappingServiceFixture.cs @@ -20,11 +20,14 @@ namespace NzbDrone.Core.Test.DataAugmentation.Scene private Mock _provider1; private Mock _provider2; - + [SetUp] public void Setup() { - _fakeMappings = Builder.CreateListOfSize(5).BuildListOfNew(); + _fakeMappings = Builder.CreateListOfSize(5) + .All() + .With(v => v.FilterRegex = null) + .BuildListOfNew(); _fakeMappings[0].SearchTerm = "Words"; _fakeMappings[1].SearchTerm = "That"; @@ -193,7 +196,7 @@ namespace NzbDrone.Core.Test.DataAugmentation.Scene Mocker.GetMock().Setup(c => c.All()).Returns(mappings); var tvdbId = Subject.FindTvdbId(parseTitle); - var seasonNumber = Subject.GetSceneSeasonNumber(parseTitle); + var seasonNumber = Subject.GetSceneSeasonNumber(parseTitle, null); tvdbId.Should().Be(100); seasonNumber.Should().Be(expectedSeasonNumber); @@ -314,6 +317,35 @@ namespace NzbDrone.Core.Test.DataAugmentation.Scene Subject.GetSceneNames(100, new List { 4 }, new List { 4 }).Should().BeEmpty(); } + [Test] + public void should_filter_by_regex() + { + var mappings = new List + { + new SceneMapping { Title = "Amareto", ParseTerm = "amareto", SearchTerm = "Amareto", TvdbId = 100 }, + new SceneMapping { Title = "Amareto", ParseTerm = "amareto", SearchTerm = "Amareto", TvdbId = 101, FilterRegex="-Viva$" } + }; + + Mocker.GetMock().Setup(c => c.All()).Returns(mappings); + + Subject.FindTvdbId("Amareto", "Amareto.S01E01.720p.WEB-DL-Viva").Should().Be(101); + Subject.FindTvdbId("Amareto", "Amareto.S01E01.720p.WEB-DL-DMO").Should().Be(100); + } + + [Test] + public void should_throw_if_multiple_mappings() + { + var mappings = new List + { + new SceneMapping { Title = "Amareto", ParseTerm = "amareto", SearchTerm = "Amareto", TvdbId = 100 }, + new SceneMapping { Title = "Amareto", ParseTerm = "amareto", SearchTerm = "Amareto", TvdbId = 101 } + }; + + Mocker.GetMock().Setup(c => c.All()).Returns(mappings); + + Assert.Throws(() => Subject.FindTvdbId("Amareto", "Amareto.S01E01.720p.WEB-DL-Viva")); + } + private void AssertNoUpdate() { _provider1.Verify(c => c.GetSceneMappings(), Times.Once()); diff --git a/src/NzbDrone.Core.Test/ParserTests/ParsingServiceTests/GetEpisodesFixture.cs b/src/NzbDrone.Core.Test/ParserTests/ParsingServiceTests/GetEpisodesFixture.cs index 7221038e7..fb27d7437 100644 --- a/src/NzbDrone.Core.Test/ParserTests/ParsingServiceTests/GetEpisodesFixture.cs +++ b/src/NzbDrone.Core.Test/ParserTests/ParsingServiceTests/GetEpisodesFixture.cs @@ -192,7 +192,7 @@ namespace NzbDrone.Core.Test.ParserTests.ParsingServiceTests GivenAbsoluteNumberingSeries(); _parsedEpisodeInfo.Special = true; - + Subject.GetEpisodes(_parsedEpisodeInfo, _series, true, null); Mocker.GetMock() @@ -210,7 +210,7 @@ namespace NzbDrone.Core.Test.ParserTests.ParsingServiceTests GivenAbsoluteNumberingSeries(); Mocker.GetMock() - .Setup(s => s.GetSceneSeasonNumber(_parsedEpisodeInfo.SeriesTitle)) + .Setup(s => s.GetSceneSeasonNumber(_parsedEpisodeInfo.SeriesTitle, It.IsAny())) .Returns(seasonNumber); Mocker.GetMock() @@ -234,7 +234,7 @@ namespace NzbDrone.Core.Test.ParserTests.ParsingServiceTests GivenAbsoluteNumberingSeries(); Mocker.GetMock() - .Setup(s => s.GetSceneSeasonNumber(_parsedEpisodeInfo.SeriesTitle)) + .Setup(s => s.GetSceneSeasonNumber(_parsedEpisodeInfo.SeriesTitle, It.IsAny())) .Returns(seasonNumber); Mocker.GetMock() @@ -258,7 +258,7 @@ namespace NzbDrone.Core.Test.ParserTests.ParsingServiceTests GivenAbsoluteNumberingSeries(); Mocker.GetMock() - .Setup(s => s.GetSceneSeasonNumber(_parsedEpisodeInfo.SeriesTitle)) + .Setup(s => s.GetSceneSeasonNumber(_parsedEpisodeInfo.SeriesTitle, It.IsAny())) .Returns(seasonNumber); Mocker.GetMock() @@ -280,7 +280,7 @@ namespace NzbDrone.Core.Test.ParserTests.ParsingServiceTests const int tvdbSeasonNumber = 5; Mocker.GetMock() - .Setup(s => s.FindSceneMapping(_parsedEpisodeInfo.SeriesTitle)) + .Setup(s => s.FindSceneMapping(_parsedEpisodeInfo.SeriesTitle, It.IsAny())) .Returns(new SceneMapping { SeasonNumber = tvdbSeasonNumber, SceneSeasonNumber = _parsedEpisodeInfo.SeasonNumber }); Subject.GetEpisodes(_parsedEpisodeInfo, _series, true, null); @@ -298,7 +298,7 @@ namespace NzbDrone.Core.Test.ParserTests.ParsingServiceTests const int tvdbSeasonNumber = 5; Mocker.GetMock() - .Setup(s => s.FindSceneMapping(_parsedEpisodeInfo.SeriesTitle)) + .Setup(s => s.FindSceneMapping(_parsedEpisodeInfo.SeriesTitle, It.IsAny())) .Returns(new SceneMapping { SeasonNumber = tvdbSeasonNumber, SceneSeasonNumber = _parsedEpisodeInfo.SeasonNumber + 100 }); Subject.GetEpisodes(_parsedEpisodeInfo, _series, true, null); @@ -330,7 +330,7 @@ namespace NzbDrone.Core.Test.ParserTests.ParsingServiceTests const int tvdbSeasonNumber = -1; Mocker.GetMock() - .Setup(s => s.FindSceneMapping(_parsedEpisodeInfo.SeriesTitle)) + .Setup(s => s.FindSceneMapping(_parsedEpisodeInfo.SeriesTitle, It.IsAny())) .Returns(new SceneMapping { SeasonNumber = tvdbSeasonNumber, SceneSeasonNumber = _parsedEpisodeInfo.SeasonNumber }); Subject.GetEpisodes(_parsedEpisodeInfo, _series, true, null); diff --git a/src/NzbDrone.Core.Test/ParserTests/ParsingServiceTests/MapFixture.cs b/src/NzbDrone.Core.Test/ParserTests/ParsingServiceTests/MapFixture.cs index cbb616412..cce11375d 100644 --- a/src/NzbDrone.Core.Test/ParserTests/ParsingServiceTests/MapFixture.cs +++ b/src/NzbDrone.Core.Test/ParserTests/ParsingServiceTests/MapFixture.cs @@ -118,7 +118,7 @@ namespace NzbDrone.Core.Test.ParserTests.ParsingServiceTests GivenMatchByTvRageId(); Mocker.GetMock() - .Setup(v => v.FindTvdbId(It.IsAny())) + .Setup(v => v.FindTvdbId(It.IsAny(), It.IsAny())) .Returns(10); var result = Subject.Map(_parsedEpisodeInfo, _series.TvdbId, _series.TvRageId); @@ -199,7 +199,7 @@ namespace NzbDrone.Core.Test.ParserTests.ParsingServiceTests public void should_use_tvdbid_matching_when_alias_is_found() { Mocker.GetMock() - .Setup(s => s.FindTvdbId(It.IsAny())) + .Setup(s => s.FindTvdbId(It.IsAny(), It.IsAny())) .Returns(_series.TvdbId); Subject.Map(_parsedEpisodeInfo, _series.TvdbId, _series.TvRageId, _singleEpisodeSearchCriteria); diff --git a/src/NzbDrone.Core/DataAugmentation/Scene/InvalidSceneMappingException.cs b/src/NzbDrone.Core/DataAugmentation/Scene/InvalidSceneMappingException.cs new file mode 100644 index 000000000..8a89d1030 --- /dev/null +++ b/src/NzbDrone.Core/DataAugmentation/Scene/InvalidSceneMappingException.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using NzbDrone.Common.Exceptions; + +namespace NzbDrone.Core.DataAugmentation.Scene +{ + public class InvalidSceneMappingException : NzbDroneException + { + public InvalidSceneMappingException(IEnumerable mappings) + : base(FormatMessage(mappings)) + { + + } + + private static string FormatMessage(IEnumerable mappings) + { + return string.Format("Scene Mappings contains a conflict for tvdbids {0}, please notify Sonarr developers", mappings.Select(v => v.TvdbId)); + } + } +} diff --git a/src/NzbDrone.Core/DataAugmentation/Scene/SceneMapping.cs b/src/NzbDrone.Core/DataAugmentation/Scene/SceneMapping.cs index b992aa029..d45c92d7d 100644 --- a/src/NzbDrone.Core/DataAugmentation/Scene/SceneMapping.cs +++ b/src/NzbDrone.Core/DataAugmentation/Scene/SceneMapping.cs @@ -17,6 +17,9 @@ namespace NzbDrone.Core.DataAugmentation.Scene public int? SeasonNumber { get; set; } public int? SceneSeasonNumber { get; set; } + + public string FilterRegex { get; set; } + public string Type { get; set; } } -} \ No newline at end of file +} diff --git a/src/NzbDrone.Core/DataAugmentation/Scene/SceneMappingService.cs b/src/NzbDrone.Core/DataAugmentation/Scene/SceneMappingService.cs index 44385a88f..5b66f8fa4 100644 --- a/src/NzbDrone.Core/DataAugmentation/Scene/SceneMappingService.cs +++ b/src/NzbDrone.Core/DataAugmentation/Scene/SceneMappingService.cs @@ -8,17 +8,18 @@ using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Parser; using System.Collections.Generic; using NzbDrone.Core.Tv.Events; +using System.Text.RegularExpressions; namespace NzbDrone.Core.DataAugmentation.Scene { public interface ISceneMappingService { List GetSceneNames(int tvdbId, List seasonNumbers, List sceneSeasonNumbers); - int? FindTvdbId(string title); + int? FindTvdbId(string sceneTitle, string releaseTitle); List FindByTvdbId(int tvdbId); - SceneMapping FindSceneMapping(string title); - int? GetSceneSeasonNumber(string title); - int? GetTvdbSeasonNumber(string title); + SceneMapping FindSceneMapping(string sceneTitle, string releaseTitle); + int? GetSceneSeasonNumber(string seriesTitle, string releaseTitle); + int? GetTvdbSeasonNumber(string seriesTitle, string releaseTitle); int? GetSceneSeasonNumber(int tvdbId, int seasonNumber); } @@ -65,14 +66,14 @@ namespace NzbDrone.Core.DataAugmentation.Scene return FilterNonEnglish(names); } - public int? FindTvdbId(string title) + public int? FindTvdbId(string seriesTitle) { - var mapping = FindMapping(title); + return FindTvdbId(seriesTitle, null); + } - if (mapping == null) - return null; - - return mapping.TvdbId; + public int? FindTvdbId(string seriesTitle, string releaseTitle) + { + return FindSceneMapping(seriesTitle, releaseTitle)?.TvdbId; } public List FindByTvdbId(int tvdbId) @@ -92,33 +93,31 @@ namespace NzbDrone.Core.DataAugmentation.Scene return mappings; } - public SceneMapping FindSceneMapping(string title) + public SceneMapping FindSceneMapping(string seriesTitle, string releaseTitle) { - return FindMapping(title); - } + var mappings = FindMappings(seriesTitle, releaseTitle); - public int? GetSceneSeasonNumber(string title) - { - var mapping = FindMapping(title); - - if (mapping == null) + if (mappings == null) { return null; } - return mapping.SceneSeasonNumber; - } - - public int? GetTvdbSeasonNumber(string title) - { - var mapping = FindMapping(title); - - if (mapping == null) + if (mappings.Count <= 1) { - return null; + return mappings.FirstOrDefault(); } - return mapping.SeasonNumber; + throw new InvalidSceneMappingException(mappings); + } + + public int? GetSceneSeasonNumber(string seriesTitle, string releaseTitle) + { + return FindSceneMapping(seriesTitle, releaseTitle)?.SceneSeasonNumber; + } + + public int? GetTvdbSeasonNumber(string seriesTitle, string releaseTitle) + { + return FindSceneMapping(seriesTitle, releaseTitle)?.SeasonNumber; } public int? GetSceneSeasonNumber(int tvdbId, int seasonNumber) @@ -184,44 +183,48 @@ namespace NzbDrone.Core.DataAugmentation.Scene _logger.Error(ex, "Failed to Update Scene Mappings."); } } - + RefreshCache(); _eventAggregator.PublishEvent(new SceneMappingsUpdatedEvent()); } - private SceneMapping FindMapping(string title) + private List FindMappings(string seriesTitle, string releaseTitle) { if (_getTvdbIdCache.Count == 0) { RefreshCache(); } - var candidates = _getTvdbIdCache.Find(title.CleanSeriesTitle()); + var candidates = _getTvdbIdCache.Find(seriesTitle.CleanSeriesTitle()); if (candidates == null) { return null; } - if (candidates.Count == 1) + candidates = FilterSceneMappings(candidates, releaseTitle); + + if (candidates.Count <= 1) { - return candidates.First(); + return candidates; } var exactMatch = candidates.OrderByDescending(v => v.SeasonNumber) - .FirstOrDefault(v => v.Title == title); + .Where(v => v.Title == seriesTitle) + .ToList(); - if (exactMatch != null) + if (exactMatch.Any()) { return exactMatch; } - var closestMatch = candidates.OrderBy(v => title.LevenshteinDistance(v.Title, 10, 1, 10)) + var closestMatch = candidates.OrderBy(v => seriesTitle.LevenshteinDistance(v.Title, 10, 1, 10)) .ThenByDescending(v => v.SeasonNumber) .First(); - return closestMatch; + + return candidates.Where(v => v.Title == closestMatch.Title).ToList(); } private void RefreshCache() @@ -232,6 +235,26 @@ namespace NzbDrone.Core.DataAugmentation.Scene _findByTvdbIdCache.Update(mappings.GroupBy(v => v.TvdbId).ToDictionary(v => v.Key.ToString(), v => v.ToList())); } + private List FilterSceneMappings(List candidates, string releaseTitle) + { + var filteredCandidates = candidates.Where(v => v.FilterRegex.IsNotNullOrWhiteSpace()).ToList(); + var normalCandidates = candidates.Except(filteredCandidates).ToList(); + + if (releaseTitle.IsNullOrWhiteSpace()) + { + return normalCandidates; + } + + filteredCandidates = filteredCandidates.Where(v => Regex.IsMatch(releaseTitle, v.FilterRegex)).ToList(); + + if (filteredCandidates.Any()) + { + return filteredCandidates; + } + + return normalCandidates; + } + private List FilterNonEnglish(List titles) { return titles.Where(title => title.All(c => c <= 255)).ToList(); diff --git a/src/NzbDrone.Core/Datastore/Migration/112_added_regex_to_scenemapping.cs b/src/NzbDrone.Core/Datastore/Migration/112_added_regex_to_scenemapping.cs new file mode 100644 index 000000000..d95177a61 --- /dev/null +++ b/src/NzbDrone.Core/Datastore/Migration/112_added_regex_to_scenemapping.cs @@ -0,0 +1,16 @@ +using System.Data; +using FluentMigrator; +using NzbDrone.Common.Extensions; +using NzbDrone.Core.Datastore.Migration.Framework; + +namespace NzbDrone.Core.Datastore.Migration +{ + [Migration(112)] + public class added_regex_to_scenemapping : NzbDroneMigrationBase + { + protected override void MainDbUpgrade() + { + Alter.Table("SceneMappings").AddColumn("FilterRegex").AsString().Nullable(); + } + } +} diff --git a/src/NzbDrone.Core/NzbDrone.Core.csproj b/src/NzbDrone.Core/NzbDrone.Core.csproj index 8b8e8de54..cdc0c3ea3 100644 --- a/src/NzbDrone.Core/NzbDrone.Core.csproj +++ b/src/NzbDrone.Core/NzbDrone.Core.csproj @@ -140,6 +140,7 @@ + @@ -249,6 +250,7 @@ + diff --git a/src/NzbDrone.Core/Parser/Model/ParsedEpisodeInfo.cs b/src/NzbDrone.Core/Parser/Model/ParsedEpisodeInfo.cs index 256269c36..d38001715 100644 --- a/src/NzbDrone.Core/Parser/Model/ParsedEpisodeInfo.cs +++ b/src/NzbDrone.Core/Parser/Model/ParsedEpisodeInfo.cs @@ -6,6 +6,7 @@ namespace NzbDrone.Core.Parser.Model { public class ParsedEpisodeInfo { + public string ReleaseTitle { get; set; } public string SeriesTitle { get; set; } public SeriesTitleInfo SeriesTitleInfo { get; set; } public QualityModel Quality { get; set; } @@ -89,4 +90,4 @@ namespace NzbDrone.Core.Parser.Model return string.Format("{0} - {1} {2}", SeriesTitle, episodeString, Quality); } } -} \ No newline at end of file +} diff --git a/src/NzbDrone.Core/Parser/Parser.cs b/src/NzbDrone.Core/Parser/Parser.cs index a1142344d..814eb764f 100644 --- a/src/NzbDrone.Core/Parser/Parser.cs +++ b/src/NzbDrone.Core/Parser/Parser.cs @@ -316,9 +316,9 @@ namespace NzbDrone.Core.Parser Logger.Debug("Reversed name detected. Converted to '{0}'", title); } - var simpleTitle = SimpleTitleRegex.Replace(title, string.Empty); + title = RemoveFileExtension(title); - simpleTitle = RemoveFileExtension(simpleTitle); + var simpleTitle = SimpleTitleRegex.Replace(title, string.Empty); // TODO: Quick fix stripping [url] - prefixes. simpleTitle = WebsitePrefixRegex.Replace(simpleTitle, string.Empty); @@ -355,7 +355,7 @@ namespace NzbDrone.Core.Parser Logger.Trace(regex); try { - var result = ParseMatchCollection(match); + var result = ParseMatchCollection(match, title); if (result != null) { @@ -522,7 +522,7 @@ namespace NzbDrone.Core.Parser return seriesTitleInfo; } - private static ParsedEpisodeInfo ParseMatchCollection(MatchCollection matchCollection) + private static ParsedEpisodeInfo ParseMatchCollection(MatchCollection matchCollection, string title) { var seriesName = matchCollection[0].Groups["title"].Value.Replace('.', ' ').Replace('_', ' '); seriesName = RequestInfoRegex.Replace(seriesName, "").Trim(' '); @@ -551,6 +551,7 @@ namespace NzbDrone.Core.Parser result = new ParsedEpisodeInfo { + ReleaseTitle = title, SeasonNumber = seasons.First(), EpisodeNumbers = new int[0], AbsoluteEpisodeNumbers = new int[0] @@ -644,6 +645,7 @@ namespace NzbDrone.Core.Parser result = new ParsedEpisodeInfo { + ReleaseTitle = title, AirDate = airDate.ToString(Episode.AIR_DATE_FORMAT), }; } diff --git a/src/NzbDrone.Core/Parser/ParsingService.cs b/src/NzbDrone.Core/Parser/ParsingService.cs index 6d0ee7f6c..eae9bb3d6 100644 --- a/src/NzbDrone.Core/Parser/ParsingService.cs +++ b/src/NzbDrone.Core/Parser/ParsingService.cs @@ -19,7 +19,7 @@ namespace NzbDrone.Core.Parser RemoteEpisode Map(ParsedEpisodeInfo parsedEpisodeInfo, int tvdbId, int tvRageId, SearchCriteriaBase searchCriteria = null); RemoteEpisode Map(ParsedEpisodeInfo parsedEpisodeInfo, int seriesId, IEnumerable episodeIds); List GetEpisodes(ParsedEpisodeInfo parsedEpisodeInfo, Series series, bool sceneSource, SearchCriteriaBase searchCriteria = null); - ParsedEpisodeInfo ParseSpecialEpisodeTitle(string title, int tvdbId, int tvRageId, SearchCriteriaBase searchCriteria = null); + ParsedEpisodeInfo ParseSpecialEpisodeTitle(string releaseTitle, int tvdbId, int tvRageId, SearchCriteriaBase searchCriteria = null); } public class ParsingService : IParsingService @@ -103,6 +103,13 @@ namespace NzbDrone.Core.Parser return _seriesService.FindByTitle(title); } + var tvdbId = _sceneMappingService.FindTvdbId(parsedEpisodeInfo.SeriesTitle, parsedEpisodeInfo.ReleaseTitle); + + if (tvdbId.HasValue) + { + return _seriesService.FindByTvdbId(tvdbId.Value); + } + var series = _seriesService.FindByTitle(parsedEpisodeInfo.SeriesTitle); if (series == null) @@ -177,29 +184,26 @@ namespace NzbDrone.Core.Parser return GetStandardEpisodes(series, parsedEpisodeInfo, sceneSource, searchCriteria); } - public ParsedEpisodeInfo ParseSpecialEpisodeTitle(string title, int tvdbId, int tvRageId, SearchCriteriaBase searchCriteria = null) + public ParsedEpisodeInfo ParseSpecialEpisodeTitle(string releaseTitle, int tvdbId, int tvRageId, SearchCriteriaBase searchCriteria = null) { if (searchCriteria != null) { - if (tvdbId == 0) - tvdbId = _sceneMappingService.FindTvdbId(title) ?? 0; - if (tvdbId != 0 && tvdbId == searchCriteria.Series.TvdbId) { - return ParseSpecialEpisodeTitle(title, searchCriteria.Series); + return ParseSpecialEpisodeTitle(releaseTitle, searchCriteria.Series); } if (tvRageId != 0 && tvRageId == searchCriteria.Series.TvRageId) { - return ParseSpecialEpisodeTitle(title, searchCriteria.Series); + return ParseSpecialEpisodeTitle(releaseTitle, searchCriteria.Series); } } - var series = GetSeries(title); + var series = GetSeries(releaseTitle); if (series == null) { - series = _seriesService.FindByTitleInexact(title); + series = _seriesService.FindByTitleInexact(releaseTitle); } if (series == null && tvdbId > 0) @@ -214,34 +218,39 @@ namespace NzbDrone.Core.Parser if (series == null) { - _logger.Debug("No matching series {0}", title); + _logger.Debug("No matching series {0}", releaseTitle); return null; } - return ParseSpecialEpisodeTitle(title, series); + return ParseSpecialEpisodeTitle(releaseTitle, series); } - private ParsedEpisodeInfo ParseSpecialEpisodeTitle(string title, Series series) + private ParsedEpisodeInfo ParseSpecialEpisodeTitle(string releaseTitle, Series series) { // find special episode in series season 0 - var episode = _episodeService.FindEpisodeByTitle(series.Id, 0, title); + var episode = _episodeService.FindEpisodeByTitle(series.Id, 0, releaseTitle); if (episode != null) { // create parsed info from tv episode - var info = new ParsedEpisodeInfo(); - info.SeriesTitle = series.Title; - info.SeriesTitleInfo = new SeriesTitleInfo(); - info.SeriesTitleInfo.Title = info.SeriesTitle; - info.SeasonNumber = episode.SeasonNumber; - info.EpisodeNumbers = new int[1] { episode.EpisodeNumber }; - info.FullSeason = false; - info.Quality = QualityParser.ParseQuality(title); - info.ReleaseGroup = Parser.ParseReleaseGroup(title); - info.Language = LanguageParser.ParseLanguage(title); - info.Special = true; + var info = new ParsedEpisodeInfo + { + ReleaseTitle = releaseTitle, + SeriesTitle = series.Title, + SeriesTitleInfo = new SeriesTitleInfo + { + Title = series.Title + }, + SeasonNumber = episode.SeasonNumber, + EpisodeNumbers = new int[1] { episode.EpisodeNumber }, + FullSeason = false, + Quality = QualityParser.ParseQuality(releaseTitle), + ReleaseGroup = Parser.ParseReleaseGroup(releaseTitle), + Language = LanguageParser.ParseLanguage(releaseTitle), + Special = true + }; - _logger.Debug("Found special episode {0} for title '{1}'", info, title); + _logger.Debug("Found special episode {0} for title '{1}'", info, releaseTitle); return info; } @@ -252,7 +261,7 @@ namespace NzbDrone.Core.Parser { Series series = null; - var sceneMappingTvdbId = _sceneMappingService.FindTvdbId(parsedEpisodeInfo.SeriesTitle); + var sceneMappingTvdbId = _sceneMappingService.FindTvdbId(parsedEpisodeInfo.SeriesTitle, parsedEpisodeInfo.ReleaseTitle); if (sceneMappingTvdbId.HasValue) { if (searchCriteria != null && searchCriteria.Series.TvdbId == sceneMappingTvdbId.Value) @@ -341,7 +350,7 @@ namespace NzbDrone.Core.Parser { var result = new List(); - var sceneSeasonNumber = _sceneMappingService.GetSceneSeasonNumber(parsedEpisodeInfo.SeriesTitle); + var sceneSeasonNumber = _sceneMappingService.GetSceneSeasonNumber(parsedEpisodeInfo.SeriesTitle, parsedEpisodeInfo.ReleaseTitle); foreach (var absoluteEpisodeNumber in parsedEpisodeInfo.AbsoluteEpisodeNumbers) { @@ -405,7 +414,7 @@ namespace NzbDrone.Core.Parser if (sceneSource) { - var sceneMapping = _sceneMappingService.FindSceneMapping(parsedEpisodeInfo.SeriesTitle); + var sceneMapping = _sceneMappingService.FindSceneMapping(parsedEpisodeInfo.SeriesTitle, parsedEpisodeInfo.ReleaseTitle); if (sceneMapping != null && sceneMapping.SeasonNumber.HasValue && sceneMapping.SeasonNumber.Value >= 0 && sceneMapping.SceneSeasonNumber == seasonNumber) @@ -475,4 +484,4 @@ namespace NzbDrone.Core.Parser return result; } } -} \ No newline at end of file +} diff --git a/src/NzbDrone.Core/Tv/SeriesService.cs b/src/NzbDrone.Core/Tv/SeriesService.cs index f4db2b0a4..171517ab3 100644 --- a/src/NzbDrone.Core/Tv/SeriesService.cs +++ b/src/NzbDrone.Core/Tv/SeriesService.cs @@ -35,21 +35,18 @@ namespace NzbDrone.Core.Tv { private readonly ISeriesRepository _seriesRepository; private readonly IEventAggregator _eventAggregator; - private readonly ISceneMappingService _sceneMappingService; private readonly IEpisodeService _episodeService; private readonly IBuildFileNames _fileNameBuilder; private readonly Logger _logger; public SeriesService(ISeriesRepository seriesRepository, IEventAggregator eventAggregator, - ISceneMappingService sceneMappingService, IEpisodeService episodeService, IBuildFileNames fileNameBuilder, Logger logger) { _seriesRepository = seriesRepository; _eventAggregator = eventAggregator; - _sceneMappingService = sceneMappingService; _episodeService = episodeService; _fileNameBuilder = fileNameBuilder; _logger = logger; @@ -85,13 +82,6 @@ namespace NzbDrone.Core.Tv public Series FindByTitle(string title) { - var tvdbId = _sceneMappingService.FindTvdbId(title); - - if (tvdbId.HasValue) - { - return _seriesRepository.FindByTvdbId(tvdbId.Value); - } - return _seriesRepository.FindByTitle(title.CleanSeriesTitle()); } @@ -107,11 +97,11 @@ namespace NzbDrone.Core.Tv } if (list.Count == 1) { - // return the first series if there is only one + // return the first series if there is only one return list.Single(); } // build ordered list of series by position in the search string - var query = + var query = list.Select(series => new { position = cleanTitle.IndexOf(series.CleanTitle), @@ -192,7 +182,7 @@ namespace NzbDrone.Core.Tv _logger.Trace("Not changing path for: {0}", s.Title); } } - + _seriesRepository.UpdateMany(series); _logger.Debug("{0} series updated", series.Count);