From 1a4fb6e7bb2c15be2e94967d8d544829c126aeb9 Mon Sep 17 00:00:00 2001 From: Devin Buhl Date: Thu, 9 Mar 2017 18:45:08 -0500 Subject: [PATCH] Update blacklist to work with movies (#1089) * Update BlacklistService * Update HistoryService, HistoryRepo and History * Update UI in Blacklists to movies * set the movie model so the movie title prints in blacklist * Would be working if I implemented the Event Handler for MovieFileDeleted --- src/NzbDrone.Api/History/HistoryModule.cs | 18 -- .../Blacklisting/BlacklistServiceFixture.cs | 9 +- .../Blacklisting/BlacklistService.cs | 2 +- src/NzbDrone.Core/History/History.cs | 6 +- .../History/HistoryRepository.cs | 6 + src/NzbDrone.Core/History/HistoryService.cs | 268 +++++++++++------- .../Activity/Blacklist/BlacklistCollection.js | 2 +- src/UI/Activity/Blacklist/BlacklistLayout.js | 8 +- src/UI/Activity/Blacklist/BlacklistModel.js | 28 +- src/UI/Activity/History/HistoryCollection.js | 2 +- src/UI/Cells/EventTypeCell.js | 4 + src/UI/Movies/MovieModel.js | 1 + 12 files changed, 212 insertions(+), 142 deletions(-) diff --git a/src/NzbDrone.Api/History/HistoryModule.cs b/src/NzbDrone.Api/History/HistoryModule.cs index a17b9963c..1cf40b95c 100644 --- a/src/NzbDrone.Api/History/HistoryModule.cs +++ b/src/NzbDrone.Api/History/HistoryModule.cs @@ -1,8 +1,6 @@ using System; using Nancy; -using NzbDrone.Api.Episodes; using NzbDrone.Api.Extensions; -using NzbDrone.Api.Series; using NzbDrone.Api.Movie; using NzbDrone.Core.Datastore; using NzbDrone.Core.DecisionEngine; @@ -32,16 +30,8 @@ public HistoryModule(IHistoryService historyService, protected HistoryResource MapToResource(Core.History.History model) { var resource = model.ToResource(); - - resource.Series = model.Series.ToResource(); - resource.Episode = model.Episode.ToResource(); resource.Movie = model.Movie.ToResource(); - if (model.Series != null) - { - resource.QualityCutoffNotMet = _qualityUpgradableSpecification.CutoffNotMet(model.Series.Profile.Value, model.Quality); - } - if (model.Movie != null) { resource.QualityCutoffNotMet = _qualityUpgradableSpecification.CutoffNotMet(model.Movie.Profile.Value, model.Quality); @@ -52,8 +42,6 @@ protected HistoryResource MapToResource(Core.History.History model) private PagingResource GetHistory(PagingResource pagingResource) { - var episodeId = Request.Query.EpisodeId; - var movieId = Request.Query.MovieId; var pagingSpec = pagingResource.MapToPagingSpec("date", SortDirection.Descending); @@ -64,12 +52,6 @@ private PagingResource GetHistory(PagingResource v.EventType == filterValue; } - if (episodeId.HasValue) - { - int i = (int)episodeId; - pagingSpec.FilterExpression = h => h.EpisodeId == i; - } - if (movieId.HasValue) { int i = (int)movieId; diff --git a/src/NzbDrone.Core.Test/Blacklisting/BlacklistServiceFixture.cs b/src/NzbDrone.Core.Test/Blacklisting/BlacklistServiceFixture.cs index 8766de661..4609d03be 100644 --- a/src/NzbDrone.Core.Test/Blacklisting/BlacklistServiceFixture.cs +++ b/src/NzbDrone.Core.Test/Blacklisting/BlacklistServiceFixture.cs @@ -19,8 +19,9 @@ public void Setup() { _event = new DownloadFailedEvent { - SeriesId = 12345, - EpisodeIds = new List {1}, + SeriesId = 0, + MovieId = 69, + EpisodeIds = null, Quality = new QualityModel(Quality.Bluray720p), SourceTitle = "series.title.s01e01", DownloadClient = "SabnzbdClient", @@ -40,7 +41,7 @@ public void should_add_to_repository() Subject.Handle(_event); Mocker.GetMock() - .Verify(v => v.Insert(It.Is(b => b.EpisodeIds == _event.EpisodeIds)), Times.Once()); + .Verify(v => v.Insert(It.Is(b => b.MovieId == _event.MovieId)), Times.Once()); } [Test] @@ -52,7 +53,7 @@ public void should_add_to_repository_missing_size_and_protocol() _event.Data.Remove("protocol"); Mocker.GetMock() - .Verify(v => v.Insert(It.Is(b => b.EpisodeIds == _event.EpisodeIds)), Times.Once()); + .Verify(v => v.Insert(It.Is(b => b.MovieId == _event.MovieId)), Times.Once()); } } } diff --git a/src/NzbDrone.Core/Blacklisting/BlacklistService.cs b/src/NzbDrone.Core/Blacklisting/BlacklistService.cs index ded7338f3..ded3a573f 100644 --- a/src/NzbDrone.Core/Blacklisting/BlacklistService.cs +++ b/src/NzbDrone.Core/Blacklisting/BlacklistService.cs @@ -129,7 +129,7 @@ public void Handle(DownloadFailedEvent message) var blacklist = new Blacklist { SeriesId = 0, - EpisodeIds = message.EpisodeIds, + EpisodeIds = null, MovieId = message.MovieId, SourceTitle = message.SourceTitle, Quality = message.Quality, diff --git a/src/NzbDrone.Core/History/History.cs b/src/NzbDrone.Core/History/History.cs index 451e9b1d5..b0e21d28e 100644 --- a/src/NzbDrone.Core/History/History.cs +++ b/src/NzbDrone.Core/History/History.cs @@ -35,9 +35,11 @@ public enum HistoryEventType { Unknown = 0, Grabbed = 1, - SeriesFolderImported = 2, + SeriesFolderImported = 2, // to be deprecate DownloadFolderImported = 3, DownloadFailed = 4, - EpisodeFileDeleted = 5 + EpisodeFileDeleted = 5, // deprecated + MovieFileDeleted = 6, + MovieFolderImported = 7, // not used yet } } \ No newline at end of file diff --git a/src/NzbDrone.Core/History/HistoryRepository.cs b/src/NzbDrone.Core/History/HistoryRepository.cs index bc0a54a5a..5cde171a3 100644 --- a/src/NzbDrone.Core/History/HistoryRepository.cs +++ b/src/NzbDrone.Core/History/HistoryRepository.cs @@ -17,6 +17,7 @@ public interface IHistoryRepository : IBasicRepository List FindByDownloadId(string downloadId); List FindDownloadHistory(int idSeriesId, QualityModel quality); void DeleteForSeries(int seriesId); + void DeleteForMovie(int movieId); History MostRecentForMovie(int movieId); } @@ -71,6 +72,11 @@ public void DeleteForSeries(int seriesId) Delete(c => c.SeriesId == seriesId); } + public void DeleteForMovie(int movieId) + { + Delete(c => c.MovieId == movieId); + } + protected override SortBuilder GetPagedQuery(QueryBuilder query, PagingSpec pagingSpec) { var baseQuery = query/*.Join(JoinType.Inner, h => h.Series, (h, s) => h.SeriesId == s.Id) diff --git a/src/NzbDrone.Core/History/HistoryService.cs b/src/NzbDrone.Core/History/HistoryService.cs index 634cf8b00..a4408ed7a 100644 --- a/src/NzbDrone.Core/History/HistoryService.cs +++ b/src/NzbDrone.Core/History/HistoryService.cs @@ -35,6 +35,7 @@ public class HistoryService : IHistoryService, IHandle, IHandle, IHandle, + IHandle, IHandle { private readonly IHistoryRepository _historyRepository; @@ -89,6 +90,160 @@ public QualityModel GetBestQualityInHistory(Profile profile, int episodeId) .FirstOrDefault(); } + public void Handle(MovieGrabbedEvent message) + { + var history = new History + { + EventType = HistoryEventType.Grabbed, + Date = DateTime.UtcNow, + Quality = message.Movie.ParsedMovieInfo.Quality, + SourceTitle = message.Movie.Release.Title, + SeriesId = 0, + EpisodeId = 0, + DownloadId = message.DownloadId, + MovieId = message.Movie.Movie.Id + }; + + history.Data.Add("Indexer", message.Movie.Release.Indexer); + history.Data.Add("NzbInfoUrl", message.Movie.Release.InfoUrl); + history.Data.Add("ReleaseGroup", message.Movie.ParsedMovieInfo.ReleaseGroup); + history.Data.Add("Age", message.Movie.Release.Age.ToString()); + history.Data.Add("AgeHours", message.Movie.Release.AgeHours.ToString()); + history.Data.Add("AgeMinutes", message.Movie.Release.AgeMinutes.ToString()); + history.Data.Add("PublishedDate", message.Movie.Release.PublishDate.ToString("s") + "Z"); + history.Data.Add("DownloadClient", message.DownloadClient); + history.Data.Add("Size", message.Movie.Release.Size.ToString()); + history.Data.Add("DownloadUrl", message.Movie.Release.DownloadUrl); + history.Data.Add("Guid", message.Movie.Release.Guid); + history.Data.Add("TvdbId", message.Movie.Release.TvdbId.ToString()); + history.Data.Add("TvRageId", message.Movie.Release.TvRageId.ToString()); + history.Data.Add("Protocol", ((int)message.Movie.Release.DownloadProtocol).ToString()); + + if (!message.Movie.ParsedMovieInfo.ReleaseHash.IsNullOrWhiteSpace()) + { + history.Data.Add("ReleaseHash", message.Movie.ParsedMovieInfo.ReleaseHash); + } + + var torrentRelease = message.Movie.Release as TorrentInfo; + + if (torrentRelease != null) + { + history.Data.Add("TorrentInfoHash", torrentRelease.InfoHash); + } + + _historyRepository.Insert(history); + } + + public void Handle(MovieImportedEvent message) + { + if (!message.NewDownload) + { + return; + } + + var downloadId = message.DownloadId; + + if (downloadId.IsNullOrWhiteSpace()) + { + downloadId = FindDownloadId(message); //For now fuck off. + } + + var movie = message.MovieInfo.Movie; + var history = new History + { + EventType = HistoryEventType.DownloadFolderImported, + Date = DateTime.UtcNow, + Quality = message.MovieInfo.Quality, + SourceTitle = movie.Title, + SeriesId = 0, + EpisodeId = 0, + DownloadId = downloadId, + MovieId = movie.Id, + }; + + //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.MovieInfo.Path); + history.Data.Add("ImportedPath", Path.Combine(movie.Path, message.ImportedMovie.RelativePath)); + history.Data.Add("DownloadClient", message.DownloadClient); + + _historyRepository.Insert(history); + } + + public void Handle(MovieFileDeletedEvent message) + { + if (message.Reason == DeleteMediaFileReason.NoLinkedEpisodes) + { + _logger.Debug("Removing movie file from DB as part of cleanup routine, not creating history event."); + return; + } + + var history = new History + { + EventType = HistoryEventType.MovieFileDeleted, + Date = DateTime.UtcNow, + Quality = message.MovieFile.Quality, + SourceTitle = message.MovieFile.Path, + SeriesId = 0, + EpisodeId = 0, + MovieId = message.MovieFile.MovieId + }; + + history.Data.Add("Reason", message.Reason.ToString()); + + _historyRepository.Insert(history); + } + + public void Handle(MovieDeletedEvent message) + { + _historyRepository.DeleteForMovie(message.Movie.Id); + } + + private string FindDownloadId(MovieImportedEvent trackedDownload) + { + _logger.Debug("Trying to find downloadId for {0} from history", trackedDownload.ImportedMovie.Path); + + 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 processedDownloadId = movieHistory + .Where(c => c.EventType != HistoryEventType.Grabbed && c.DownloadId != null) + .Select(c => c.DownloadId); + + var stillDownloading = movieHistory.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.MovieId == e.Id).ToList())) + //foreach (var matchingHistory in stillDownloading.Where(c => c.MovieId == e.Id).ToList()) + //{ + if (stillDownloading.Count != 1) + { + return null; + } + + var newDownloadId = stillDownloading.Single().DownloadId; + + if (downloadId == null || downloadId == newDownloadId) + { + downloadId = newDownloadId; + } + else + { + return null; + } + //} + } + + return downloadId; + } + private string FindDownloadId(EpisodeImportedEvent trackedDownload) { _logger.Debug("Trying to find downloadId for {0} from history", trackedDownload.ImportedEpisode.Path); @@ -181,50 +336,6 @@ public void Handle(EpisodeGrabbedEvent message) } } - public void Handle(MovieGrabbedEvent message) - { - var history = new History - { - EventType = HistoryEventType.Grabbed, - Date = DateTime.UtcNow, - Quality = message.Movie.ParsedMovieInfo.Quality, - SourceTitle = message.Movie.Release.Title, - SeriesId = 0, - EpisodeId = 0, - DownloadId = message.DownloadId, - MovieId = message.Movie.Movie.Id - }; - - history.Data.Add("Indexer", message.Movie.Release.Indexer); - history.Data.Add("NzbInfoUrl", message.Movie.Release.InfoUrl); - history.Data.Add("ReleaseGroup", message.Movie.ParsedMovieInfo.ReleaseGroup); - history.Data.Add("Age", message.Movie.Release.Age.ToString()); - history.Data.Add("AgeHours", message.Movie.Release.AgeHours.ToString()); - history.Data.Add("AgeMinutes", message.Movie.Release.AgeMinutes.ToString()); - history.Data.Add("PublishedDate", message.Movie.Release.PublishDate.ToString("s") + "Z"); - history.Data.Add("DownloadClient", message.DownloadClient); - history.Data.Add("Size", message.Movie.Release.Size.ToString()); - history.Data.Add("DownloadUrl", message.Movie.Release.DownloadUrl); - history.Data.Add("Guid", message.Movie.Release.Guid); - history.Data.Add("TvdbId", message.Movie.Release.TvdbId.ToString()); - history.Data.Add("TvRageId", message.Movie.Release.TvRageId.ToString()); - history.Data.Add("Protocol", ((int)message.Movie.Release.DownloadProtocol).ToString()); - - if (!message.Movie.ParsedMovieInfo.ReleaseHash.IsNullOrWhiteSpace()) - { - history.Data.Add("ReleaseHash", message.Movie.ParsedMovieInfo.ReleaseHash); - } - - var torrentRelease = message.Movie.Release as TorrentInfo; - - if (torrentRelease != null) - { - history.Data.Add("TorrentInfoHash", torrentRelease.InfoHash); - } - - _historyRepository.Insert(history); - } - public void Handle(EpisodeImportedEvent message) { if (!message.NewDownload) @@ -251,8 +362,6 @@ public void Handle(EpisodeImportedEvent message) EpisodeId = episode.Id, DownloadId = downloadId, MovieId = 0, - - }; //Won't have a value since we publish this event before saving to DB. @@ -265,65 +374,24 @@ public void Handle(EpisodeImportedEvent message) } } - public void Handle(MovieImportedEvent message) - { - if (!message.NewDownload) - { - return; - } - - var downloadId = message.DownloadId; - - if (downloadId.IsNullOrWhiteSpace()) - { - //downloadId = FindDownloadId(message); For now fuck off. - } - - var movie = message.MovieInfo.Movie; - var history = new History - { - EventType = HistoryEventType.DownloadFolderImported, - Date = DateTime.UtcNow, - Quality = message.MovieInfo.Quality, - SourceTitle = movie.Title, - SeriesId = 0, - EpisodeId = 0, - DownloadId = downloadId, - MovieId = movie.Id, - - - }; - - //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.MovieInfo.Path); - history.Data.Add("ImportedPath", Path.Combine(movie.Path, message.ImportedMovie.RelativePath)); - history.Data.Add("DownloadClient", message.DownloadClient); - - _historyRepository.Insert(history); - - } - public void Handle(DownloadFailedEvent message) { - foreach (var episodeId in message.EpisodeIds) + var history = new History { - var history = new History - { - EventType = HistoryEventType.DownloadFailed, - Date = DateTime.UtcNow, - Quality = message.Quality, - SourceTitle = message.SourceTitle, - SeriesId = message.SeriesId, - EpisodeId = episodeId, - DownloadId = message.DownloadId - }; + EventType = HistoryEventType.DownloadFailed, + Date = DateTime.UtcNow, + Quality = message.Quality, + SourceTitle = message.SourceTitle, + SeriesId = 0, + EpisodeId = 0, + MovieId = message.MovieId, + DownloadId = message.DownloadId + }; - history.Data.Add("DownloadClient", message.DownloadClient); - history.Data.Add("Message", message.Message); + history.Data.Add("DownloadClient", message.DownloadClient); + history.Data.Add("Message", message.Message); - _historyRepository.Insert(history); - } + _historyRepository.Insert(history); } public void Handle(EpisodeFileDeletedEvent message) diff --git a/src/UI/Activity/Blacklist/BlacklistCollection.js b/src/UI/Activity/Blacklist/BlacklistCollection.js index d7e2f1a16..626123711 100644 --- a/src/UI/Activity/Blacklist/BlacklistCollection.js +++ b/src/UI/Activity/Blacklist/BlacklistCollection.js @@ -26,7 +26,7 @@ var Collection = PageableCollection.extend({ }, sortMappings : { - 'series' : { sortKey : 'series.sortTitle' } + 'movie' : { sortKey : 'movie.title' } }, parseState : function(resp) { diff --git a/src/UI/Activity/Blacklist/BlacklistLayout.js b/src/UI/Activity/Blacklist/BlacklistLayout.js index 22d7da60e..c6ca98dab 100644 --- a/src/UI/Activity/Blacklist/BlacklistLayout.js +++ b/src/UI/Activity/Blacklist/BlacklistLayout.js @@ -2,7 +2,7 @@ var vent = require('vent'); var Marionette = require('marionette'); var Backgrid = require('backgrid'); var BlacklistCollection = require('./BlacklistCollection'); -var SeriesTitleCell = require('../../Cells/SeriesTitleCell'); +var MovieTitleCell = require('../../Cells/MovieTitleCell'); var QualityCell = require('../../Cells/QualityCell'); var RelativeDateCell = require('../../Cells/RelativeDateCell'); var BlacklistActionsCell = require('./BlacklistActionsCell'); @@ -21,9 +21,9 @@ module.exports = Marionette.Layout.extend({ columns : [ { - name : 'series', - label : 'Series', - cell : SeriesTitleCell + name : 'movie', + label : 'Movie Title', + cell : MovieTitleCell }, { name : 'sourceTitle', diff --git a/src/UI/Activity/Blacklist/BlacklistModel.js b/src/UI/Activity/Blacklist/BlacklistModel.js index e103f718f..c94d57d47 100644 --- a/src/UI/Activity/Blacklist/BlacklistModel.js +++ b/src/UI/Activity/Blacklist/BlacklistModel.js @@ -1,17 +1,23 @@ var Backbone = require('backbone'); -var SeriesCollection = require('../../Series/SeriesCollection'); +var SeriesModel = require('../../Series/SeriesModel'); +var EpisodeModel = require('../../Series/EpisodeModel'); +var MovieModel = require('../../Movies/MovieModel'); +var MoviesCollection = require('../../Movies/FullMovieCollection'); module.exports = Backbone.Model.extend({ - - //Hack to deal with Backbone 1.0's bug - initialize : function() { - this.url = function() { - return this.collection.url + '/' + this.get('id'); - }; - }, - parse : function(model) { - model.series = SeriesCollection.get(model.seriesId); + if (model.series) { + model.series = new SeriesModel(model.series); + model.episode = new EpisodeModel(model.episode); + model.episode.set('series', model.series); + } + + //if (model.movie) { + // model.movie = new MovieModel(model.movie); + //} + + model.movie = MoviesCollection.get(model.movieId); + return model; } -}); \ No newline at end of file +}); diff --git a/src/UI/Activity/History/HistoryCollection.js b/src/UI/Activity/History/HistoryCollection.js index 8c82b7988..3db1b0d21 100644 --- a/src/UI/Activity/History/HistoryCollection.js +++ b/src/UI/Activity/History/HistoryCollection.js @@ -45,7 +45,7 @@ var Collection = PageableCollection.extend({ ], 'deleted' : [ 'eventType', - '5' + '6' ] }, diff --git a/src/UI/Cells/EventTypeCell.js b/src/UI/Cells/EventTypeCell.js index 5426c7efb..ed58b17f3 100644 --- a/src/UI/Cells/EventTypeCell.js +++ b/src/UI/Cells/EventTypeCell.js @@ -31,6 +31,10 @@ module.exports = NzbDroneCell.extend({ icon = 'icon-sonarr-deleted'; toolTip = 'Movie file deleted'; break; + case 'movieFileDeleted': + icon = 'icon-sonarr-deleted'; + toolTip = 'Movie file deleted'; + break; default: icon = 'icon-sonarr-unknown'; toolTip = 'unknown event'; diff --git a/src/UI/Movies/MovieModel.js b/src/UI/Movies/MovieModel.js index c1e731664..2a7a9249c 100644 --- a/src/UI/Movies/MovieModel.js +++ b/src/UI/Movies/MovieModel.js @@ -21,6 +21,7 @@ module.exports = Backbone.Model.extend({ //var timeSince = new Date().getTime() - date.getTime(); //var numOfMonths = timeSince / 1000 / 60 / 60 / 24 / 30; + // lol could return status if (status === "announced") { return "announced"; }