From fcfdac99d594f5e9b9b1dcaa4097a00a92c84ca7 Mon Sep 17 00:00:00 2001 From: Mark McDowall Date: Sat, 14 Feb 2026 19:32:35 -0800 Subject: [PATCH] New: Parse series if year is added to known alias Closes #8408 --- .../ParsingServiceTests/MapFixture.cs | 50 +++++++++++++++++++ src/NzbDrone.Core/Parser/ParsingService.cs | 25 ++++++++++ 2 files changed, 75 insertions(+) diff --git a/src/NzbDrone.Core.Test/ParserTests/ParsingServiceTests/MapFixture.cs b/src/NzbDrone.Core.Test/ParserTests/ParsingServiceTests/MapFixture.cs index 5b26d0461..0f0da6768 100644 --- a/src/NzbDrone.Core.Test/ParserTests/ParsingServiceTests/MapFixture.cs +++ b/src/NzbDrone.Core.Test/ParserTests/ParsingServiceTests/MapFixture.cs @@ -293,5 +293,55 @@ namespace NzbDrone.Core.Test.ParserTests.ParsingServiceTests result.MappedSeasonNumber.Should().Be(sceneMapping.SceneSeasonNumber); } + + [Test] + public void should_use_tvdbid_matching_when_alias_without_year_is_found() + { + var alias = "Series Alias"; + + _parsedEpisodeInfo.SeriesTitle = $"{alias} {_series.Year}"; + _parsedEpisodeInfo.SeriesTitleInfo.TitleWithoutYear = alias; + _parsedEpisodeInfo.SeriesTitleInfo.Year = _series.Year; + + Mocker.GetMock() + .Setup(s => s.FindTvdbId(alias, It.IsAny(), It.IsAny())) + .Returns(_series.TvdbId); + + Mocker.GetMock() + .Setup(s => s.FindByTvdbId(_series.Id)) + .Returns(_series); + + var result = Subject.Map(_parsedEpisodeInfo, _series.TvdbId, _series.TvRageId, _series.ImdbId, null); + + result.Series.Should().Be(_series); + + Mocker.GetMock() + .Verify(v => v.FindByTvdbId(It.IsAny()), Times.Once()); + } + + [Test] + public void should_not_use_tvdbid_matching_when_alias_without_year_is_found_with_wrong_year() + { + var alias = "Series Alias"; + + _parsedEpisodeInfo.SeriesTitle = $"{alias} {_series.Year}"; + _parsedEpisodeInfo.SeriesTitleInfo.TitleWithoutYear = alias; + _parsedEpisodeInfo.SeriesTitleInfo.Year = _series.Year + 1; + + Mocker.GetMock() + .Setup(s => s.FindTvdbId(alias, It.IsAny(), It.IsAny())) + .Returns(_series.TvdbId); + + Mocker.GetMock() + .Setup(s => s.FindByTvdbId(_series.Id)) + .Returns(_series); + + var result = Subject.Map(_parsedEpisodeInfo, 0, 0, "", null); + + result.Series.Should().BeNull(); + + Mocker.GetMock() + .Verify(v => v.FindByTvdbId(It.IsAny()), Times.Once()); + } } } diff --git a/src/NzbDrone.Core/Parser/ParsingService.cs b/src/NzbDrone.Core/Parser/ParsingService.cs index 30f5943e2..5b857c002 100644 --- a/src/NzbDrone.Core/Parser/ParsingService.cs +++ b/src/NzbDrone.Core/Parser/ParsingService.cs @@ -116,6 +116,25 @@ namespace NzbDrone.Core.Parser return foundSeries; } + private Series GetSeriesAliasTitleAndYear(ParsedEpisodeInfo parsedEpisodeInfo) + { + var year = parsedEpisodeInfo.SeriesTitleInfo.Year; + var titleWithoutyear = parsedEpisodeInfo.SeriesTitleInfo.TitleWithoutYear; + var tvdbId = _sceneMappingService.FindTvdbId(titleWithoutyear, parsedEpisodeInfo.ReleaseTitle, parsedEpisodeInfo.SeasonNumber); + + if (tvdbId.HasValue) + { + var series = _seriesService.FindByTvdbId(tvdbId.Value); + + if (series.Year == year) + { + return series; + } + } + + return null; + } + public RemoteEpisode Map(ParsedEpisodeInfo parsedEpisodeInfo, int tvdbId, int tvRageId, string imdbId, SearchCriteriaBase searchCriteria = null) { return Map(parsedEpisodeInfo, tvdbId, tvRageId, imdbId, null, searchCriteria); @@ -449,6 +468,12 @@ namespace NzbDrone.Core.Parser { series = _seriesService.FindByTitle(parsedEpisodeInfo.SeriesTitleInfo.TitleWithoutYear, parsedEpisodeInfo.SeriesTitleInfo.Year); matchType = SeriesMatchType.Title; + + if (series == null) + { + series = GetSeriesAliasTitleAndYear(parsedEpisodeInfo); + matchType = SeriesMatchType.Alias; + } } if (series == null && tvdbId > 0)