1
0
mirror of https://github.com/Sonarr/Sonarr.git synced 2024-12-14 11:23:42 +02:00

Fixed: Parsing anime dual language titles

closes #3756
This commit is contained in:
Taloth Saldono 2020-05-17 23:01:41 +02:00
parent 5251db7224
commit a75e10c4c9
6 changed files with 94 additions and 2 deletions

View File

@ -3,6 +3,7 @@
using NzbDrone.Common.Extensions;
using NzbDrone.Core.Parser;
using Sonarr.Http;
using Sonarr.Http.REST;
namespace NzbDrone.Api.Parse
{
@ -21,6 +22,12 @@ private ParseResource Parse()
{
var title = Request.Query.Title.Value as string;
var path = Request.Query.Path.Value as string;
if (path.IsNullOrWhiteSpace() && title.IsNullOrWhiteSpace())
{
throw new BadRequestException("title or path is missing");
}
var parsedEpisodeInfo = path.IsNotNullOrWhiteSpace() ? Parser.ParsePath(path) : Parser.ParseTitle(title);
if (parsedEpisodeInfo == null)

View File

@ -1,5 +1,7 @@
using Moq;
using FluentAssertions;
using Moq;
using NUnit.Framework;
using NzbDrone.Core.DataAugmentation.Scene;
using NzbDrone.Core.Parser;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Core.Tv;
@ -43,5 +45,18 @@ public void should_fallback_to_title_without_year_and_year_when_title_lookup_fai
.Verify(s => s.FindByTitle(parsedEpisodeInfo.SeriesTitleInfo.TitleWithoutYear,
parsedEpisodeInfo.SeriesTitleInfo.Year), Times.Once());
}
[Test]
public void should_parse_concatenated_title()
{
var series = new Series { TvdbId = 100 };
Mocker.GetMock<ISeriesService>().Setup(v => v.FindByTitle("Welcome")).Returns(series);
Mocker.GetMock<ISceneMappingService>().Setup(v => v.FindTvdbId("Mairimashita", It.IsAny<string>())).Returns(100);
var result = Subject.GetSeries("Welcome (Mairimashita).S01E01.720p.WEB-DL-Viva");
result.Should().NotBeNull();
result.TvdbId.Should().Be(100);
}
}
}

View File

@ -5,5 +5,6 @@ public class SeriesTitleInfo
public string Title { get; set; }
public string TitleWithoutYear { get; set; }
public int Year { get; set; }
public string[] AllTitles { get; set; }
}
}

View File

@ -385,6 +385,9 @@ public static class Parser
private static readonly Regex YearInTitleRegex = new Regex(@"^(?<title>.+?)(?:\W|_)?(?<year>\d{4})",
RegexOptions.IgnoreCase | RegexOptions.Compiled);
private static readonly Regex TitleComponentsRegex = new Regex(@"^(?<title>.+?) \((?<title>.+?)\)$",
RegexOptions.IgnoreCase | RegexOptions.Compiled);
private static readonly Regex WordDelimiterRegex = new Regex(@"(\s|\.|,|_|-|=|\|)+", RegexOptions.Compiled);
private static readonly Regex PunctuationRegex = new Regex(@"[^\w\s]", RegexOptions.Compiled);
private static readonly Regex CommonWordRegex = new Regex(@"\b(a|an|the|and|or|of)\b\s?", RegexOptions.IgnoreCase | RegexOptions.Compiled);
@ -670,13 +673,19 @@ private static SeriesTitleInfo GetSeriesTitleInfo(string title)
{
seriesTitleInfo.TitleWithoutYear = title;
}
else
{
seriesTitleInfo.TitleWithoutYear = match.Groups["title"].Value;
seriesTitleInfo.Year = Convert.ToInt32(match.Groups["year"].Value);
}
var matchComponents = TitleComponentsRegex.Match(seriesTitleInfo.TitleWithoutYear);
if (matchComponents.Success)
{
seriesTitleInfo.AllTitles = matchComponents.Groups["title"].Captures.OfType<Capture>().Select(v => v.Value).ToArray();
}
return seriesTitleInfo;
}

View File

@ -57,6 +57,11 @@ public Series GetSeries(string title)
var series = _seriesService.FindByTitle(parsedEpisodeInfo.SeriesTitle);
if (series == null && parsedEpisodeInfo.SeriesTitleInfo.AllTitles != null)
{
series = GetSeriesByAllTitles(parsedEpisodeInfo);
}
if (series == null)
{
series = _seriesService.FindByTitle(parsedEpisodeInfo.SeriesTitleInfo.TitleWithoutYear,
@ -66,6 +71,49 @@ public Series GetSeries(string title)
return series;
}
private Series GetSeriesByAllTitles(ParsedEpisodeInfo parsedEpisodeInfo)
{
Series foundSeries = null;
int? foundTvdbId = null;
// Match each title individually, they must all resolve to the same tvdbid
foreach (var title in parsedEpisodeInfo.SeriesTitleInfo.AllTitles)
{
var series = _seriesService.FindByTitle(title);
var tvdbId = series?.TvdbId;
if (series == null)
{
tvdbId = _sceneMappingService.FindTvdbId(title, parsedEpisodeInfo.ReleaseTitle);
}
if (!tvdbId.HasValue)
{
_logger.Trace("Title {0} not matching any series.", title);
return null;
}
if (foundTvdbId.HasValue && tvdbId != foundTvdbId)
{
_logger.Trace("Title {0} both matches tvdbid {1} and {2}, no series selected.", parsedEpisodeInfo.SeriesTitle, foundTvdbId, tvdbId);
return null;
}
if (foundSeries == null)
{
foundSeries = series;
}
foundTvdbId = tvdbId;
}
if (foundSeries == null && foundTvdbId.HasValue)
{
foundSeries = _seriesService.FindByTvdbId(foundTvdbId.Value);
}
return foundSeries;
}
public RemoteEpisode Map(ParsedEpisodeInfo parsedEpisodeInfo, int tvdbId, int tvRageId, SearchCriteriaBase searchCriteria = null)
{
var remoteEpisode = new RemoteEpisode
@ -270,6 +318,11 @@ private Series GetSeries(ParsedEpisodeInfo parsedEpisodeInfo, int tvdbId, int tv
series = _seriesService.FindByTitle(parsedEpisodeInfo.SeriesTitle);
if (series == null && parsedEpisodeInfo.SeriesTitleInfo.AllTitles != null)
{
series = GetSeriesByAllTitles(parsedEpisodeInfo);
}
if (series == null && parsedEpisodeInfo.SeriesTitleInfo.Year > 0)
{
series = _seriesService.FindByTitle(parsedEpisodeInfo.SeriesTitleInfo.TitleWithoutYear, parsedEpisodeInfo.SeriesTitleInfo.Year);

View File

@ -3,6 +3,7 @@
using Sonarr.Api.V3.Episodes;
using Sonarr.Api.V3.Series;
using Sonarr.Http;
using Sonarr.Http.REST;
namespace Sonarr.Api.V3.Parse
{
@ -21,6 +22,12 @@ private ParseResource Parse()
{
var title = Request.Query.Title.Value as string;
var path = Request.Query.Path.Value as string;
if (path.IsNullOrWhiteSpace() && title.IsNullOrWhiteSpace())
{
throw new BadRequestException("title or path is missing");
}
var parsedEpisodeInfo = path.IsNotNullOrWhiteSpace() ? Parser.ParsePath(path) : Parser.ParseTitle(title);
if (parsedEpisodeInfo == null)