basic implementation of the wanted tab (#31)

* top buttons don't yet work

* new missing module for movies

*  find missing movies method to movie service

* new movie status cell with text

* adapted UI missing collection and layout
This commit is contained in:
Vlad Ilies 2017-01-18 20:53:17 +02:00
parent 10dc3993df
commit da2d075aa8
9 changed files with 170 additions and 31 deletions

View File

@ -118,6 +118,7 @@
<Compile Include="Indexers\ReleasePushModule.cs" /> <Compile Include="Indexers\ReleasePushModule.cs" />
<Compile Include="Movies\MovieFileModule.cs" /> <Compile Include="Movies\MovieFileModule.cs" />
<Compile Include="Movies\MovieModule.cs" /> <Compile Include="Movies\MovieModule.cs" />
<Compile Include="Movies\MovieModuleWithSignalR.cs" />
<Compile Include="Movies\RenameMovieModule.cs" /> <Compile Include="Movies\RenameMovieModule.cs" />
<Compile Include="Movies\RenameMovieResource.cs" /> <Compile Include="Movies\RenameMovieResource.cs" />
<Compile Include="Movies\MovieEditorModule.cs" /> <Compile Include="Movies\MovieEditorModule.cs" />
@ -260,6 +261,7 @@
<Compile Include="Wanted\CutoffModule.cs" /> <Compile Include="Wanted\CutoffModule.cs" />
<Compile Include="Wanted\LegacyMissingModule.cs" /> <Compile Include="Wanted\LegacyMissingModule.cs" />
<Compile Include="Wanted\MissingModule.cs" /> <Compile Include="Wanted\MissingModule.cs" />
<Compile Include="Wanted\MovieMissingModule.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="app.config" /> <None Include="app.config" />

View File

@ -12,7 +12,7 @@ namespace NzbDrone.Api.Wanted
ISeriesService seriesService, ISeriesService seriesService,
IQualityUpgradableSpecification qualityUpgradableSpecification, IQualityUpgradableSpecification qualityUpgradableSpecification,
IBroadcastSignalRMessage signalRBroadcaster) IBroadcastSignalRMessage signalRBroadcaster)
: base(episodeService, seriesService, qualityUpgradableSpecification, signalRBroadcaster, "wanted/missing") : base(episodeService, seriesService, qualityUpgradableSpecification, signalRBroadcaster, "wanted/missing_episodes")
{ {
GetResourcePaged = GetMissingEpisodes; GetResourcePaged = GetMissingEpisodes;
} }

View File

@ -0,0 +1,77 @@
using NzbDrone.Api.Movie;
using NzbDrone.Api.Movies;
using NzbDrone.Core.DecisionEngine;
using NzbDrone.Core.Tv;
using NzbDrone.Core.Datastore;
using NzbDrone.SignalR;
using NzbDrone.Core.Download;
using NzbDrone.Core.MediaFiles.Events;
using NzbDrone.Core.Messaging.Events;
using System;
using NzbDrone.Core.Datastore.Events;
namespace NzbDrone.Api.Wanted
{
class MovieMissingModule : NzbDroneRestModuleWithSignalR<MovieResource, Core.Tv.Movie>,
IHandle<MovieGrabbedEvent>,
IHandle<MovieDownloadedEvent>
{
protected readonly IMovieService _movieService;
public MovieMissingModule(IMovieService movieService,
IQualityUpgradableSpecification qualityUpgradableSpecification,
IBroadcastSignalRMessage signalRBroadcaster)
: base(signalRBroadcaster, "wanted/missing")
{
_movieService = movieService;
GetResourcePaged = GetMissingMovies;
}
private PagingResource<MovieResource> GetMissingMovies(PagingResource<MovieResource> pagingResource)
{
var pagingSpec = pagingResource.MapToPagingSpec<MovieResource, Core.Tv.Movie>("physicalRelease", SortDirection.Descending);
if (pagingResource.FilterKey == "monitored" && pagingResource.FilterValue == "false")
{
pagingSpec.FilterExpression = v => v.Monitored == false;
}
else
{
pagingSpec.FilterExpression = v => v.Monitored == true;
}
var resource = ApplyToPage(_movieService.MoviesWithoutFiles, pagingSpec, v => MapToResource(v, false));
return resource;
}
private MovieResource GetMovie(int id)
{
var movie = _movieService.GetMovie(id);
var resource = MapToResource(movie, true);
return resource;
}
private MovieResource MapToResource(Core.Tv.Movie movie, bool includeMovieFile)
{
var resource = movie.ToResource();
return resource;
}
public void Handle(MovieGrabbedEvent message)
{
var resource = message.Movie.Movie.ToResource();
//add a grabbed field in MovieResource?
//resource.Grabbed = true;
BroadcastResourceChange(ModelAction.Updated, resource);
}
public void Handle(MovieDownloadedEvent message)
{
BroadcastResourceChange(ModelAction.Updated, message.Movie.Movie.Id);
}
}
}

View File

