Fixed: Automatic import of releases when file is not matched to series

Closes #4935
This commit is contained in:
Mark McDowall 2022-03-19 12:57:00 -07:00
parent bb02fc4668
commit e280897bc7
10 changed files with 88 additions and 14 deletions

View File

@ -0,0 +1,14 @@
using FluentMigrator;
using NzbDrone.Core.Datastore.Migration.Framework;
namespace NzbDrone.Core.Datastore.Migration
{
[Migration(168)]
public class add_additional_info_to_pending_releases : NzbDroneMigrationBase
{
protected override void MainDbUpgrade()
{
Alter.Table("PendingReleases").AddColumn("AdditionalInfo").AsString().Nullable();
}
}
}

View File

@ -177,6 +177,7 @@ namespace NzbDrone.Core.Datastore
MapRepository.Instance.RegisterTypeConverter(typeof(List<LanguageProfileItem>), new EmbeddedDocumentConverter(new LanguageIntConverter()));
MapRepository.Instance.RegisterTypeConverter(typeof(ParsedEpisodeInfo), new EmbeddedDocumentConverter());
MapRepository.Instance.RegisterTypeConverter(typeof(ReleaseInfo), new EmbeddedDocumentConverter());
MapRepository.Instance.RegisterTypeConverter(typeof(PendingReleaseAdditionalInfo), new EmbeddedDocumentConverter());
MapRepository.Instance.RegisterTypeConverter(typeof(HashSet<int>), new EmbeddedDocumentConverter());
MapRepository.Instance.RegisterTypeConverter(typeof(OsPath), new OsPathConverter());
MapRepository.Instance.RegisterTypeConverter(typeof(Guid), new GuidConverter());

View File

@ -13,6 +13,7 @@ using NzbDrone.Core.MediaFiles;
using NzbDrone.Core.MediaFiles.EpisodeImport;
using NzbDrone.Core.Messaging.Events;
using NzbDrone.Core.Parser;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Tv;
namespace NzbDrone.Core.Download
@ -97,9 +98,13 @@ namespace NzbDrone.Core.Download
return;
}
trackedDownload.Warn("Found matching series via grab history, but release title doesn't match series title. Automatic import is not possible.");
Enum.TryParse(historyItem.Data.GetValueOrDefault(EpisodeHistory.SERIES_MATCH_TYPE, SeriesMatchType.Unknown.ToString()), out SeriesMatchType seriesMatchType);
return;
if (seriesMatchType == SeriesMatchType.Id)
{
trackedDownload.Warn("Found matching series via grab history, but release was matched to series by ID. Automatic import is not possible.");
return;
}
}
trackedDownload.State = TrackedDownloadState.ImportPending;

View File

@ -12,8 +12,14 @@ namespace NzbDrone.Core.Download.Pending
public ParsedEpisodeInfo ParsedEpisodeInfo { get; set; }
public ReleaseInfo Release { get; set; }
public PendingReleaseReason Reason { get; set; }
public PendingReleaseAdditionalInfo AdditionalInfo { get; set; }
//Not persisted
public RemoteEpisode RemoteEpisode { get; set; }
}
public class PendingReleaseAdditionalInfo
{
public SeriesMatchType SeriesMatchType { get; set; }
}
}

View File

@ -291,16 +291,15 @@ namespace NzbDrone.Core.Download.Pending
// Just in case the series was removed, but wasn't cleaned up yet (housekeeper will clean it up)
if (series == null) return null;
release.RemoteEpisode = new RemoteEpisode
{
Series = series,
SeriesMatchType = release.AdditionalInfo?.SeriesMatchType ?? SeriesMatchType.Unknown,
ParsedEpisodeInfo = release.ParsedEpisodeInfo,
Release = release.Release
};
RemoteEpisode knownRemoteEpisode;
if (knownRemoteEpisodes != null && knownRemoteEpisodes.TryGetValue(release.Release.Title, out knownRemoteEpisode))
if (knownRemoteEpisodes != null && knownRemoteEpisodes.TryGetValue(release.Release.Title, out var knownRemoteEpisode))
{
release.RemoteEpisode.MappedSeasonNumber = knownRemoteEpisode.MappedSeasonNumber;
release.RemoteEpisode.Episodes = knownRemoteEpisode.Episodes;
@ -333,7 +332,11 @@ namespace NzbDrone.Core.Download.Pending
Release = decision.RemoteEpisode.Release,
Title = decision.RemoteEpisode.Release.Title,
Added = DateTime.UtcNow,
Reason = reason
Reason = reason,
AdditionalInfo = new PendingReleaseAdditionalInfo
{
SeriesMatchType = decision.RemoteEpisode.SeriesMatchType
}
});
_eventAggregator.PublishEvent(new PendingReleasesUpdatedEvent());

View File

