Co-Authored-By: Mark McDowall <markus101@users.noreply.github.com>pull/4342/head
parent
72caab1b2b
commit
824d315a3b
@ -0,0 +1,184 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using FizzWare.NBuilder;
|
||||
using FluentAssertions;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.Configuration;
|
||||
using NzbDrone.Core.DecisionEngine.Specifications;
|
||||
using NzbDrone.Core.History;
|
||||
using NzbDrone.Core.Indexers;
|
||||
using NzbDrone.Core.Movies;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
|
||||
namespace NzbDrone.Core.Test.DecisionEngineTests
|
||||
{
|
||||
[TestFixture]
|
||||
public class AlreadyImportedSpecificationFixture : CoreTest<AlreadyImportedSpecification>
|
||||
{
|
||||
private const int FIRST_MOVIE_ID = 1;
|
||||
private const string TITLE = "Movie.Title.2018.720p.HDTV.x264-Radarr";
|
||||
|
||||
private Movie _movie;
|
||||
private QualityModel _hdtv720p;
|
||||
private QualityModel _hdtv1080p;
|
||||
private RemoteMovie _remoteMovie;
|
||||
private List<MovieHistory> _history;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_movie = Builder<Movie>.CreateNew()
|
||||
.With(m => m.Id = FIRST_MOVIE_ID)
|
||||
.With(m => m.MovieFileId = 1)
|
||||
.Build();
|
||||
|
||||
_hdtv720p = new QualityModel(Quality.HDTV720p, new Revision(version: 1));
|
||||
_hdtv1080p = new QualityModel(Quality.HDTV1080p, new Revision(version: 1));
|
||||
|
||||
_remoteMovie = new RemoteMovie
|
||||
{
|
||||
Movie = _movie,
|
||||
ParsedMovieInfo = new ParsedMovieInfo { Quality = _hdtv720p },
|
||||
Release = Builder<ReleaseInfo>.CreateNew()
|
||||
.Build()
|
||||
};
|
||||
|
||||
_history = new List<MovieHistory>();
|
||||
|
||||
Mocker.GetMock<IConfigService>()
|
||||
.SetupGet(s => s.EnableCompletedDownloadHandling)
|
||||
.Returns(true);
|
||||
|
||||
Mocker.GetMock<IHistoryService>()
|
||||
.Setup(s => s.GetByMovieId(It.IsAny<int>(), null))
|
||||
.Returns(_history);
|
||||
}
|
||||
|
||||
private void GivenCdhDisabled()
|
||||
{
|
||||
Mocker.GetMock<IConfigService>()
|
||||
.SetupGet(s => s.EnableCompletedDownloadHandling)
|
||||
.Returns(false);
|
||||
}
|
||||
|
||||
private void GivenHistoryItem(string downloadId, string sourceTitle, QualityModel quality, MovieHistoryEventType eventType)
|
||||
{
|
||||
_history.Add(new MovieHistory
|
||||
{
|
||||
DownloadId = downloadId,
|
||||
SourceTitle = sourceTitle,
|
||||
Quality = quality,
|
||||
Date = DateTime.UtcNow,
|
||||
EventType = eventType
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_be_accepted_if_CDH_is_disabled()
|
||||
{
|
||||
GivenCdhDisabled();
|
||||
|
||||
Subject.IsSatisfiedBy(_remoteMovie, null).Accepted.Should().BeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_be_accepted_if_movie_does_not_have_a_file()
|
||||
{
|
||||
_remoteMovie.Movie.MovieFileId = 0;
|
||||
|
||||
Subject.IsSatisfiedBy(_remoteMovie, null).Accepted.Should().BeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_be_accepted_if_movie_does_not_have_grabbed_event()
|
||||
{
|
||||
Subject.IsSatisfiedBy(_remoteMovie, null).Accepted.Should().BeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_be_accepted_if_movie_does_not_have_imported_event()
|
||||
{
|
||||
GivenHistoryItem(Guid.NewGuid().ToString().ToUpper(), TITLE, _hdtv720p, MovieHistoryEventType.Grabbed);
|
||||
|
||||
Subject.IsSatisfiedBy(_remoteMovie, null).Accepted.Should().BeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_be_accepted_if_grabbed_and_imported_quality_is_the_same()
|
||||
{
|
||||
var downloadId = Guid.NewGuid().ToString().ToUpper();
|
||||
|
||||
GivenHistoryItem(downloadId, TITLE, _hdtv720p, MovieHistoryEventType.Grabbed);
|
||||
GivenHistoryItem(downloadId, TITLE, _hdtv720p, MovieHistoryEventType.DownloadFolderImported);
|
||||
|
||||
Subject.IsSatisfiedBy(_remoteMovie, null).Accepted.Should().BeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_be_accepted_if_grabbed_download_id_and_release_torrent_hash_is_unknown()
|
||||
{
|
||||
var downloadId = Guid.NewGuid().ToString().ToUpper();
|
||||
|
||||
GivenHistoryItem(downloadId, TITLE, _hdtv720p, MovieHistoryEventType.Grabbed);
|
||||
GivenHistoryItem(downloadId, TITLE, _hdtv1080p, MovieHistoryEventType.DownloadFolderImported);
|
||||
|
||||
_remoteMovie.Release = Builder<TorrentInfo>.CreateNew()
|
||||
.With(t => t.DownloadProtocol = DownloadProtocol.Torrent)
|
||||
.With(t => t.InfoHash = null)
|
||||
.Build();
|
||||
|
||||
Subject.IsSatisfiedBy(_remoteMovie, null).Accepted.Should().BeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_be_accepted_if_grabbed_download_does_not_have_an_id()
|
||||
{
|
||||
var downloadId = Guid.NewGuid().ToString().ToUpper();
|
||||
|
||||
GivenHistoryItem(null, TITLE, _hdtv720p, MovieHistoryEventType.Grabbed);
|
||||
GivenHistoryItem(downloadId, TITLE, _hdtv1080p, MovieHistoryEventType.DownloadFolderImported);
|
||||
|
||||
_remoteMovie.Release = Builder<TorrentInfo>.CreateNew()
|
||||
.With(t => t.DownloadProtocol = DownloadProtocol.Torrent)
|
||||
.With(t => t.InfoHash = downloadId)
|
||||
.Build();
|
||||
|
||||
Subject.IsSatisfiedBy(_remoteMovie, null).Accepted.Should().BeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_be_rejected_if_grabbed_download_id_matches_release_torrent_hash()
|
||||
{
|
||||
var downloadId = Guid.NewGuid().ToString().ToUpper();
|
||||
|
||||
GivenHistoryItem(downloadId, TITLE, _hdtv720p, MovieHistoryEventType.Grabbed);
|
||||
GivenHistoryItem(downloadId, TITLE, _hdtv1080p, MovieHistoryEventType.DownloadFolderImported);
|
||||
|
||||
_remoteMovie.Release = Builder<TorrentInfo>.CreateNew()
|
||||
.With(t => t.DownloadProtocol = DownloadProtocol.Torrent)
|
||||
.With(t => t.InfoHash = downloadId)
|
||||
.Build();
|
||||
|
||||
Subject.IsSatisfiedBy(_remoteMovie, null).Accepted.Should().BeFalse();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_be_rejected_if_release_title_matches_grabbed_event_source_title()
|
||||
{
|
||||
var downloadId = Guid.NewGuid().ToString().ToUpper();
|
||||
|
||||
GivenHistoryItem(downloadId, TITLE, _hdtv720p, MovieHistoryEventType.Grabbed);
|
||||
GivenHistoryItem(downloadId, TITLE, _hdtv1080p, MovieHistoryEventType.DownloadFolderImported);
|
||||
|
||||
_remoteMovie.Release = Builder<TorrentInfo>.CreateNew()
|
||||
.With(t => t.DownloadProtocol = DownloadProtocol.Torrent)
|
||||
.With(t => t.InfoHash = downloadId)
|
||||
.Build();
|
||||
|
||||
Subject.IsSatisfiedBy(_remoteMovie, null).Accepted.Should().BeFalse();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using FluentAssertions;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.DecisionEngine;
|
||||
using NzbDrone.Core.DecisionEngine.Specifications;
|
||||
using NzbDrone.Core.Indexers;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
|
||||
namespace NzbDrone.Core.Test.DecisionEngineTests
|
||||
{
|
||||
[TestFixture]
|
||||
|
||||
public class BlockedIndexerSpecificationFixture : CoreTest<BlockedIndexerSpecification>
|
||||
{
|
||||
private RemoteMovie _remoteMovie;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_remoteMovie = new RemoteMovie
|
||||
{
|
||||
Release = new ReleaseInfo { IndexerId = 1 }
|
||||
};
|
||||
|
||||
Mocker.GetMock<IIndexerStatusService>()
|
||||
.Setup(v => v.GetBlockedProviders())
|
||||
.Returns(new List<IndexerStatus>());
|
||||
}
|
||||
|
||||
private void WithBlockedIndexer()
|
||||
{
|
||||
Mocker.GetMock<IIndexerStatusService>()
|
||||
.Setup(v => v.GetBlockedProviders())
|
||||
.Returns(new List<IndexerStatus> { new IndexerStatus { ProviderId = 1, DisabledTill = DateTime.UtcNow } });
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_true_if_no_blocked_indexer()
|
||||
{
|
||||
Subject.IsSatisfiedBy(_remoteMovie, null).Accepted.Should().BeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_false_if_blocked_indexer()
|
||||
{
|
||||
WithBlockedIndexer();
|
||||
|
||||
Subject.IsSatisfiedBy(_remoteMovie, null).Accepted.Should().BeFalse();
|
||||
Subject.Type.Should().Be(RejectionType.Temporary);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,95 @@
|
||||
using System.Collections.Generic;
|
||||
using FizzWare.NBuilder;
|
||||
using FluentAssertions;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.Download;
|
||||
using NzbDrone.Core.History;
|
||||
using NzbDrone.Core.MediaFiles.MovieImport.Specifications;
|
||||
using NzbDrone.Core.Movies;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.Profiles;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
|
||||
namespace NzbDrone.Core.Test.MediaFiles.MovieImport.Specifications
|
||||
{
|
||||
[TestFixture]
|
||||
public class DifferentQualitySpecificationFixture : CoreTest<DifferentQualitySpecification>
|
||||
{
|
||||
private LocalMovie _localMovie;
|
||||
private DownloadClientItem _downloadClientItem;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
var qualityProfile = new Profile
|
||||
{
|
||||
Cutoff = Quality.Bluray1080p.Id,
|
||||
Items = Qualities.QualityFixture.GetDefaultQualities(Quality.DVD, Quality.HDTV720p, Quality.Bluray1080p)
|
||||
};
|
||||
|
||||
var fakeMovie = Builder<Movie>.CreateNew()
|
||||
.With(c => c.Profile = qualityProfile)
|
||||
.Build();
|
||||
|
||||
_localMovie = Builder<LocalMovie>.CreateNew()
|
||||
.With(l => l.Quality = new QualityModel(Quality.Bluray1080p))
|
||||
.With(l => l.DownloadClientMovieInfo = new ParsedMovieInfo())
|
||||
.With(l => l.Movie = fakeMovie)
|
||||
.Build();
|
||||
|
||||
_downloadClientItem = Builder<DownloadClientItem>.CreateNew()
|
||||
.Build();
|
||||
}
|
||||
|
||||
private void GivenGrabbedMovieHistory(QualityModel quality)
|
||||
{
|
||||
var history = Builder<MovieHistory>.CreateListOfSize(1)
|
||||
.TheFirst(1)
|
||||
.With(h => h.Quality = quality)
|
||||
.With(h => h.EventType = MovieHistoryEventType.Grabbed)
|
||||
.BuildList();
|
||||
|
||||
Mocker.GetMock<IHistoryService>()
|
||||
.Setup(s => s.FindByDownloadId(It.IsAny<string>()))
|
||||
.Returns(history);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_be_accepted_if_no_download_client_item()
|
||||
{
|
||||
Subject.IsSatisfiedBy(_localMovie, null).Accepted.Should().BeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_be_accepted_if_no_grabbed_movie_history()
|
||||
{
|
||||
Mocker.GetMock<IHistoryService>()
|
||||
.Setup(s => s.FindByDownloadId(It.IsAny<string>()))
|
||||
.Returns(new List<MovieHistory>());
|
||||
|
||||
_localMovie.Movie = Builder<Movie>.CreateNew()
|
||||
.With(e => e.MovieFileId = 0)
|
||||
.Build();
|
||||
|
||||
Subject.IsSatisfiedBy(_localMovie, _downloadClientItem).Accepted.Should().BeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_be_accepted_if_quality_matches()
|
||||
{
|
||||
GivenGrabbedMovieHistory(_localMovie.Quality);
|
||||
|
||||
Subject.IsSatisfiedBy(_localMovie, _downloadClientItem).Accepted.Should().BeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_be_rejected_if_quality_does_not_match()
|
||||
{
|
||||
GivenGrabbedMovieHistory(new QualityModel(Quality.SDTV));
|
||||
|
||||
Subject.IsSatisfiedBy(_localMovie, _downloadClientItem).Accepted.Should().BeFalse();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,76 +0,0 @@
|
||||
using FizzWare.NBuilder;
|
||||
using FluentAssertions;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
using NzbDrone.Core.MediaFiles.MovieImport.Specifications;
|
||||
using NzbDrone.Core.Movies;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
|
||||
namespace NzbDrone.Core.Test.MediaFiles.MovieImport.Specifications
|
||||
{
|
||||
[TestFixture]
|
||||
public class SameFileSpecificationFixture : CoreTest<SameFileSpecification>
|
||||
{
|
||||
private LocalMovie _localMovie;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_localMovie = Builder<LocalMovie>.CreateNew()
|
||||
.With(l => l.Size = 150.Megabytes())
|
||||
.Build();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_be_accepted_if_no_existing_file()
|
||||
{
|
||||
_localMovie.Movie = Builder<Movie>.CreateNew()
|
||||
.With(e => e.MovieFileId = 0)
|
||||
.Build();
|
||||
|
||||
Subject.IsSatisfiedBy(_localMovie, null).Accepted.Should().BeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_be_accepted_if_file_size_is_different()
|
||||
{
|
||||
_localMovie.Movie = Builder<Movie>.CreateNew()
|
||||
.With(e => e.MovieFileId = 1)
|
||||
.With(e => e.MovieFile =
|
||||
new MovieFile
|
||||
{
|
||||
Size = _localMovie.Size + 100.Megabytes()
|
||||
})
|
||||
.Build();
|
||||
|
||||
Subject.IsSatisfiedBy(_localMovie, null).Accepted.Should().BeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_be_reject_if_file_size_is_the_same()
|
||||
{
|
||||
_localMovie.Movie = Builder<Movie>.CreateNew()
|
||||
.With(e => e.MovieFileId = 1)
|
||||
.With(e => e.MovieFile =
|
||||
new MovieFile
|
||||
{
|
||||
Size = _localMovie.Size
|
||||
})
|
||||
.Build();
|
||||
|
||||
Subject.IsSatisfiedBy(_localMovie, null).Accepted.Should().BeFalse();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_be_accepted_if_file_cannot_be_fetched()
|
||||
{
|
||||
_localMovie.Movie = Builder<Movie>.CreateNew()
|
||||
.With(e => e.MovieFileId = 1)
|
||||
.With(e => e.MovieFile = null)
|
||||
.Build();
|
||||
|
||||
Subject.IsSatisfiedBy(_localMovie, null).Accepted.Should().BeTrue();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,94 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using FluentMigrator;
|
||||
using NzbDrone.Common.Serializer;
|
||||
using NzbDrone.Core.Datastore.Migration.Framework;
|
||||
|
||||
namespace NzbDrone.Core.Datastore.Migration
|
||||
{
|
||||
[Migration(172)]
|
||||
public class add_download_history : NzbDroneMigrationBase
|
||||
{
|
||||
protected override void MainDbUpgrade()
|
||||
{
|
||||
Create.TableForModel("DownloadHistory")
|
||||
.WithColumn("EventType").AsInt32().NotNullable()
|
||||
.WithColumn("MovieId").AsInt32().NotNullable()
|
||||
.WithColumn("DownloadId").AsString().NotNullable()
|
||||
.WithColumn("SourceTitle").AsString().NotNullable()
|
||||
.WithColumn("Date").AsDateTime().NotNullable()
|
||||
.WithColumn("Protocol").AsInt32().Nullable()
|
||||
.WithColumn("IndexerId").AsInt32().Nullable()
|
||||
.WithColumn("DownloadClientId").AsInt32().Nullable()
|
||||
.WithColumn("Release").AsString().Nullable()
|
||||
.WithColumn("Data").AsString().Nullable();
|
||||
|
||||
Create.Index().OnTable("DownloadHistory").OnColumn("EventType");
|
||||
Create.Index().OnTable("DownloadHistory").OnColumn("MovieId");
|
||||
Create.Index().OnTable("DownloadHistory").OnColumn("DownloadId");
|
||||
|
||||
Execute.WithConnection(InitialImportedDownloadHistory);
|
||||
}
|
||||
|
||||
private static readonly Dictionary<int, int> EventTypeMap = new Dictionary<int, int>()
|
||||
{
|
||||
{ 1, 1 }, // MovieHistoryType.Grabbed -> DownloadHistoryType.Grabbed
|
||||
{ 3, 2 }, // MovieHistoryType.DownloadFolderImported -> DownloadHistoryType.DownloadImported
|
||||
{ 4, 3 }, // MovieHistoryType.DownloadFailed -> DownloadHistoryType.DownloadFailed
|
||||
{ 9, 4 } // MovieHistoryType.DownloadIgnored -> DownloadHistoryType.DownloadIgnored
|
||||
};
|
||||
|
||||
private void InitialImportedDownloadHistory(IDbConnection conn, IDbTransaction tran)
|
||||
{
|
||||
using (var cmd = conn.CreateCommand())
|
||||
{
|
||||
cmd.Transaction = tran;
|
||||
cmd.CommandText = "SELECT MovieId, DownloadId, EventType, SourceTitle, Date, Data FROM History WHERE DownloadId IS NOT NULL AND EventType IN (1, 3, 4, 9) GROUP BY EventType, DownloadId";
|
||||
|
||||
using (var reader = cmd.ExecuteReader())
|
||||
{
|
||||
while (reader.Read())
|
||||
{
|
||||
var movieId = reader.GetInt32(0);
|
||||
var downloadId = reader.GetString(1);
|
||||
var eventType = reader.GetInt32(2);
|
||||
var sourceTitle = reader.GetString(3);
|
||||
var date = reader.GetDateTime(4);
|
||||
var rawData = reader.GetString(5);
|
||||
var data = Json.Deserialize<Dictionary<string, string>>(rawData);
|
||||
|
||||
var downloadHistoryEventType = EventTypeMap[eventType];
|
||||
var protocol = data.ContainsKey("protocol") ? Convert.ToInt32(data["protocol"]) : (int?)null;
|
||||
var downloadHistoryData = new Dictionary<string, string>();
|
||||
|
||||
if (data.ContainsKey("indexer"))
|
||||
{
|
||||
downloadHistoryData.Add("indexer", data["indexer"]);
|
||||
}
|
||||
|
||||
if (data.ContainsKey("downloadClient"))
|
||||
{
|
||||
downloadHistoryData.Add("downloadClient", data["downloadClient"]);
|
||||
}
|
||||
|
||||
using (var updateCmd = conn.CreateCommand())
|
||||
{
|
||||
updateCmd.Transaction = tran;
|
||||
updateCmd.CommandText = @"INSERT INTO DownloadHistory (EventType, MovieId, DownloadId, SourceTitle, Date, Protocol, Data) VALUES (?, ?, ?, ?, ?, ?, ?)";
|
||||
updateCmd.AddParameter(downloadHistoryEventType);
|
||||
updateCmd.AddParameter(movieId);
|
||||
updateCmd.AddParameter(downloadId);
|
||||
updateCmd.AddParameter(sourceTitle);
|
||||
updateCmd.AddParameter(date);
|
||||
updateCmd.AddParameter(protocol);
|
||||
updateCmd.AddParameter(downloadHistoryData.ToJson());
|
||||
|
||||
updateCmd.ExecuteNonQuery();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using NzbDrone.Core.Datastore;
|
||||
using NzbDrone.Core.Indexers;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
|
||||
namespace NzbDrone.Core.Download.History
|
||||
{
|
||||
public class DownloadHistory : ModelBase
|
||||
{
|
||||
public DownloadHistoryEventType EventType { get; set; }
|
||||
public int MovieId { get; set; }
|
||||
public string DownloadId { get; set; }
|
||||
public string SourceTitle { get; set; }
|
||||
public DateTime Date { get; set; }
|
||||
public DownloadProtocol Protocol { get; set; }
|
||||
public int IndexerId { get; set; }
|
||||
public int DownloadClientId { get; set; }
|
||||
public ReleaseInfo Release { get; set; }
|
||||
public Dictionary<string, string> Data { get; set; }
|
||||
public DownloadHistory()
|
||||
{
|
||||
Data = new Dictionary<string, string>();
|
||||
}
|
||||
}
|
||||
|
||||
public enum DownloadHistoryEventType
|
||||
{
|
||||
DownloadGrabbed = 1,
|
||||
DownloadImported = 2,
|
||||
DownloadFailed = 3,
|
||||
DownloadIgnored = 4,
|
||||
FileImported = 5
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NzbDrone.Core.Datastore;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
|
||||
namespace NzbDrone.Core.Download.History
|
||||
{
|
||||
public interface IDownloadHistoryRepository : IBasicRepository<DownloadHistory>
|
||||
{
|
||||
List<DownloadHistory> FindByDownloadId(string downloadId);
|
||||
void DeleteByMovieId(int movieId);
|
||||
}
|
||||
|
||||
public class DownloadHistoryRepository : BasicRepository<DownloadHistory>, IDownloadHistoryRepository
|
||||
{
|
||||
public DownloadHistoryRepository(IMainDatabase database, IEventAggregator eventAggregator)
|
||||
: base(database, eventAggregator)
|
||||
{
|
||||
}
|
||||
|
||||
public List<DownloadHistory> FindByDownloadId(string downloadId)
|
||||
{
|
||||
return Query(x => x.DownloadId == downloadId).OrderByDescending(h => h.Date).ToList();
|
||||
}
|
||||
|
||||
public void DeleteByMovieId(int movieId)
|
||||
{
|
||||
Delete(r => r.MovieId == movieId);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,210 @@
|
||||
using System;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.History;
|
||||
using NzbDrone.Core.MediaFiles.Events;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
using NzbDrone.Core.Movies.Events;
|
||||
|
||||
namespace NzbDrone.Core.Download.History
|
||||
{
|
||||
public interface IDownloadHistoryService
|
||||
{
|
||||
bool DownloadAlreadyImported(string downloadId);
|
||||
DownloadHistory GetLatestDownloadHistoryItem(string downloadId);
|
||||
}
|
||||
|
||||
public class DownloadHistoryService : IDownloadHistoryService,
|
||||
IHandle<MovieGrabbedEvent>,
|
||||
IHandle<MovieImportedEvent>,
|
||||
IHandle<DownloadCompletedEvent>,
|
||||
IHandle<DownloadFailedEvent>,
|
||||
IHandle<DownloadIgnoredEvent>,
|
||||
IHandle<MovieDeletedEvent>
|
||||
{
|
||||
private readonly IDownloadHistoryRepository _repository;
|
||||
private readonly IHistoryService _historyService;
|
||||
|
||||
public DownloadHistoryService(IDownloadHistoryRepository repository, IHistoryService historyService)
|
||||
{
|
||||
_repository = repository;
|
||||
_historyService = historyService;
|
||||
}
|
||||
|
||||
public bool DownloadAlreadyImported(string downloadId)
|
||||
{
|
||||
var events = _repository.FindByDownloadId(downloadId);
|
||||
|
||||
// Events are ordered by date descending, if a grabbed event comes before an imported event then it was never imported
|
||||
// or grabbed again after importing and should be reprocessed.
|
||||
foreach (var e in events)
|
||||
{
|
||||
if (e.EventType == DownloadHistoryEventType.DownloadGrabbed)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (e.EventType == DownloadHistoryEventType.DownloadImported)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public DownloadHistory GetLatestDownloadHistoryItem(string downloadId)
|
||||
{
|
||||
var events = _repository.FindByDownloadId(downloadId);
|
||||
|
||||
// Events are ordered by date descending. We'll return the most recent expected event.
|
||||
foreach (var e in events)
|
||||
{
|
||||
if (e.EventType == DownloadHistoryEventType.DownloadGrabbed)
|
||||
{
|
||||
return e;
|
||||
}
|
||||
|
||||
if (e.EventType == DownloadHistoryEventType.DownloadImported)
|
||||
{
|
||||
return e;
|
||||
}
|
||||
|
||||
if (e.EventType == DownloadHistoryEventType.DownloadFailed)
|
||||
{
|
||||
return e;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void Handle(MovieGrabbedEvent message)
|
||||
{
|
||||
var history = new DownloadHistory
|
||||
{
|
||||
EventType = DownloadHistoryEventType.DownloadGrabbed,
|
||||
MovieId = message.Movie.Movie.Id,
|
||||
DownloadId = message.DownloadId,
|
||||
SourceTitle = message.Movie.Release.Title,
|
||||
Date = DateTime.UtcNow,
|
||||
Protocol = message.Movie.Release.DownloadProtocol,
|
||||
IndexerId = message.Movie.Release.IndexerId,
|
||||
DownloadClientId = message.DownloadClientId,
|
||||
Release = message.Movie.Release
|
||||
};
|
||||
|
||||
history.Data.Add("Indexer", message.Movie.Release.Indexer);
|
||||
history.Data.Add("DownloadClient", message.DownloadClient);
|
||||
history.Data.Add("DownloadClientName", message.DownloadClientName);
|
||||
|
||||
history.Data.Add("CustomFormatScore", message.Movie.CustomFormatScore.ToString());
|
||||
_repository.Insert(history);
|
||||
}
|
||||
|
||||
public void Handle(MovieImportedEvent message)
|
||||
{
|
||||
if (!message.NewDownload)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var downloadId = message.DownloadId;
|
||||
|
||||
// Try to find the downloadId if the user used manual import (from wanted: missing) or the
|
||||
// API to import and downloadId wasn't provided.
|
||||
if (downloadId.IsNullOrWhiteSpace())
|
||||
{
|
||||
downloadId = _historyService.FindDownloadId(message);
|
||||
}
|
||||
|
||||
if (downloadId.IsNullOrWhiteSpace())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var history = new DownloadHistory
|
||||
{
|
||||
EventType = DownloadHistoryEventType.FileImported,
|
||||
MovieId = message.MovieInfo.Movie.Id,
|
||||
DownloadId = downloadId,
|
||||
SourceTitle = message.MovieInfo.Path,
|
||||
Date = DateTime.UtcNow,
|
||||
Protocol = message.DownloadClientInfo.Protocol,
|
||||
DownloadClientId = message.DownloadClientInfo.Id
|
||||
};
|
||||
|
||||
history.Data.Add("DownloadClient", message.DownloadClientInfo.Type);
|
||||
history.Data.Add("DownloadClientName", message.DownloadClientInfo.Name);
|
||||
|
||||
_repository.Insert(history);
|
||||
}
|
||||
|
||||
public void Handle(DownloadCompletedEvent message)
|
||||
{
|
||||
var history = new DownloadHistory
|
||||
{
|
||||
EventType = DownloadHistoryEventType.DownloadImported,
|
||||
MovieId = message.TrackedDownload.RemoteMovie.Movie.Id,
|
||||
DownloadId = message.TrackedDownload.DownloadItem.DownloadId,
|
||||
SourceTitle = message.TrackedDownload.DownloadItem.OutputPath.ToString(),
|
||||
Date = DateTime.UtcNow,
|
||||
Protocol = message.TrackedDownload.Protocol,
|
||||
DownloadClientId = message.TrackedDownload.DownloadClient
|
||||
};
|
||||
|
||||
history.Data.Add("DownloadClient", message.TrackedDownload.DownloadItem.DownloadClientInfo.Type);
|
||||
history.Data.Add("DownloadClientName", message.TrackedDownload.DownloadItem.DownloadClientInfo.Name);
|
||||
|
||||
_repository.Insert(history);
|
||||
}
|
||||
|
||||
public void Handle(DownloadFailedEvent message)
|
||||
{
|
||||
// Don't track failed download for an unknown download
|
||||
if (message.TrackedDownload == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var history = new DownloadHistory
|
||||
{
|
||||
EventType = DownloadHistoryEventType.DownloadFailed,
|
||||
MovieId = message.MovieId,
|
||||
DownloadId = message.DownloadId,
|
||||
SourceTitle = message.SourceTitle,
|
||||
Date = DateTime.UtcNow,
|
||||
Protocol = message.TrackedDownload.Protocol,
|
||||
DownloadClientId = message.TrackedDownload.DownloadClient
|
||||
};
|
||||
|
||||
history.Data.Add("DownloadClient", message.TrackedDownload.DownloadItem.DownloadClientInfo.Type);
|
||||
history.Data.Add("DownloadClientName", message.TrackedDownload.DownloadItem.DownloadClientInfo.Name);
|
||||
|
||||
_repository.Insert(history);
|
||||
}
|
||||
|
||||
public void Handle(DownloadIgnoredEvent message)
|
||||
{
|
||||
var history = new DownloadHistory
|
||||
{
|
||||
EventType = DownloadHistoryEventType.DownloadIgnored,
|
||||
MovieId = message.MovieId,
|
||||
DownloadId = message.DownloadId,
|
||||
SourceTitle = message.SourceTitle,
|
||||
Date = DateTime.UtcNow,
|
||||
Protocol = message.DownloadClientInfo.Protocol,
|
||||
DownloadClientId = message.DownloadClientInfo.Id
|
||||
};
|
||||
|
||||
history.Data.Add("DownloadClient", message.DownloadClientInfo.Type);
|
||||
history.Data.Add("DownloadClientName", message.DownloadClientInfo.Name);
|
||||
|
||||
_repository.Insert(history);
|
||||
}
|
||||
|
||||
public void Handle(MovieDeletedEvent message)
|
||||
{
|
||||
_repository.DeleteByMovieId(message.Movie.Id);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
using System.Linq;
|
||||
using NLog;
|
||||
using NzbDrone.Core.DecisionEngine;
|
||||
using NzbDrone.Core.Download;
|
||||
using NzbDrone.Core.History;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.Qualities;
|
||||
|
||||
namespace NzbDrone.Core.MediaFiles.MovieImport.Specifications
|
||||
{
|
||||
public class DifferentQualitySpecification : IImportDecisionEngineSpecification
|
||||
{
|
||||
private readonly IHistoryService _historyService;
|
||||
private readonly Logger _logger;
|
||||
|
||||
public DifferentQualitySpecification(IHistoryService historyService, Logger logger)
|
||||
{
|
||||
_historyService = historyService;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public Decision IsSatisfiedBy(LocalMovie localMovie, DownloadClientItem downloadClientItem)
|
||||
{
|
||||
if (downloadClientItem == null)
|
||||
{
|
||||
_logger.Debug("No download client item, skipping");
|
||||
return Decision.Accept();
|
||||
}
|
||||
|
||||
var grabbedMovieHistory = _historyService.FindByDownloadId(downloadClientItem.DownloadId)
|
||||
.OrderByDescending(h => h.Date)
|
||||
.FirstOrDefault(h => h.EventType == MovieHistoryEventType.Grabbed);
|
||||
|
||||
if (grabbedMovieHistory == null)
|
||||
{
|
||||
_logger.Debug("No grabbed history for this download item, skipping");
|
||||
return Decision.Accept();
|
||||
}
|
||||
|
||||
var qualityComparer = new QualityModelComparer(localMovie.Movie.Profile);
|
||||
var qualityCompare = qualityComparer.Compare(localMovie.Quality, grabbedMovieHistory.Quality);
|
||||
|
||||
if (qualityCompare != 0)
|
||||
{
|
||||
_logger.Debug("Quality of file ({0}) does not match quality of grabbed history ({1})", localMovie.Quality, grabbedMovieHistory.Quality);
|
||||
return Decision.Reject("Not an upgrade for existing movie file(s)");
|
||||
}
|
||||
|
||||
return Decision.Accept();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,44 +0,0 @@
|
||||
using NLog;
|
||||
using NzbDrone.Core.DecisionEngine;
|
||||
using NzbDrone.Core.Download;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
|
||||
namespace NzbDrone.Core.MediaFiles.MovieImport.Specifications
|
||||
{
|
||||
public class SameFileSpecification : IImportDecisionEngineSpecification
|
||||
{
|
||||
private readonly Logger _logger;
|
||||
|
||||
public SameFileSpecification(Logger logger)
|
||||
{
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public Decision IsSatisfiedBy(LocalMovie localMovie, DownloadClientItem downloadClientItem)
|
||||
{
|
||||
var movieFile = localMovie.Movie.MovieFile;
|
||||
|
||||
if (localMovie.Movie.MovieFileId == 0)
|
||||
{
|
||||
_logger.Debug("No existing movie file, skipping");
|
||||
return Decision.Accept();
|
||||
}
|
||||
|
||||
if (movieFile == null)
|
||||
{
|
||||
var movie = localMovie.Movie;
|
||||
_logger.Trace("Unable to get movie file details from the DB. MovieId: {0} MovieFileId: {1}", movie.Id, movie.MovieFileId);
|
||||
|
||||
return Decision.Accept();
|
||||
}
|
||||
|
||||
if (movieFile.Size == localMovie.Size)
|
||||
{
|
||||
_logger.Debug("'{0}' Has the same filesize as existing file", localMovie.Path);
|
||||
return Decision.Reject("Has the same filesize as existing file");
|
||||
}
|
||||
|
||||
return Decision.Accept();
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in new issue