@ -3,7 +3,7 @@ using System.Linq;
using System.Collections.Generic; using System.Collections.Generic;
using NzbDrone.Core.Datastore; using NzbDrone.Core.Datastore;
using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Messaging.Events;
using NzbDrone.Core.Datastore.Extensions;
namespace NzbDrone.Core.Tv namespace NzbDrone.Core.Tv
{ {
@ -15,6 +15,7 @@ namespace NzbDrone.Core.Tv
Movie FindByImdbId(string imdbid); Movie FindByImdbId(string imdbid);
Movie FindByTitleSlug(string slug); Movie FindByTitleSlug(string slug);
List<Movie> MoviesBetweenDates(DateTime start, DateTime end, bool includeUnmonitored); List<Movie> MoviesBetweenDates(DateTime start, DateTime end, bool includeUnmonitored);
PagingSpec<Movie> MoviesWithoutFiles(PagingSpec<Movie> pagingSpec);
List<Movie> GetMoviesByFileId(int fileId); List<Movie> GetMoviesByFileId(int fileId);
void SetFileId(int fileId, int movieId); void SetFileId(int fileId, int movieId);
} }
@ -132,5 +133,21 @@ namespace NzbDrone.Core.Tv
return query.ToList(); return query.ToList();
} }
public PagingSpec<Movie> MoviesWithoutFiles(PagingSpec<Movie> pagingSpec)
{
var query = Query.Where(pagingSpec.FilterExpression)
.AndWhere(m => m.MovieFileId == 0)
.AndWhere(m => m.Status == MovieStatusType.Released)
.OrderBy(pagingSpec.OrderByClause(), pagingSpec.ToSortDirection())
.Skip(pagingSpec.PagingOffset())
.Take(pagingSpec.PageSize);
pagingSpec.Records = query.ToList();
pagingSpec.TotalRecords = pagingSpec.Records.Count;
return pagingSpec;
}
} }
} }

View File

@ -12,6 +12,7 @@ using NzbDrone.Core.Parser;
using NzbDrone.Core.Tv.Events; using NzbDrone.Core.Tv.Events;
using NzbDrone.Core.MediaFiles; using NzbDrone.Core.MediaFiles;
using NzbDrone.Core.MediaFiles.Events; using NzbDrone.Core.MediaFiles.Events;
using NzbDrone.Core.Datastore;
namespace NzbDrone.Core.Tv namespace NzbDrone.Core.Tv
{ {
@ -27,6 +28,7 @@ namespace NzbDrone.Core.Tv
Movie FindByTitleSlug(string slug); Movie FindByTitleSlug(string slug);
Movie GetMovieByFileId(int fileId); Movie GetMovieByFileId(int fileId);
List<Movie> GetMoviesBetweenDates(DateTime start, DateTime end, bool includeUnmonitored); List<Movie> GetMoviesBetweenDates(DateTime start, DateTime end, bool includeUnmonitored);
PagingSpec<Movie> MoviesWithoutFiles(PagingSpec<Movie> pagingSpec);
void DeleteMovie(int movieId, bool deleteFiles); void DeleteMovie(int movieId, bool deleteFiles);
List<Movie> GetAllMovies(); List<Movie> GetAllMovies();
Movie UpdateMovie(Movie movie); Movie UpdateMovie(Movie movie);
@ -232,5 +234,12 @@ namespace NzbDrone.Core.Tv
return episodes; return episodes;
} }
public PagingSpec<Movie> MoviesWithoutFiles(PagingSpec<Movie> pagingSpec)
{
var movieResult = _movieRepository.MoviesWithoutFiles(pagingSpec);
return movieResult;
}
} }
} }

View File

@ -0,0 +1,42 @@
var NzbDroneCell = require('./NzbDroneCell');
//used in Wanted tab
module.exports = NzbDroneCell.extend({
className : 'movie-status-text-cell',
render : function() {
this.$el.empty();
var monitored = this.model.get('monitored');
var status = this.model.get('status');
var inCinemas = this.model.get("inCinemas");
var date = new Date(inCinemas);
var timeSince = new Date().getTime() - date.getTime();
var numOfMonths = timeSince / 1000 / 60 / 60 / 24 / 30;
if (status === 'released') {
this.$el.html('<div class="released-banner"><i class="icon-sonarr-movie-released grid-icon" title=""></i>&nbsp;Released</div>');
this._setStatusWeight(3);
}
if (numOfMonths > 3) {
this.$el.html('<div class="released-banner"><i class="icon-sonarr-movie-released grid-icon" title=""></i>&nbsp;Released</div>');//TODO: Update for PreDB.me
this._setStatusWeight(2);
}
if (numOfMonths < 3) {
this.$el.html('<div class="cinemas-banner"><i class="icon-sonarr-movie-cinemas grid-icon" title=""></i>&nbsp;In Cinemas</div>');
this._setStatusWeight(2);
}
if (status === "announced") {
this.$el.html('<div class="announced-banner"><i class="icon-sonarr-movie-announced grid-icon" title=""></i>&nbsp;Announced</div>');
this._setStatusWeight(1);
}
return this;
},
_setStatusWeight : function(weight) {
this.model.set('statusWeight', weight, { silent : true });
}
});