@ -10,6 +10,7 @@ namespace NzbDrone.Core.History
public class EpisodeHistory : ModelBase
{
public const string DOWNLOAD_CLIENT = "downloadClient";
public const string SERIES_MATCH_TYPE = "seriesMatchType";
public EpisodeHistory()
{

View File

@ -169,6 +169,7 @@ namespace NzbDrone.Core.History
history.Data.Add("TvRageId", message.Episode.Release.TvRageId.ToString());
history.Data.Add("Protocol", ((int)message.Episode.Release.DownloadProtocol).ToString());
history.Data.Add("PreferredWordScore", message.Episode.PreferredWordScore.ToString());
history.Data.Add("SeriesMatchType", message.Episode.SeriesMatchType.ToString());
if (!message.Episode.ParsedEpisodeInfo.ReleaseHash.IsNullOrWhiteSpace())
{

View File

@ -0,0 +1,24 @@
using NzbDrone.Core.Tv;
namespace NzbDrone.Core.Parser.Model
{
public class FindSeriesResult
{
public Series Series { get; set; }
public SeriesMatchType MatchType { get; set; }
public FindSeriesResult(Series series, SeriesMatchType matchType)
{
Series = series;
MatchType = matchType;
}
}
public enum SeriesMatchType
{
Unknown = 0,
Title = 1,
Alias = 2,
Id = 3
}
}

View File

@ -20,6 +20,7 @@ namespace NzbDrone.Core.Parser.Model
public bool DownloadAllowed { get; set; }
public TorrentSeedConfiguration SeedConfiguration { get; set; }
public int PreferredWordScore { get; set; }
public SeriesMatchType SeriesMatchType { get; set; }
public RemoteEpisode()
{

View File

@ -164,7 +164,13 @@ namespace NzbDrone.Core.Parser
if (series == null)
{
series = GetSeries(parsedEpisodeInfo, tvdbId, tvRageId, sceneMapping, searchCriteria);
var seriesMatch = FindSeries(parsedEpisodeInfo, tvdbId, tvRageId, sceneMapping, searchCriteria);
if (seriesMatch != null)
{
series = seriesMatch.Series;
remoteEpisode.SeriesMatchType = seriesMatch.MatchType;
}
}
if (series != null)
@ -328,7 +334,7 @@ namespace NzbDrone.Core.Parser
return null;
}
private Series GetSeries(ParsedEpisodeInfo parsedEpisodeInfo, int tvdbId, int tvRageId, SceneMapping sceneMapping, SearchCriteriaBase searchCriteria)
private FindSeriesResult FindSeries(ParsedEpisodeInfo parsedEpisodeInfo, int tvdbId, int tvRageId, SceneMapping sceneMapping, SearchCriteriaBase searchCriteria)
{
Series series = null;
@ -336,7 +342,7 @@ namespace NzbDrone.Core.Parser
{
if (searchCriteria != null && searchCriteria.Series.TvdbId == sceneMapping.TvdbId)
{
return searchCriteria.Series;
return new FindSeriesResult(searchCriteria.Series, SeriesMatchType.Alias);
}
series = _seriesService.FindByTvdbId(sceneMapping.TvdbId);
@ -347,14 +353,14 @@ namespace NzbDrone.Core.Parser
return null;
}
return series;
return new FindSeriesResult(series, SeriesMatchType.Alias);
}
if (searchCriteria != null)
{
if (searchCriteria.Series.CleanTitle == parsedEpisodeInfo.SeriesTitle.CleanSeriesTitle())
{
return searchCriteria.Series;
return new FindSeriesResult(searchCriteria.Series, SeriesMatchType.Title);
}
if (tvdbId > 0 && tvdbId == searchCriteria.Series.TvdbId)
@ -366,7 +372,7 @@ namespace NzbDrone.Core.Parser
.WriteSentryWarn("TvdbIdMatch", tvdbId.ToString(), parsedEpisodeInfo.SeriesTitle)
.Write();
return searchCriteria.Series;
return new FindSeriesResult(searchCriteria.Series, SeriesMatchType.Id);
}
if (tvRageId > 0 && tvRageId == searchCriteria.Series.TvRageId)
@ -378,20 +384,28 @@ namespace NzbDrone.Core.Parser
.WriteSentryWarn("TvRageIdMatch", tvRageId.ToString(), parsedEpisodeInfo.SeriesTitle)
.Write();
return searchCriteria.Series;
return new FindSeriesResult(searchCriteria.Series, SeriesMatchType.Id);
}
}
var matchType = SeriesMatchType.Unknown;
series = _seriesService.FindByTitle(parsedEpisodeInfo.SeriesTitle);
if (series != null)
{
matchType = SeriesMatchType.Title;
}
if (series == null && parsedEpisodeInfo.SeriesTitleInfo.AllTitles != null)
{
series = GetSeriesByAllTitles(parsedEpisodeInfo);
matchType = SeriesMatchType.Title;
}
if (series == null && parsedEpisodeInfo.SeriesTitleInfo.Year > 0)
{
series = _seriesService.FindByTitle(parsedEpisodeInfo.SeriesTitleInfo.TitleWithoutYear, parsedEpisodeInfo.SeriesTitleInfo.Year);
matchType = SeriesMatchType.Title;
}
if (series == null && tvdbId > 0)
@ -406,6 +420,8 @@ namespace NzbDrone.Core.Parser
.Property("ParsedEpisodeInfo", parsedEpisodeInfo)
.WriteSentryWarn("TvdbIdMatch", tvdbId.ToString(), parsedEpisodeInfo.SeriesTitle)
.Write();
matchType = SeriesMatchType.Id;
}
}
@ -421,6 +437,8 @@ namespace NzbDrone.Core.Parser
.Property("ParsedEpisodeInfo", parsedEpisodeInfo)
.WriteSentryWarn("TvRageIdMatch", tvRageId.ToString(), parsedEpisodeInfo.SeriesTitle)
.Write();
matchType = SeriesMatchType.Id;
}
}
@ -430,7 +448,7 @@ namespace NzbDrone.Core.Parser
return null;
}
return series;
return new FindSeriesResult(series, matchType);
}
private Episode GetDailyEpisode(Series series, string airDate, int? part, SearchCriteriaBase searchCriteria)