diff --git a/NzbDrone.Core/IndexerSearch/EpisodeSearchCommand.cs b/NzbDrone.Core/IndexerSearch/EpisodeSearchCommand.cs new file mode 100644 index 000000000..b0dce2fd1 --- /dev/null +++ b/NzbDrone.Core/IndexerSearch/EpisodeSearchCommand.cs @@ -0,0 +1,9 @@ +using NzbDrone.Common.Messaging; + +namespace NzbDrone.Core.IndexerSearch +{ + public class EpisodeSearchCommand : ICommand + { + public int EpisodeId { get; set; } + } +} \ No newline at end of file diff --git a/NzbDrone.Core/IndexerSearch/EpisodeSearchService.cs b/NzbDrone.Core/IndexerSearch/EpisodeSearchService.cs new file mode 100644 index 000000000..3f215b0fa --- /dev/null +++ b/NzbDrone.Core/IndexerSearch/EpisodeSearchService.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using NzbDrone.Common.Messaging; +using NzbDrone.Core.Download; + +namespace NzbDrone.Core.IndexerSearch +{ + public class EpisodeSearchService : IExecute + { + private readonly ISearchForNzb _nzbSearchService; + private readonly IDownloadApprovedReports _downloadApprovedReports; + + public EpisodeSearchService(ISearchForNzb nzbSearchService, IDownloadApprovedReports downloadApprovedReports) + { + _nzbSearchService = nzbSearchService; + _downloadApprovedReports = downloadApprovedReports; + } + + public void Execute(EpisodeSearchCommand message) + { + var decisions = _nzbSearchService.EpisodeSearch(message.EpisodeId); + _downloadApprovedReports.DownloadApproved(decisions); + } + } +} diff --git a/NzbDrone.Core/NzbDrone.Core.csproj b/NzbDrone.Core/NzbDrone.Core.csproj index bdeec9ed2..b82ef3973 100644 --- a/NzbDrone.Core/NzbDrone.Core.csproj +++ b/NzbDrone.Core/NzbDrone.Core.csproj @@ -250,6 +250,8 @@ + + diff --git a/UI/Episode/Layout.js b/UI/Episode/Layout.js index d895c99f5..e7481f498 100644 --- a/UI/Episode/Layout.js +++ b/UI/Episode/Layout.js @@ -3,15 +3,12 @@ define( [ 'marionette', 'Episode/Summary/View', - 'Episode/Search/Layout', - 'Release/Collection', - 'Shared/SpinnerView' - ], function (Marionette, SummaryView, SearchLayout, ReleaseCollection, SpinnerView) { + 'Episode/Search/Layout' + ], function (Marionette, SummaryView, SearchLayout) { return Marionette.Layout.extend({ template: 'Episode/LayoutTemplate', - regions: { summary : '#episode-summary', activity: '#episode-activity', @@ -31,7 +28,6 @@ define( 'click .x-episode-search' : '_showSearch' }, - onShow: function () { this._showSummary(); this._releaseSearchActivated = false; @@ -61,23 +57,8 @@ define( e.preventDefault(); } - if (this._releaseSearchActivated) { - return; - } - - var self = this; - this.ui.search.tab('show'); - this.search.show(new SpinnerView()); - - var releases = new ReleaseCollection(); - var promise = releases.fetchEpisodeReleases(this.model.id); - - promise.done(function () { - if (!self.isClosed) { - self.search.show(new SearchLayout({collection: releases})); - } - }); + this.search.show(new SearchLayout({ model: this.model })); } }); diff --git a/UI/Episode/Search/Layout.js b/UI/Episode/Search/Layout.js index e4e5d68e2..300b99a87 100644 --- a/UI/Episode/Search/Layout.js +++ b/UI/Episode/Search/Layout.js @@ -1,69 +1,71 @@ 'use strict'; define( [ + 'app', 'marionette', - 'backgrid', - 'Cells/FileSizeCell', - 'Cells/QualityCell', - 'Release/ApprovalStatusCell', - 'Release/DownloadReportCell' - ], function (Marionette, Backgrid, FileSizeCell, QualityCell, ApprovalStatusCell, DownloadReportCell) { + 'Episode/Search/ManualLayout', + 'Release/Collection', + 'Shared/SpinnerView', + 'Shared/Messenger', + 'Commands/CommandController' + ], function (App, Marionette, ManualSearchLayout, ReleaseCollection, SpinnerView, Messenger, CommandController) { return Marionette.Layout.extend({ template: 'Episode/Search/LayoutTemplate', regions: { - grid: '#episode-release-grid' + main: '#episode-search-region' }, - columns: - [ - { - name : 'age', - label : 'Age', - sortable: true, - cell : Backgrid.IntegerCell - }, - { - name : 'title', - label : 'Title', - sortable: true, - cell : Backgrid.StringCell - }, - { - name : 'size', - label : 'Size', - sortable: true, - cell : FileSizeCell - }, - { - name : 'quality', - label : 'Quality', - sortable: true, - cell : QualityCell - }, - - { - name : 'rejections', - label: 'decision', - cell : ApprovalStatusCell - }, - { - name : 'download', - label: '', - cell : DownloadReportCell - } - ], + events: { + 'click .x-search-auto': '_searchAuto', + 'click .x-search-manual': '_searchManual' + }, onShow: function () { - if (!this.isClosed) { - this.grid.show(new Backgrid.Grid({ - row : Backgrid.Row, - columns : this.columns, - collection: this.collection, - className : 'table table-hover' - })); + this._releaseSearchActivated = false; + }, + + _searchAuto: function (e) { + if (e) { + e.preventDefault(); } + + CommandController.Execute('episodeSearch', { episodeId: this.model.get('id') }); + + var seriesTitle = this.model.get('series').get('title'); + var season = this.model.get('seasonNumber'); + var episode = this.model.get('episodeNumber'); + var message = seriesTitle + ' - S' + season.pad(2) + 'E' + episode.pad(2); + + Messenger.show({ + message: 'Search started for: ' + message + }); + + App.modalRegion.closeModal(); + }, + + _searchManual: function (e) { + if (e) { + e.preventDefault(); + } + + if (this._releaseSearchActivated) { + return; + } + + var self = this; + + this.main.show(new SpinnerView()); + + var releases = new ReleaseCollection(); + var promise = releases.fetchEpisodeReleases(this.model.id); + + promise.done(function () { + if (!self.isClosed) { + self.main.show(new ManualSearchLayout({collection: releases})); + } + }); } }); diff --git a/UI/Episode/Search/LayoutTemplate.html b/UI/Episode/Search/LayoutTemplate.html index d90cd597d..547d6d631 100644 --- a/UI/Episode/Search/LayoutTemplate.html +++ b/UI/Episode/Search/LayoutTemplate.html @@ -1 +1,7 @@ -
+ +
+
+ + +
+
\ No newline at end of file diff --git a/UI/Episode/Search/ManualLayout.js b/UI/Episode/Search/ManualLayout.js new file mode 100644 index 000000000..430f9f1d7 --- /dev/null +++ b/UI/Episode/Search/ManualLayout.js @@ -0,0 +1,71 @@ +'use strict'; +define( + [ + 'marionette', + 'backgrid', + 'Cells/FileSizeCell', + 'Cells/QualityCell', + 'Release/ApprovalStatusCell', + 'Release/DownloadReportCell' + + ], function (Marionette, Backgrid, FileSizeCell, QualityCell, ApprovalStatusCell, DownloadReportCell) { + + return Marionette.Layout.extend({ + template: 'Episode/Search/ManualLayoutTemplate', + + regions: { + grid: '#episode-release-grid' + }, + + columns: + [ + { + name : 'age', + label : 'Age', + sortable: true, + cell : Backgrid.IntegerCell + }, + { + name : 'title', + label : 'Title', + sortable: true, + cell : Backgrid.StringCell + }, + { + name : 'size', + label : 'Size', + sortable: true, + cell : FileSizeCell + }, + { + name : 'quality', + label : 'Quality', + sortable: true, + cell : QualityCell + }, + + { + name : 'rejections', + label: 'decision', + cell : ApprovalStatusCell + }, + { + name : 'download', + label: '', + cell : DownloadReportCell + } + ], + + onShow: function () { + if (!this.isClosed) { + this.grid.show(new Backgrid.Grid({ + row : Backgrid.Row, + columns : this.columns, + collection: this.collection, + className : 'table table-hover' + })); + } + } + }); + + }); diff --git a/UI/Episode/Search/ManualLayoutTemplate.html b/UI/Episode/Search/ManualLayoutTemplate.html new file mode 100644 index 000000000..d90cd597d --- /dev/null +++ b/UI/Episode/Search/ManualLayoutTemplate.html @@ -0,0 +1 @@ +
diff --git a/UI/Episode/Summary/ViewTemplate.html b/UI/Episode/Summary/ViewTemplate.html index 992793110..ebeedf1d0 100644 --- a/UI/Episode/Summary/ViewTemplate.html +++ b/UI/Episode/Summary/ViewTemplate.html @@ -15,7 +15,7 @@ {{path}} - {{Byte size}} + {{Bytes size}} {{quality.quality.name}} diff --git a/UI/Series/Details/SeasonCollectionView.js b/UI/Series/Details/SeasonCollectionView.js index c99df15d7..6fab22774 100644 --- a/UI/Series/Details/SeasonCollectionView.js +++ b/UI/Series/Details/SeasonCollectionView.js @@ -15,12 +15,13 @@ define( } this.episodeCollection = options.episodeCollection; - + this.series = options.series; }, itemViewOptions: function () { return { - episodeCollection: this.episodeCollection + episodeCollection: this.episodeCollection, + series : this.series }; } diff --git a/UI/Series/Details/SeasonLayout.js b/UI/Series/Details/SeasonLayout.js index 01cd6ea6a..31c0c466f 100644 --- a/UI/Series/Details/SeasonLayout.js +++ b/UI/Series/Details/SeasonLayout.js @@ -67,7 +67,7 @@ define( this.episodeCollection = options.episodeCollection.bySeason(this.model.get('seasonNumber')); _.each(this.episodeCollection.models, function (episode) { - episode.set({ hideSeriesLink: true }); + episode.set({ hideSeriesLink: true, series: options.series }); }); }, diff --git a/UI/Series/Details/SeriesDetailsLayout.js b/UI/Series/Details/SeriesDetailsLayout.js index b54d79525..8d4c08c0b 100644 --- a/UI/Series/Details/SeriesDetailsLayout.js +++ b/UI/Series/Details/SeriesDetailsLayout.js @@ -43,7 +43,8 @@ define( $.when(this.episodeCollection.fetch({data: { seriesId: this.model.id }}), this.seasonCollection.fetch({data: { seriesId: this.model.id }})).done(function () { self.seasons.show(new SeasonCollectionView({ collection : self.seasonCollection, - episodeCollection: self.episodeCollection + episodeCollection: self.episodeCollection, + series : self.model })); }); }, diff --git a/UI/Series/EpisodeModel.js b/UI/Series/EpisodeModel.js index 05e3e4eff..0321c1e77 100644 --- a/UI/Series/EpisodeModel.js +++ b/UI/Series/EpisodeModel.js @@ -89,8 +89,7 @@ define( defaults: { seasonNumber: 0, - status : 0, - title : 'TBA' + status : 0 } }); }); diff --git a/UI/Series/series.less b/UI/Series/series.less index 4748f73d9..07bc836bd 100644 --- a/UI/Series/series.less +++ b/UI/Series/series.less @@ -162,6 +162,12 @@ margin-top : 30px; font-size : 12px; } + + .search-buttons { + width: 400px; + margin-left: auto; + margin-right: auto; + } } .season-grid { diff --git a/UI/Settings/Notifications/EditView.js b/UI/Settings/Notifications/EditView.js index 27f4646f0..ebcb13ff0 100644 --- a/UI/Settings/Notifications/EditView.js +++ b/UI/Settings/Notifications/EditView.js @@ -6,10 +6,11 @@ define([ 'Settings/Notifications/Model', 'Settings/Notifications/DeleteView', 'Shared/Messenger', + 'Commands/CommandController', 'Mixins/AsModelBoundView', 'Form/FormBuilder' -], function (App, Marionette, NotificationModel, DeleteView, Messenger, AsModelBoundView) { +], function (App, Marionette, NotificationModel, DeleteView, Messenger, CommandController, AsModelBoundView) { var model = Marionette.ItemView.extend({ template: 'Settings/Notifications/EditTemplate', @@ -79,7 +80,7 @@ define([ }); var self = this; - var commandPromise = App.Commands.Execute(testCommand, properties); + var commandPromise = CommandController.Execute(testCommand, properties); commandPromise.done(function () { Messenger.show({ message: 'Notification settings tested successfully'