View File

@ -55,6 +55,10 @@
width : 150px; width : 150px;
} }
.movie-status-text-cell {
width : 150px;
}
.history-event-type-cell { .history-event-type-cell {
width : 10px; width : 10px;
} }

View File

@ -1,5 +1,5 @@
var _ = require('underscore'); var _ = require('underscore');
var EpisodeModel = require('../../Series/EpisodeModel'); var MovieModel = require('../../Movies/MovieModel');
var PagableCollection = require('backbone.pageable'); var PagableCollection = require('backbone.pageable');
var AsFilteredCollection = require('../../Mixins/AsFilteredCollection'); var AsFilteredCollection = require('../../Mixins/AsFilteredCollection');
var AsSortedCollection = require('../../Mixins/AsSortedCollection'); var AsSortedCollection = require('../../Mixins/AsSortedCollection');
@ -7,13 +7,13 @@ var AsPersistedStateCollection = require('../../Mixins/AsPersistedStateCollectio
var Collection = PagableCollection.extend({ var Collection = PagableCollection.extend({
url : window.NzbDrone.ApiRoot + '/wanted/missing', url : window.NzbDrone.ApiRoot + '/wanted/missing',
model : EpisodeModel, model : MovieModel,
tableName : 'wanted.missing', tableName : 'wanted.missing',
state : { state : {
pageSize : 15, pageSize : 15,
sortKey : 'airDateUtc', sortKey : 'inCinemas',
order : 1 order : -1
}, },
queryParams : { queryParams : {
@ -39,10 +39,6 @@ var Collection = PagableCollection.extend({
] ]
}, },
sortMappings : {
'series' : { sortKey : 'series.sortTitle' }
},
parseState : function(resp) { parseState : function(resp) {
return { totalRecords : resp.totalRecords }; return { totalRecords : resp.totalRecords };
}, },
@ -58,4 +54,4 @@ var Collection = PagableCollection.extend({
Collection = AsFilteredCollection.call(Collection); Collection = AsFilteredCollection.call(Collection);
Collection = AsSortedCollection.call(Collection); Collection = AsSortedCollection.call(Collection);
module.exports = AsPersistedStateCollection.call(Collection); module.exports = AsPersistedStateCollection.call(Collection);

View File

@ -5,11 +5,9 @@ var Marionette = require('marionette');
var Backgrid = require('backgrid'); var Backgrid = require('backgrid');
var MissingCollection = require('./MissingCollection'); var MissingCollection = require('./MissingCollection');
var SelectAllCell = require('../../Cells/SelectAllCell'); var SelectAllCell = require('../../Cells/SelectAllCell');
var SeriesTitleCell = require('../../Cells/SeriesTitleCell'); var MovieTitleCell = require('../../Cells/MovieTitleCell');
var EpisodeNumberCell = require('../../Cells/EpisodeNumberCell');
var EpisodeTitleCell = require('../../Cells/EpisodeTitleCell');
var RelativeDateCell = require('../../Cells/RelativeDateCell'); var RelativeDateCell = require('../../Cells/RelativeDateCell');
var EpisodeStatusCell = require('../../Cells/EpisodeStatusCell'); var MovieStatusWithTextCell = require('../../Cells/MovieStatusWithTextCell');
var GridPager = require('../../Shared/Grid/Pager'); var GridPager = require('../../Shared/Grid/Pager');
var ToolbarLayout = require('../../Shared/Toolbar/ToolbarLayout'); var ToolbarLayout = require('../../Shared/Toolbar/ToolbarLayout');
var LoadingView = require('../../Shared/LoadingView'); var LoadingView = require('../../Shared/LoadingView');
@ -39,35 +37,29 @@ module.exports = Marionette.Layout.extend({
headerCell : 'select-all', headerCell : 'select-all',
sortable : false sortable : false
}, },
{
name : 'series',
label : 'Series Title',
cell : SeriesTitleCell,
sortValue : 'series.sortTitle'
},
{ {
name : 'this', name : 'this',
label : 'Episode', label : 'Movie Title',
cell : EpisodeNumberCell, cell : MovieTitleCell,
sortable : false sortable : false
}, },
{ {
name : 'this', name : 'inCinemas',
label : 'Episode Title', label : 'In Cinemas',
cell : EpisodeTitleCell, cell : RelativeDateCell
sortable : false
}, },
{ {
name : 'airDateUtc', name : 'physicalRelease',
label : 'Air Date', label : 'PhysicalRelease',
cell : RelativeDateCell cell : RelativeDateCell
}, },
{ {
name : 'status', name : 'status',
label : 'Status', label : 'Status',
cell : EpisodeStatusCell, cell : MovieStatusWithTextCell,
sortable : false sortable : false
} },
], ],
initialize : function() { initialize : function() {