mirror of
https://github.com/Radarr/Radarr
synced 2024-12-26 17:59:14 +00:00
Fixed: Multiple History Issues (#2571)
This commit is contained in:
parent
15fe7a844c
commit
9e7e8cff11
8 changed files with 33 additions and 269 deletions
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using FizzWare.NBuilder;
|
||||
using FluentAssertions;
|
||||
|
@ -72,7 +72,7 @@ public void Setup()
|
|||
|
||||
private void GivenMostRecentForEpisode(int episodeId, string downloadId, QualityModel quality, DateTime date, HistoryEventType eventType)
|
||||
{
|
||||
Mocker.GetMock<IHistoryService>().Setup(s => s.MostRecentForEpisode(episodeId))
|
||||
Mocker.GetMock<IHistoryService>().Setup(s => s.MostRecentForMovie(episodeId))
|
||||
.Returns(new History.History { DownloadId = downloadId, Quality = quality, Date = date, EventType = eventType });
|
||||
}
|
||||
|
||||
|
@ -92,7 +92,7 @@ public void should_return_true_if_it_is_a_search()
|
|||
[Test]
|
||||
public void should_return_true_if_latest_history_item_is_null()
|
||||
{
|
||||
Mocker.GetMock<IHistoryService>().Setup(s => s.MostRecentForEpisode(It.IsAny<int>())).Returns((History.History)null);
|
||||
Mocker.GetMock<IHistoryService>().Setup(s => s.MostRecentForMovie(It.IsAny<int>())).Returns((History.History)null);
|
||||
_upgradeHistory.IsSatisfiedBy(_parseResultMulti, null).Accepted.Should().BeTrue();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using FizzWare.NBuilder;
|
||||
using FizzWare.NBuilder;
|
||||
using FluentAssertions;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.History;
|
||||
|
@ -32,13 +32,13 @@ public void should_get_download_history()
|
|||
{
|
||||
var historyBluray = Builder<History.History>.CreateNew()
|
||||
.With(c => c.Quality = new QualityModel(Quality.Bluray1080p))
|
||||
.With(c => c.SeriesId = 12)
|
||||
.With(c => c.MovieId = 12)
|
||||
.With(c => c.EventType = HistoryEventType.Grabbed)
|
||||
.BuildNew();
|
||||
|
||||
var historyDvd = Builder<History.History>.CreateNew()
|
||||
.With(c => c.Quality = new QualityModel(Quality.DVD))
|
||||
.With(c => c.SeriesId = 12)
|
||||
.With(c => c.MovieId = 12)
|
||||
.With(c => c.EventType = HistoryEventType.Grabbed)
|
||||
.BuildNew();
|
||||
|
||||
|
@ -51,4 +51,4 @@ public void should_get_download_history()
|
|||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System.IO;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using FizzWare.NBuilder;
|
||||
using Moq;
|
||||
|
@ -68,23 +68,23 @@ public void should_return_best_quality_with_custom_order()
|
|||
[Test]
|
||||
public void should_use_file_name_for_source_title_if_scene_name_is_null()
|
||||
{
|
||||
var series = Builder<Series>.CreateNew().Build();
|
||||
var episodes = Builder<Episode>.CreateListOfSize(1).Build().ToList();
|
||||
var episodeFile = Builder<EpisodeFile>.CreateNew()
|
||||
// Test fails becuase Radarr is using movie.title in historyService with no fallback
|
||||
|
||||
var movie = Builder<Movie>.CreateNew().Build();
|
||||
var movieFile = Builder<MovieFile>.CreateNew()
|
||||
.With(f => f.SceneName = null)
|
||||
.Build();
|
||||
|
||||
var localEpisode = new LocalEpisode
|
||||
var localMovie = new LocalMovie()
|
||||
{
|
||||
Series = series,
|
||||
Episodes = episodes,
|
||||
Path = @"C:\Test\Unsorted\Series.s01e01.mkv"
|
||||
Movie = movie,
|
||||
Path = @"C:\Test\Unsorted\Movie.2011.mkv"
|
||||
};
|
||||
|
||||
Subject.Handle(new EpisodeImportedEvent(localEpisode, episodeFile, true, "sab", "abcd", true));
|
||||
Subject.Handle(new MovieImportedEvent(localMovie, movieFile, true, "sab", "abcd", true));
|
||||
|
||||
Mocker.GetMock<IHistoryRepository>()
|
||||
.Verify(v => v.Insert(It.Is<History.History>(h => h.SourceTitle == Path.GetFileNameWithoutExtension(localEpisode.Path))));
|
||||
.Verify(v => v.Insert(It.Is<History.History>(h => h.SourceTitle == Path.GetFileNameWithoutExtension(localMovie.Path))));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -80,54 +80,7 @@ public virtual Decision IsSatisfiedBy(RemoteMovie subject, SearchCriteriaBase se
|
|||
|
||||
public virtual Decision IsSatisfiedBy(RemoteEpisode subject, SearchCriteriaBase searchCriteria)
|
||||
{
|
||||
if (searchCriteria != null)
|
||||
{
|
||||
_logger.Debug("Skipping history check during search");
|
||||
return Decision.Accept();
|
||||
}
|
||||
|
||||
var cdhEnabled = _configService.EnableCompletedDownloadHandling;
|
||||
|
||||
_logger.Debug("Performing history status check on report");
|
||||
foreach (var episode in subject.Episodes)
|
||||
{
|
||||
_logger.Debug("Checking current status of episode [{0}] in history", episode.Id);
|
||||
var mostRecent = _historyService.MostRecentForEpisode(episode.Id);
|
||||
|
||||
if (mostRecent != null && mostRecent.EventType == HistoryEventType.Grabbed)
|
||||
{
|
||||
var recent = mostRecent.Date.After(DateTime.UtcNow.AddHours(-12));
|
||||
var cutoffUnmet = _qualityUpgradableSpecification.CutoffNotMet(subject.Series.Profile, mostRecent.Quality, subject.ParsedEpisodeInfo.Quality);
|
||||
var upgradeable = _qualityUpgradableSpecification.IsUpgradable(subject.Series.Profile, mostRecent.Quality, subject.ParsedEpisodeInfo.Quality);
|
||||
|
||||
if (!recent && cdhEnabled)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!cutoffUnmet)
|
||||
{
|
||||
if (recent)
|
||||
{
|
||||
return Decision.Reject("Recent grab event in history already meets cutoff: {0}", mostRecent.Quality);
|
||||
}
|
||||
|
||||
return Decision.Reject("CDH is disabled and grab event in history already meets cutoff: {0}", mostRecent.Quality);
|
||||
}
|
||||
|
||||
if (!upgradeable)
|
||||
{
|
||||
if (recent)
|
||||
{
|
||||
return Decision.Reject("Recent grab event in history is of equal or higher quality: {0}", mostRecent.Quality);
|
||||
}
|
||||
|
||||
return Decision.Reject("CDH is disabled and grab event in history is of equal or higher quality: {0}", mostRecent.Quality);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Decision.Accept();
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Marr.Data.QGen;
|
||||
|
@ -11,12 +11,10 @@ namespace NzbDrone.Core.History
|
|||
{
|
||||
public interface IHistoryRepository : IBasicRepository<History>
|
||||
{
|
||||
List<QualityModel> GetBestQualityInHistory(int episodeId);
|
||||
History MostRecentForEpisode(int episodeId);
|
||||
List<QualityModel> GetBestQualityInHistory(int movieId);
|
||||
History MostRecentForDownloadId(string downloadId);
|
||||
List<History> FindByDownloadId(string downloadId);
|
||||
List<History> FindDownloadHistory(int idSeriesId, QualityModel quality);
|
||||
void DeleteForSeries(int seriesId);
|
||||
List<History> FindDownloadHistory(int idMovieId, QualityModel quality);
|
||||
void DeleteForMovie(int movieId);
|
||||
History MostRecentForMovie(int movieId);
|
||||
}
|
||||
|
@ -29,21 +27,13 @@ public HistoryRepository(IMainDatabase database, IEventAggregator eventAggregato
|
|||
{
|
||||
}
|
||||
|
||||
|
||||
public List<QualityModel> GetBestQualityInHistory(int episodeId)
|
||||
public List<QualityModel> GetBestQualityInHistory(int movieId)
|
||||
{
|
||||
var history = Query.Where(c => c.EpisodeId == episodeId);
|
||||
var history = Query.Where(c => c.MovieId == movieId);
|
||||
|
||||
return history.Select(h => h.Quality).ToList();
|
||||
}
|
||||
|
||||
public History MostRecentForEpisode(int episodeId)
|
||||
{
|
||||
return Query.Where(h => h.EpisodeId == episodeId)
|
||||
.OrderByDescending(h => h.Date)
|
||||
.FirstOrDefault();
|
||||
}
|
||||
|
||||
public History MostRecentForDownloadId(string downloadId)
|
||||
{
|
||||
return Query.Where(h => h.DownloadId == downloadId)
|
||||
|
@ -56,10 +46,10 @@ public List<History> FindByDownloadId(string downloadId)
|
|||
return Query.Where(h => h.DownloadId == downloadId);
|
||||
}
|
||||
|
||||
public List<History> FindDownloadHistory(int idSeriesId, QualityModel quality)
|
||||
public List<History> FindDownloadHistory(int idMovieId, QualityModel quality)
|
||||
{
|
||||
return Query.Where(h =>
|
||||
h.SeriesId == idSeriesId &&
|
||||
h.MovieId == idMovieId &&
|
||||
h.Quality == quality &&
|
||||
(h.EventType == HistoryEventType.Grabbed ||
|
||||
h.EventType == HistoryEventType.DownloadFailed ||
|
||||
|
@ -67,11 +57,6 @@ public List<History> FindDownloadHistory(int idSeriesId, QualityModel quality)
|
|||
).ToList();
|
||||
}
|
||||
|
||||
public void DeleteForSeries(int seriesId)
|
||||
{
|
||||
Delete(c => c.SeriesId == seriesId);
|
||||
}
|
||||
|
||||
public void DeleteForMovie(int movieId)
|
||||
{
|
||||
Delete(c => c.MovieId == movieId);
|
||||
|
@ -95,4 +80,4 @@ public History MostRecentForMovie(int movieId)
|
|||
.FirstOrDefault();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
@ -21,7 +21,6 @@ public interface IHistoryService
|
|||
QualityModel GetBestQualityInHistory(Profile profile, int episodeId);
|
||||
PagingSpec<History> Paged(PagingSpec<History> pagingSpec);
|
||||
History MostRecentForMovie(int movieId);
|
||||
History MostRecentForEpisode(int episodeId);
|
||||
History MostRecentForDownloadId(string downloadId);
|
||||
History Get(int historyId);
|
||||
List<History> Find(string downloadId, HistoryEventType eventType);
|
||||
|
@ -29,14 +28,11 @@ public interface IHistoryService
|
|||
}
|
||||
|
||||
public class HistoryService : IHistoryService,
|
||||
IHandle<EpisodeGrabbedEvent>,
|
||||
IHandle<MovieGrabbedEvent>,
|
||||
IHandle<MovieImportedEvent>,
|
||||
IHandle<EpisodeImportedEvent>,
|
||||
IHandle<DownloadFailedEvent>,
|
||||
IHandle<EpisodeFileDeletedEvent>,
|
||||
IHandle<MovieFileDeletedEvent>,
|
||||
IHandle<SeriesDeletedEvent>
|
||||
IHandle<MovieDeletedEvent>
|
||||
{
|
||||
private readonly IHistoryRepository _historyRepository;
|
||||
private readonly Logger _logger;
|
||||
|
@ -52,11 +48,6 @@ public PagingSpec<History> Paged(PagingSpec<History> pagingSpec)
|
|||
return _historyRepository.GetPaged(pagingSpec);
|
||||
}
|
||||
|
||||
public History MostRecentForEpisode(int episodeId)
|
||||
{
|
||||
return _historyRepository.MostRecentForEpisode(episodeId);
|
||||
}
|
||||
|
||||
public History MostRecentForMovie(int movieId)
|
||||
{
|
||||
return _historyRepository.MostRecentForMovie(movieId);
|
||||
|
@ -205,10 +196,7 @@ private string FindDownloadId(MovieImportedEvent trackedDownload)
|
|||
|
||||
var movieId = trackedDownload.MovieInfo.Movie.Id;
|
||||
|
||||
var allHistory = _historyRepository.FindDownloadHistory(movieId, trackedDownload.ImportedMovie.Quality);
|
||||
|
||||
//Find download related items for this movie
|
||||
var movieHistory = allHistory.Where(h => movieId == h.MovieId).ToList();
|
||||
var movieHistory = _historyRepository.FindDownloadHistory(movieId, trackedDownload.ImportedMovie.Quality);
|
||||
|
||||
var processedDownloadId = movieHistory
|
||||
.Where(c => c.EventType != HistoryEventType.Grabbed && c.DownloadId != null)
|
||||
|
@ -244,136 +232,6 @@ private string FindDownloadId(MovieImportedEvent trackedDownload)
|
|||
return downloadId;
|
||||
}
|
||||
|
||||
private string FindDownloadId(EpisodeImportedEvent trackedDownload)
|
||||
{
|
||||
_logger.Debug("Trying to find downloadId for {0} from history", trackedDownload.ImportedEpisode.Path);
|
||||
|
||||
var episodeIds = trackedDownload.EpisodeInfo.Episodes.Select(c => c.Id).ToList();
|
||||
|
||||
var allHistory = _historyRepository.FindDownloadHistory(trackedDownload.EpisodeInfo.Series.Id, trackedDownload.ImportedEpisode.Quality);
|
||||
|
||||
|
||||
//Find download related items for these episdoes
|
||||
var episodesHistory = allHistory.Where(h => episodeIds.Contains(h.EpisodeId)).ToList();
|
||||
|
||||
var processedDownloadId = episodesHistory
|
||||
.Where(c => c.EventType != HistoryEventType.Grabbed && c.DownloadId != null)
|
||||
.Select(c => c.DownloadId);
|
||||
|
||||
var stillDownloading = episodesHistory.Where(c => c.EventType == HistoryEventType.Grabbed && !processedDownloadId.Contains(c.DownloadId)).ToList();
|
||||
|
||||
string downloadId = null;
|
||||
|
||||
if (stillDownloading.Any())
|
||||
{
|
||||
foreach (var matchingHistory in trackedDownload.EpisodeInfo.Episodes.Select(e => stillDownloading.Where(c => c.EpisodeId == e.Id).ToList()))
|
||||
{
|
||||
if (matchingHistory.Count != 1)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var newDownloadId = matchingHistory.Single().DownloadId;
|
||||
|
||||
if (downloadId == null || downloadId == newDownloadId)
|
||||
{
|
||||
downloadId = newDownloadId;
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return downloadId;
|
||||
}
|
||||
|
||||
public void Handle(EpisodeGrabbedEvent message)
|
||||
{
|
||||
foreach (var episode in message.Episode.Episodes)
|
||||
{
|
||||
var history = new History
|
||||
{
|
||||
EventType = HistoryEventType.Grabbed,
|
||||
Date = DateTime.UtcNow,
|
||||
Quality = message.Episode.ParsedEpisodeInfo.Quality,
|
||||
SourceTitle = message.Episode.Release.Title,
|
||||
SeriesId = episode.SeriesId,
|
||||
EpisodeId = episode.Id,
|
||||
DownloadId = message.DownloadId,
|
||||
MovieId = 0
|
||||
};
|
||||
|
||||
history.Data.Add("Indexer", message.Episode.Release.Indexer);
|
||||
history.Data.Add("NzbInfoUrl", message.Episode.Release.InfoUrl);
|
||||
history.Data.Add("ReleaseGroup", message.Episode.ParsedEpisodeInfo.ReleaseGroup);
|
||||
history.Data.Add("Age", message.Episode.Release.Age.ToString());
|
||||
history.Data.Add("AgeHours", message.Episode.Release.AgeHours.ToString());
|
||||
history.Data.Add("AgeMinutes", message.Episode.Release.AgeMinutes.ToString());
|
||||
history.Data.Add("PublishedDate", message.Episode.Release.PublishDate.ToString("s") + "Z");
|
||||
history.Data.Add("DownloadClient", message.DownloadClient);
|
||||
history.Data.Add("Size", message.Episode.Release.Size.ToString());
|
||||
history.Data.Add("DownloadUrl", message.Episode.Release.DownloadUrl);
|
||||
history.Data.Add("Guid", message.Episode.Release.Guid);
|
||||
history.Data.Add("TvdbId", message.Episode.Release.TvdbId.ToString());
|
||||
history.Data.Add("TvRageId", message.Episode.Release.TvRageId.ToString());
|
||||
history.Data.Add("Protocol", ((int)message.Episode.Release.DownloadProtocol).ToString());
|
||||
|
||||
if (!message.Episode.ParsedEpisodeInfo.ReleaseHash.IsNullOrWhiteSpace())
|
||||
{
|
||||
history.Data.Add("ReleaseHash", message.Episode.ParsedEpisodeInfo.ReleaseHash);
|
||||
}
|
||||
|
||||
var torrentRelease = message.Episode.Release as TorrentInfo;
|
||||
|
||||
if (torrentRelease != null)
|
||||
{
|
||||
history.Data.Add("TorrentInfoHash", torrentRelease.InfoHash);
|
||||
}
|
||||
|
||||
_historyRepository.Insert(history);
|
||||
}
|
||||
}
|
||||
|
||||
public void Handle(EpisodeImportedEvent message)
|
||||
{
|
||||
if (!message.NewDownload)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var downloadId = message.DownloadId;
|
||||
|
||||
if (downloadId.IsNullOrWhiteSpace())
|
||||
{
|
||||
downloadId = FindDownloadId(message);
|
||||
}
|
||||
|
||||
foreach (var episode in message.EpisodeInfo.Episodes)
|
||||
{
|
||||
var history = new History
|
||||
{
|
||||
EventType = HistoryEventType.DownloadFolderImported,
|
||||
Date = DateTime.UtcNow,
|
||||
Quality = message.EpisodeInfo.Quality,
|
||||
SourceTitle = message.ImportedEpisode.SceneName ?? Path.GetFileNameWithoutExtension(message.EpisodeInfo.Path),
|
||||
SeriesId = message.ImportedEpisode.SeriesId,
|
||||
EpisodeId = episode.Id,
|
||||
DownloadId = downloadId,
|
||||
MovieId = 0,
|
||||
};
|
||||
|
||||
//Won't have a value since we publish this event before saving to DB.
|
||||
//history.Data.Add("FileId", message.ImportedEpisode.Id.ToString());
|
||||
history.Data.Add("DroppedPath", message.EpisodeInfo.Path);
|
||||
history.Data.Add("ImportedPath", Path.Combine(message.EpisodeInfo.Series.Path, message.ImportedEpisode.RelativePath));
|
||||
history.Data.Add("DownloadClient", message.DownloadClient);
|
||||
|
||||
_historyRepository.Insert(history);
|
||||
}
|
||||
}
|
||||
|
||||
public void Handle(DownloadFailedEvent message)
|
||||
{
|
||||
var history = new History
|
||||
|
@ -393,37 +251,5 @@ public void Handle(DownloadFailedEvent message)
|
|||
|
||||
_historyRepository.Insert(history);
|
||||
}
|
||||
|
||||
public void Handle(EpisodeFileDeletedEvent message)
|
||||
{
|
||||
if (message.Reason == DeleteMediaFileReason.NoLinkedEpisodes)
|
||||
{
|
||||
_logger.Debug("Removing episode file from DB as part of cleanup routine, not creating history event.");
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var episode in message.EpisodeFile.Episodes.Value)
|
||||
{
|
||||
var history = new History
|
||||
{
|
||||
EventType = HistoryEventType.EpisodeFileDeleted,
|
||||
Date = DateTime.UtcNow,
|
||||
Quality = message.EpisodeFile.Quality,
|
||||
SourceTitle = message.EpisodeFile.Path,
|
||||
SeriesId = message.EpisodeFile.SeriesId,
|
||||
EpisodeId = episode.Id,
|
||||
MovieId = 0
|
||||
};
|
||||
|
||||
history.Data.Add("Reason", message.Reason.ToString());
|
||||
|
||||
_historyRepository.Insert(history);
|
||||
}
|
||||
}
|
||||
|
||||
public void Handle(SeriesDeletedEvent message)
|
||||
{
|
||||
_historyRepository.DeleteForSeries(message.Series.Id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
{{#if_eq eventType compare="grabbed"}}Grabbed{{/if_eq}}
|
||||
{{#if_eq eventType compare="downloadFailed"}}Download Failed{{/if_eq}}
|
||||
{{#if_eq eventType compare="downloadFolderImported"}}Movie Imported{{/if_eq}}
|
||||
{{#if_eq eventType compare="episodeFileDeleted"}}Movie File Deleted{{/if_eq}}
|
||||
{{#if_eq eventType compare="movieFileDeleted"}}Movie File Deleted{{/if_eq}}
|
||||
</h3>
|
||||
|
||||
</div>
|
||||
|
|
|
@ -77,7 +77,7 @@
|
|||
</dl>
|
||||
{{/if_eq}}
|
||||
|
||||
{{#if_eq eventType compare="episodeFileDeleted"}}
|
||||
{{#if_eq eventType compare="movieFileDeleted"}}
|
||||
<dl class="dl-horizontal">
|
||||
|
||||
<dt>Path:</dt>
|
||||
|
|
Loading…
Reference in a new issue