Added missing view
This commit is contained in:
parent
9ff7aa1bf7
commit
05c7b4f4ef
|
@ -2,6 +2,7 @@
|
||||||
using AutoMapper;
|
using AutoMapper;
|
||||||
using NzbDrone.Api.Calendar;
|
using NzbDrone.Api.Calendar;
|
||||||
using NzbDrone.Api.Episodes;
|
using NzbDrone.Api.Episodes;
|
||||||
|
using NzbDrone.Api.Missing;
|
||||||
using NzbDrone.Api.QualityProfiles;
|
using NzbDrone.Api.QualityProfiles;
|
||||||
using NzbDrone.Api.QualityType;
|
using NzbDrone.Api.QualityType;
|
||||||
using NzbDrone.Api.Resolvers;
|
using NzbDrone.Api.Resolvers;
|
||||||
|
@ -52,6 +53,11 @@ namespace NzbDrone.Api
|
||||||
|
|
||||||
//Episode
|
//Episode
|
||||||
Mapper.CreateMap<Episode, EpisodeResource>();
|
Mapper.CreateMap<Episode, EpisodeResource>();
|
||||||
|
|
||||||
|
//Missing
|
||||||
|
Mapper.CreateMap<Episode, MissingResource>()
|
||||||
|
.ForMember(dest => dest.SeriesTitle, opt => opt.MapFrom(src => src.Series.Title))
|
||||||
|
.ForMember(dest => dest.EpisodeTitle, opt => opt.MapFrom(src => src.Title));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using AutoMapper;
|
||||||
|
using Nancy;
|
||||||
|
using NzbDrone.Api.Extensions;
|
||||||
|
using NzbDrone.Core.Tv;
|
||||||
|
|
||||||
|
namespace NzbDrone.Api.Missing
|
||||||
|
{
|
||||||
|
public class MissingModule : NzbDroneApiModule
|
||||||
|
{
|
||||||
|
private readonly EpisodeService _episodeService;
|
||||||
|
|
||||||
|
public MissingModule(EpisodeService episodeService)
|
||||||
|
: base("/missing")
|
||||||
|
{
|
||||||
|
_episodeService = episodeService;
|
||||||
|
Get["/"] = x => GetMissingEpisodes();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Response GetMissingEpisodes()
|
||||||
|
{
|
||||||
|
bool includeSpecials;
|
||||||
|
Boolean.TryParse(PrimitiveExtensions.ToNullSafeString(Request.Query.IncludeSpecials), out includeSpecials);
|
||||||
|
|
||||||
|
var episodes = _episodeService.EpisodesWithoutFiles(includeSpecials);
|
||||||
|
return Mapper.Map<List<Episode>, List<MissingResource>>(episodes).AsResponse();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace NzbDrone.Api.Missing
|
||||||
|
{
|
||||||
|
public class MissingResource
|
||||||
|
{
|
||||||
|
public Int32 SeriesId { get; set; }
|
||||||
|
public String SeriesTitle { get; set; }
|
||||||
|
public Int32 EpisodeId { get; set; }
|
||||||
|
public String EpisodeTitle { get; set; }
|
||||||
|
public Int32 SeasonNumber { get; set; }
|
||||||
|
public Int32 EpisodeNumber { get; set; }
|
||||||
|
public DateTime? AirDate { get; set; }
|
||||||
|
public String Overview { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -120,6 +120,8 @@
|
||||||
<Compile Include="FrontendModule\IndexModule.cs" />
|
<Compile Include="FrontendModule\IndexModule.cs" />
|
||||||
<Compile Include="FrontendModule\BootstrapModule.cs" />
|
<Compile Include="FrontendModule\BootstrapModule.cs" />
|
||||||
<Compile Include="FrontendModule\LessService.cs" />
|
<Compile Include="FrontendModule\LessService.cs" />
|
||||||
|
<Compile Include="Missing\MissingResource.cs" />
|
||||||
|
<Compile Include="Missing\MissingModule.cs" />
|
||||||
<Compile Include="Resolvers\EndTimeResolver.cs" />
|
<Compile Include="Resolvers\EndTimeResolver.cs" />
|
||||||
<Compile Include="Resolvers\NextAiringResolver.cs" />
|
<Compile Include="Resolvers\NextAiringResolver.cs" />
|
||||||
<Compile Include="Resolvers\NullableDatetimeToString.cs" />
|
<Compile Include="Resolvers\NullableDatetimeToString.cs" />
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
'Calendar/CalendarCollectionView', 'Shared/NotificationView',
|
'Calendar/CalendarCollectionView', 'Shared/NotificationView',
|
||||||
'Shared/NotFoundView', 'MainMenuView', 'HeaderView',
|
'Shared/NotFoundView', 'MainMenuView', 'HeaderView',
|
||||||
'Series/Details/SeriesDetailsView', 'Series/EpisodeCollection',
|
'Series/Details/SeriesDetailsView', 'Series/EpisodeCollection',
|
||||||
'Settings/SettingsLayout'],
|
'Settings/SettingsLayout', 'Missing/MissingCollectionView'],
|
||||||
function (app, modalRegion) {
|
function (app, modalRegion) {
|
||||||
|
|
||||||
var controller = Backbone.Marionette.Controller.extend({
|
var controller = Backbone.Marionette.Controller.extend({
|
||||||
|
@ -48,12 +48,23 @@
|
||||||
|
|
||||||
var settingsModel = new NzbDrone.Settings.SettingsModel();
|
var settingsModel = new NzbDrone.Settings.SettingsModel();
|
||||||
settingsModel.fetch({
|
settingsModel.fetch({
|
||||||
success: function(settings){
|
success: function(settings) {
|
||||||
NzbDrone.mainRegion.show(new NzbDrone.Settings.SettingsLayout(this, action, query, settings));
|
NzbDrone.mainRegion.show(new NzbDrone.Settings.SettingsLayout(this, action, query, settings));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
missing: function(action, query) {
|
||||||
|
this.setTitle('Missing');
|
||||||
|
|
||||||
|
var missingCollection = new NzbDrone.Missing.MissingCollection();
|
||||||
|
missingCollection.fetch({
|
||||||
|
success: function(missing) {
|
||||||
|
NzbDrone.mainRegion.show(new NzbDrone.Missing.MissingCollectionView(this, action, query, missing));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
notFound: function () {
|
notFound: function () {
|
||||||
this.setTitle('Not Found');
|
this.setTitle('Not Found');
|
||||||
NzbDrone.mainRegion.show(new NzbDrone.Shared.NotFoundView(this));
|
NzbDrone.mainRegion.show(new NzbDrone.Shared.NotFoundView(this));
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
define(['app', 'Missing/MissingModel'], function () {
|
||||||
|
NzbDrone.Missing.MissingCollection = Backbone.Collection.extend({
|
||||||
|
url: NzbDrone.Constants.ApiRoot + '/missing',
|
||||||
|
model: NzbDrone.Missing.MissingModel,
|
||||||
|
comparator: function(model) {
|
||||||
|
return model.get('airDate');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,12 @@
|
||||||
|
<table class="table table-hover x-missing-table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Series Title</th>
|
||||||
|
<th>Episode</th>
|
||||||
|
<th>Episode Title</th>
|
||||||
|
<th>Air Date</th>
|
||||||
|
<th></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody></tbody>
|
||||||
|
</table>
|
|
@ -0,0 +1,75 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
define(['app', 'Missing/MissingItemView'], function (app) {
|
||||||
|
NzbDrone.Missing.MissingCollectionView = Backbone.Marionette.CompositeView.extend({
|
||||||
|
itemView: NzbDrone.Missing.MissingItemView,
|
||||||
|
itemViewContainer: 'tbody',
|
||||||
|
template: 'Missing/MissingCollectionTemplate',
|
||||||
|
|
||||||
|
ui:{
|
||||||
|
table : '.x-missing-table'
|
||||||
|
},
|
||||||
|
|
||||||
|
initialize: function (context, action, query, collection) {
|
||||||
|
this.collection = collection;
|
||||||
|
},
|
||||||
|
onCompositeCollectionRendered: function() {
|
||||||
|
this.ui.table.trigger('update');
|
||||||
|
|
||||||
|
if(!this.tableSorter && this.collection.length > 0)
|
||||||
|
{
|
||||||
|
this.tableSorter = this.ui.table.tablesorter({
|
||||||
|
textExtraction: function (node) {
|
||||||
|
return node.innerHTML;
|
||||||
|
},
|
||||||
|
sortList: [[3,1]],
|
||||||
|
headers: {
|
||||||
|
0: {
|
||||||
|
sorter: 'innerHtml'
|
||||||
|
},
|
||||||
|
1: {
|
||||||
|
sorter: false
|
||||||
|
},
|
||||||
|
2: {
|
||||||
|
sorter: false
|
||||||
|
},
|
||||||
|
3: {
|
||||||
|
sorter: 'date'
|
||||||
|
},
|
||||||
|
4: {
|
||||||
|
sorter: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
//Todo: We should extract these common settings out
|
||||||
|
this.ui.table.find('th.header').each(function(){
|
||||||
|
$(this).append('<i class="icon-sort pull-right">');
|
||||||
|
});
|
||||||
|
|
||||||
|
this.ui.table.bind("sortEnd", function() {
|
||||||
|
$(this).find('th.header i').each(function(){
|
||||||
|
$(this).remove();
|
||||||
|
});
|
||||||
|
|
||||||
|
$(this).find('th.header').each(function () {
|
||||||
|
if (!$(this).hasClass('headerSortDown') && !$(this).hasClass('headerSortUp'))
|
||||||
|
$(this).append('<i class="icon-sort pull-right">');
|
||||||
|
});
|
||||||
|
|
||||||
|
$(this).find('th.headerSortDown').each(function(){
|
||||||
|
$(this).append('<i class="icon-sort-up pull-right">');
|
||||||
|
});
|
||||||
|
|
||||||
|
$(this).find('th.headerSortUp').each(function(){
|
||||||
|
$(this).append('<i class="icon-sort-down pull-right">');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.ui.table.trigger('update');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,5 @@
|
||||||
|
<td><a href="/series/details/{{seriesId}}">{{seriesTitle}}</a></td>
|
||||||
|
<td>{{seasonNumber}}x{{paddedEpisodeNumber}}</td>
|
||||||
|
<td name="episodeTitle"></td>
|
||||||
|
<td><span title="{{formatedDateString}}" data-date="{{airDate}}">{{bestDateString}}</span></td>
|
||||||
|
<td><i class="icon-search x-search" title="Search for Episode"></i></td>
|
|
@ -0,0 +1,16 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
define([
|
||||||
|
'app',
|
||||||
|
'Missing/MissingCollection'
|
||||||
|
|
||||||
|
], function () {
|
||||||
|
NzbDrone.Missing.MissingItemView = Backbone.Marionette.ItemView.extend({
|
||||||
|
template: 'Missing/MissingItemTemplate',
|
||||||
|
tagName: 'tr',
|
||||||
|
|
||||||
|
onRender: function () {
|
||||||
|
NzbDrone.ModelBinder.bind(this.model, this.el);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
|
@ -0,0 +1,12 @@
|
||||||
|
define(['app'], function (app) {
|
||||||
|
NzbDrone.Missing.MissingModel = Backbone.Model.extend({
|
||||||
|
mutators: {
|
||||||
|
bestDateString: function () {
|
||||||
|
return bestDateString(this.get('airDate'));
|
||||||
|
},
|
||||||
|
paddedEpisodeNumber: function(){
|
||||||
|
return this.get('episodeNumber');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
|
@ -6,7 +6,7 @@ function bestDateString(sourceDate){
|
||||||
if (date.isYesterday()) return 'Yesterday';
|
if (date.isYesterday()) return 'Yesterday';
|
||||||
if (date.isToday()) return 'Today';
|
if (date.isToday()) return 'Today';
|
||||||
if (date.isTomorrow()) return 'Tomorrow';
|
if (date.isTomorrow()) return 'Tomorrow';
|
||||||
if (date.isBefore(Date.create().addDays(7))) return date.format('{Weekday}');
|
if (date.isAfter(Date.create('tomorrow')) && date.isBefore(Date.create().addDays(7))) return date.format('{Weekday}');
|
||||||
|
|
||||||
return date.format('{MM}/{dd}/{yyyy}');
|
return date.format('{MM}/{dd}/{yyyy}');
|
||||||
}
|
}
|
|
@ -15,6 +15,7 @@
|
||||||
'calendar': 'calendar',
|
'calendar': 'calendar',
|
||||||
'settings': 'settings',
|
'settings': 'settings',
|
||||||
'settings/:action(/:query)': 'settings',
|
'settings/:action(/:query)': 'settings',
|
||||||
|
'missing': 'missing',
|
||||||
':whatever': 'notFound'
|
':whatever': 'notFound'
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -57,6 +57,7 @@ define(['app', 'Quality/QualityProfileCollection', 'Series/Index/SeriesItemView'
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
//Todo: We should extract these common settings out
|
||||||
this.ui.table.find('th.header').each(function(){
|
this.ui.table.find('th.header').each(function(){
|
||||||
$(this).append('<i class="icon-sort pull-right">');
|
$(this).append('<i class="icon-sort pull-right">');
|
||||||
});
|
});
|
||||||
|
@ -72,11 +73,11 @@ define(['app', 'Quality/QualityProfileCollection', 'Series/Index/SeriesItemView'
|
||||||
});
|
});
|
||||||
|
|
||||||
$(this).find('th.headerSortDown').each(function(){
|
$(this).find('th.headerSortDown').each(function(){
|
||||||
$(this).append('<i class="icon-sort-down pull-right">');
|
$(this).append('<i class="icon-sort-up pull-right">');
|
||||||
});
|
});
|
||||||
|
|
||||||
$(this).find('th.headerSortUp').each(function(){
|
$(this).find('th.headerSortUp').each(function(){
|
||||||
$(this).append('<i class="icon-sort-up pull-right">');
|
$(this).append('<i class="icon-sort-down pull-right">');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,6 +52,7 @@ define('app', function () {
|
||||||
window.NzbDrone.Settings.Notifications = {};
|
window.NzbDrone.Settings.Notifications = {};
|
||||||
window.NzbDrone.Settings.System = {};
|
window.NzbDrone.Settings.System = {};
|
||||||
window.NzbDrone.Settings.Misc = {};
|
window.NzbDrone.Settings.Misc = {};
|
||||||
|
window.NzbDrone.Missing = {};
|
||||||
|
|
||||||
window.NzbDrone.Events = {
|
window.NzbDrone.Events = {
|
||||||
OpenModalDialog :'openModal',
|
OpenModalDialog :'openModal',
|
||||||
|
|
Binary file not shown.
|
@ -61,7 +61,7 @@ namespace NzbDrone.Core.Tvdb
|
||||||
[XmlElement]
|
[XmlElement]
|
||||||
public int EpisodeNumber { get; set; }
|
public int EpisodeNumber { get; set; }
|
||||||
|
|
||||||
[XmlIgnore]
|
[XmlElement]
|
||||||
public DateTime FirstAired { get; set; }
|
public DateTime FirstAired { get; set; }
|
||||||
|
|
||||||
[XmlElement]
|
[XmlElement]
|
||||||
|
|
Loading…
Reference in New Issue