1
0
mirror of https://github.com/Radarr/Radarr.git synced 2024-11-09 04:22:30 +01:00

Series Details started

This commit is contained in:
Mark McDowall 2013-03-02 11:13:23 -08:00
parent e1a3637107
commit bb27995eaf
20 changed files with 243 additions and 24 deletions

View File

@ -1,6 +1,7 @@
using System; using System;
using AutoMapper; using AutoMapper;
using NzbDrone.Api.Calendar; using NzbDrone.Api.Calendar;
using NzbDrone.Api.Episodes;
using NzbDrone.Api.QualityProfiles; using NzbDrone.Api.QualityProfiles;
using NzbDrone.Api.QualityType; using NzbDrone.Api.QualityType;
using NzbDrone.Api.Resolvers; using NzbDrone.Api.Resolvers;
@ -48,6 +49,9 @@ public static void InitializeAutomapper()
.ForMember(dest => dest.EpisodeTitle, opt => opt.MapFrom(src => src.Title)) .ForMember(dest => dest.EpisodeTitle, opt => opt.MapFrom(src => src.Title))
.ForMember(dest => dest.Start, opt => opt.MapFrom(src => src.AirDate)) .ForMember(dest => dest.Start, opt => opt.MapFrom(src => src.AirDate))
.ForMember(dest => dest.End, opt => opt.ResolveUsing<EndTimeResolver>()); .ForMember(dest => dest.End, opt => opt.ResolveUsing<EndTimeResolver>());
//Episode
Mapper.CreateMap<Episode, EpisodeResource>();
} }
} }
} }

View File

@ -0,0 +1,29 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using AutoMapper;
using Nancy;
using NzbDrone.Api.Extensions;
using NzbDrone.Core.Tv;
namespace NzbDrone.Api.Episodes
{
public class EpisodeModule : NzbDroneApiModule
{
private readonly EpisodeService _episodeService;
public EpisodeModule(EpisodeService episodeService)
: base("/episodes")
{
_episodeService = episodeService;
Get["/{seriesId}"] = x => GetEpisodesForSeries(x.SeriesId);
}
private Response GetEpisodesForSeries(int seriesId)
{
var episodes = _episodeService.GetEpisodeBySeries(seriesId);
return Mapper.Map<List<Episode>, List<EpisodeResource>>(episodes).AsResponse();
}
}
}

View File

@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NzbDrone.Core.Tv;
namespace NzbDrone.Api.Episodes
{
public class EpisodeResource
{
public Int32 SeriesId { get; set; }
public Int32 EpisodeId { get; set; }
public Int32 EpisodeFileId { get; set; }
public Int32 SeasonNumber { get; set; }
public Int32 EpisodeNumber { get; set; }
public String Title { get; set; }
public DateTime AirDate { get; set; }
public Int32 Status { get; set; }
public String Overview { get; set; }
public EpisodeFile EpisodeFile { get; set; }
}
}

View File

@ -113,6 +113,8 @@
<Compile Include="Calendar\CalendarModule.cs" /> <Compile Include="Calendar\CalendarModule.cs" />
<Compile Include="Calendar\CalendarResource.cs" /> <Compile Include="Calendar\CalendarResource.cs" />
<Compile Include="Directories\DirectoryModule.cs" /> <Compile Include="Directories\DirectoryModule.cs" />
<Compile Include="Episodes\EpisodeModule.cs" />
<Compile Include="Episodes\EpisodeResource.cs" />
<Compile Include="Extensions\NancyJsonSerializer.cs" /> <Compile Include="Extensions\NancyJsonSerializer.cs" />
<Compile Include="Extensions\Serializer.cs" /> <Compile Include="Extensions\Serializer.cs" />
<Compile Include="FrontendModule\IndexModule.cs" /> <Compile Include="FrontendModule\IndexModule.cs" />

View File

@ -1,6 +1,9 @@
define(['app', 'Shared/ModalRegion', 'AddSeries/AddSeriesLayout', 'Series/SeriesCollectionView', define(['app', 'Shared/ModalRegion', 'AddSeries/AddSeriesLayout',
'Upcoming/UpcomingCollectionView', 'Calendar/CalendarCollectionView', 'Shared/NotificationView', 'Series/SeriesCollectionView', 'Upcoming/UpcomingCollectionView',
'Shared/NotFoundView', 'MainMenuView', 'HeaderView'], function (app, modalRegion) { 'Calendar/CalendarCollectionView', 'Shared/NotificationView',
'Shared/NotFoundView', 'MainMenuView', 'HeaderView',
'Series/Details/SeriesDetailsView', 'Series/Details/EpisodeCollection'],
function (app, modalRegion) {
var controller = Backbone.Marionette.Controller.extend({ var controller = Backbone.Marionette.Controller.extend({
@ -26,6 +29,36 @@
NzbDrone.mainRegion.show(new NzbDrone.Calendar.CalendarCollectionView(this, action, query, calendarCollection)); NzbDrone.mainRegion.show(new NzbDrone.Calendar.CalendarCollectionView(this, action, query, calendarCollection));
}, },
seriesDetails: function (query) {
this.setTitle('Series Title Goes Here');
// var seriesModel = new NzbDrone.Series.SeriesModel();
// seriesModel.fetch();
var seriesEpisodes = new NzbDrone.Series.Details.EpisodeCollection({ seriesId: query });
seriesEpisodes.fetch({
success: function (collection) {
var seasons = collection.models.groupBy(function(episode){
var seasonNumber = episode.get('seasonNumber');
if (seasonNumber === undefined)
return 0;
return seasonNumber;
});
var seasonCollection = new NzbDrone.Series.Details.SeasonCollection();
$.each(seasons, function(index, season){
seasonCollection.add(new NzbDrone.Series.Details.SeasonModel(
{ seasonNumber: index, episodes: season })
);
});
NzbDrone.mainRegion.show(new NzbDrone.Series.Details.SeriesDetailsView({ collection: seasonCollection }));
}
});
},
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));

View File

@ -32,6 +32,7 @@
<CodeAnalysisIgnoreGeneratedCode>true</CodeAnalysisIgnoreGeneratedCode> <CodeAnalysisIgnoreGeneratedCode>true</CodeAnalysisIgnoreGeneratedCode>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Content Include="HeaderView.js" />
<Content Include="MainMenuView.js" /> <Content Include="MainMenuView.js" />
<Content Include="AddSeries\addSeries.css" /> <Content Include="AddSeries\addSeries.css" />
<Content Include="AddSeries\AddSeriesLayout.js" /> <Content Include="AddSeries\AddSeriesLayout.js" />
@ -121,6 +122,12 @@
<Content Include="Routing.js" /> <Content Include="Routing.js" />
<Content Include="Series\Delete\DeleteSeriesTemplate.html" /> <Content Include="Series\Delete\DeleteSeriesTemplate.html" />
<Content Include="Series\Delete\DeleteSeriesView.js" /> <Content Include="Series\Delete\DeleteSeriesView.js" />
<Content Include="Series\Details\EpisodeModel.js" />
<Content Include="Series\Details\SeasonCollection.js" />
<Content Include="Series\Details\SeasonCollectionTemplate.html" />
<Content Include="Series\Details\SeasonCollectionView.js" />
<Content Include="Series\Details\SeriesDetailsTemplate.html" />
<Content Include="Series\Details\SeriesDetailsView.js" />
<Content Include="Series\Edit\EditSeriesTemplate.html" /> <Content Include="Series\Edit\EditSeriesTemplate.html" />
<Content Include="Series\Edit\EditSeriesView.js" /> <Content Include="Series\Edit\EditSeriesView.js" />
<Content Include="Series\EmptySeriesCollectionTemplate.html" /> <Content Include="Series\EmptySeriesCollectionTemplate.html" />

View File

@ -9,6 +9,7 @@
'series/index': 'series', 'series/index': 'series',
'series/add': 'addSeries', 'series/add': 'addSeries',
'series/add/:action(/:query)': 'addSeries', 'series/add/:action(/:query)': 'addSeries',
'series/details/:query': 'seriesDetails',
'upcoming': 'upcoming', 'upcoming': 'upcoming',
'upcoming/index': 'upcoming', 'upcoming/index': 'upcoming',
'calendar': 'calendar', 'calendar': 'calendar',

View File

@ -0,0 +1,13 @@
define(['app', 'Series/Details/EpisodeModel'], function () {
NzbDrone.Series.Details.EpisodeCollection = Backbone.Collection.extend({
initialize: function(options) {
this.seriesId = options.seriesId;
},
url: function(){
return NzbDrone.Constants.ApiRoot + '/episodes/' + this.seriesId;
},
model: NzbDrone.Series.Details.EpisodeModel
});
});

View File

@ -0,0 +1 @@
{{title}}

View File

@ -0,0 +1,24 @@
'use strict';
define([
'app',
'Series/Details/SeasonModel'
], function () {
NzbDrone.Series.Details.EpisodeItemView = Backbone.Marionette.ItemView.extend({
template: 'Series/Details/EpisodeItemTemplate',
tagName: 'tr',
ui: {
},
events: {
},
onRender: function () {
NzbDrone.ModelBinder.bind(this.model, this.el);
}
});
});

View File

@ -0,0 +1,12 @@
define(['app'], function (app) {
NzbDrone.Series.Details.EpisodeModel = Backbone.Model.extend({
mutators: {
},
defaults: {
seasonNumber: 0
}
});
});

View File

@ -0,0 +1,10 @@
define(['app'], function (app) {
NzbDrone.Series.Details.SeasonCollection = Backbone.Collection.extend({
// Todo: Why does this throw: "this.model is undefined" - Chnaging to another model fixes it
//model: NzbDrone.Series.Details.SeasonModel,
model: NzbDrone.Series.Details.EpisodeModel,
comparator: function(model) {
return -model.get('seasonNumber');
}
});
});

View File

@ -0,0 +1,13 @@
<h3>Season {{seasonNumber}}</h3>
<table class="table table-hover x-season-table">
<thead>
<tr>
<th>#</th>
<th>Title</th>
<th>Air Date</th>
<th>Quality</th>
<th>Controls</th>
</tr>
</thead>
<tbody></tbody>
</table>

View File

@ -0,0 +1,15 @@
'use strict';
define(['app', 'Series/Details/EpisodeItemView'], function (app) {
NzbDrone.Series.Details.SeasonCollectionView = Backbone.Marionette.CompositeView.extend({
itemView: NzbDrone.Series.Details.EpisodeItemView,
itemViewContainer: '#seasons',
template: 'Series/Details/SeasonCollectionTemplate',
initialize: function() {
var episodes = this.model.get('episodes');
var test = 1;
//this.collection
}
});
});

View File

@ -0,0 +1,11 @@
define(['app', 'Series/Details/SeasonCollection'], function (app) {
NzbDrone.Series.Details.SeasonModel = Backbone.Model.extend({
//Season Number
//Episodes
initialize: function(options) {
this.seasonNumber = options.seasonNumber;
this.episodes = options.episodes;
}
});
});

View File

@ -0,0 +1,4 @@
<div>
<div id="details"></div>
<div id="seasons"></div>
</div>

View File

@ -0,0 +1,19 @@
define(['app', 'Quality/QualityProfileCollection', 'Series/Details/SeasonCollectionView'], function (app, qualityProfileCollection) {
NzbDrone.Series.Details.SeriesDetailsView = Backbone.Marionette.CompositeView.extend({
itemView: NzbDrone.Series.Details.SeasonCollectionView,
itemViewContainer: '#seasons',
template: 'Series/Details/SeriesDetailsTemplate',
qualityProfileCollection: qualityProfileCollection,
initialize: function (options) {
this.collection = options.collection;
this.qualityProfileCollection.fetch();
},
onCompositeCollectionRendered: function()
{
var test = 1;
}
});
});

View File

@ -32,6 +32,7 @@ define('app', function () {
window.NzbDrone.Series = {}; window.NzbDrone.Series = {};
window.NzbDrone.Series.Edit = {}; window.NzbDrone.Series.Edit = {};
window.NzbDrone.Series.Delete = {}; window.NzbDrone.Series.Delete = {};
window.NzbDrone.Series.Details = {};
window.NzbDrone.AddSeries = {}; window.NzbDrone.AddSeries = {};
window.NzbDrone.AddSeries.New = {}; window.NzbDrone.AddSeries.New = {};
window.NzbDrone.AddSeries.Existing = {}; window.NzbDrone.AddSeries.Existing = {};

View File

@ -17,7 +17,7 @@ public interface IEpisodeService
Episode GetEpisode(int id); Episode GetEpisode(int id);
Episode GetEpisode(int seriesId, int seasonNumber, int episodeNumber); Episode GetEpisode(int seriesId, int seasonNumber, int episodeNumber);
Episode GetEpisode(int seriesId, DateTime date); Episode GetEpisode(int seriesId, DateTime date);
IList<Episode> GetEpisodeBySeries(int seriesId); List<Episode> GetEpisodeBySeries(int seriesId);
IList<Episode> GetEpisodesBySeason(int seriesId, int seasonNumber); IList<Episode> GetEpisodesBySeason(int seriesId, int seasonNumber);
IList<Episode> GetEpisodesByParseResult(EpisodeParseResult parseResult); IList<Episode> GetEpisodesByParseResult(EpisodeParseResult parseResult);
IList<Episode> EpisodesWithoutFiles(bool includeSpecials); IList<Episode> EpisodesWithoutFiles(bool includeSpecials);
@ -56,32 +56,32 @@ public void AddEpisode(Episode episode)
_episodeRepository.Insert(episode); _episodeRepository.Insert(episode);
} }
public virtual Episode GetEpisode(int id) public Episode GetEpisode(int id)
{ {
return _episodeRepository.Get(id); return _episodeRepository.Get(id);
} }
public virtual Episode GetEpisode(int seriesId, int seasonNumber, int episodeNumber) public Episode GetEpisode(int seriesId, int seasonNumber, int episodeNumber)
{ {
return _episodeRepository.Get(seriesId, seasonNumber, episodeNumber); return _episodeRepository.Get(seriesId, seasonNumber, episodeNumber);
} }
public virtual Episode GetEpisode(int seriesId, DateTime date) public Episode GetEpisode(int seriesId, DateTime date)
{ {
return _episodeRepository.Get(seriesId, date); return _episodeRepository.Get(seriesId, date);
} }
public virtual IList<Episode> GetEpisodeBySeries(int seriesId) public List<Episode> GetEpisodeBySeries(int seriesId)
{ {
return _episodeRepository.GetEpisodes(seriesId); return _episodeRepository.GetEpisodes(seriesId).ToList();
} }
public virtual IList<Episode> GetEpisodesBySeason(int seriesId, int seasonNumber) public IList<Episode> GetEpisodesBySeason(int seriesId, int seasonNumber)
{ {
return _episodeRepository.GetEpisodes(seriesId, seasonNumber); return _episodeRepository.GetEpisodes(seriesId, seasonNumber);
} }
public virtual IList<Episode> GetEpisodesByParseResult(EpisodeParseResult parseResult) public IList<Episode> GetEpisodesByParseResult(EpisodeParseResult parseResult)
{ {
var result = new List<Episode>(); var result = new List<Episode>();
@ -159,22 +159,22 @@ public virtual IList<Episode> GetEpisodesByParseResult(EpisodeParseResult parseR
return result; return result;
} }
public virtual IList<Episode> EpisodesWithoutFiles(bool includeSpecials) public IList<Episode> EpisodesWithoutFiles(bool includeSpecials)
{ {
return _episodeRepository.EpisodesWithoutFiles(includeSpecials); return _episodeRepository.EpisodesWithoutFiles(includeSpecials);
} }
public virtual IList<Episode> GetEpisodesByFileId(int episodeFileId) public IList<Episode> GetEpisodesByFileId(int episodeFileId)
{ {
return _episodeRepository.GetEpisodeByFileId(episodeFileId); return _episodeRepository.GetEpisodeByFileId(episodeFileId);
} }
public virtual IList<Episode> EpisodesWithFiles() public IList<Episode> EpisodesWithFiles()
{ {
return _episodeRepository.EpisodesWithFiles(); return _episodeRepository.EpisodesWithFiles();
} }
public virtual void RefreshEpisodeInfo(Series series) public void RefreshEpisodeInfo(Series series)
{ {
logger.Trace("Starting episode info refresh for series: {0}", series.Title.WithDefault(series.Id)); logger.Trace("Starting episode info refresh for series: {0}", series.Title.WithDefault(series.Id));
var successCount = 0; var successCount = 0;
@ -270,17 +270,17 @@ public virtual void RefreshEpisodeInfo(Series series)
DeleteEpisodesNotInTvdb(series, tvdbEpisodes); DeleteEpisodesNotInTvdb(series, tvdbEpisodes);
} }
public virtual void UpdateEpisode(Episode episode) public void UpdateEpisode(Episode episode)
{ {
_episodeRepository.Update(episode); _episodeRepository.Update(episode);
} }
public virtual IList<int> GetEpisodeNumbersBySeason(int seriesId, int seasonNumber) public IList<int> GetEpisodeNumbersBySeason(int seriesId, int seasonNumber)
{ {
return GetEpisodesBySeason(seriesId, seasonNumber).Select(c => c.Id).ToList(); return GetEpisodesBySeason(seriesId, seasonNumber).Select(c => c.Id).ToList();
} }
public virtual void SetEpisodeIgnore(int episodeId, bool isIgnored) public void SetEpisodeIgnore(int episodeId, bool isIgnored)
{ {
var episode = _episodeRepository.Get(episodeId); var episode = _episodeRepository.Get(episodeId);
_episodeRepository.SetIgnoreFlat(episode, isIgnored); _episodeRepository.SetIgnoreFlat(episode, isIgnored);
@ -288,7 +288,7 @@ public virtual void SetEpisodeIgnore(int episodeId, bool isIgnored)
logger.Info("Ignore flag for Episode:{0} was set to {1}", episodeId, isIgnored); logger.Info("Ignore flag for Episode:{0} was set to {1}", episodeId, isIgnored);
} }
public virtual bool IsFirstOrLastEpisodeOfSeason(int seriesId, int seasonNumber, int episodeNumber) public bool IsFirstOrLastEpisodeOfSeason(int seriesId, int seasonNumber, int episodeNumber)
{ {
var episodes = GetEpisodesBySeason(seriesId, seasonNumber).OrderBy(e => e.EpisodeNumber); var episodes = GetEpisodesBySeason(seriesId, seasonNumber).OrderBy(e => e.EpisodeNumber);
@ -316,7 +316,7 @@ private void DeleteEpisodesNotInTvdb(Series series, IEnumerable<Episode> tvdbEpi
logger.Trace("Deleted episodes that no longer exist in TVDB for {0}", series.Id); logger.Trace("Deleted episodes that no longer exist in TVDB for {0}", series.Id);
} }
public virtual void SetPostDownloadStatus(List<int> episodeIds, PostDownloadStatusType postDownloadStatus) public void SetPostDownloadStatus(List<int> episodeIds, PostDownloadStatusType postDownloadStatus)
{ {
if (episodeIds.Count == 0) throw new ArgumentException("episodeIds should contain one or more episode ids."); if (episodeIds.Count == 0) throw new ArgumentException("episodeIds should contain one or more episode ids.");
@ -332,12 +332,12 @@ public virtual void SetPostDownloadStatus(List<int> episodeIds, PostDownloadStat
logger.Trace("Updating PostDownloadStatus for {0} episode(s) to {1}", episodeIds.Count, postDownloadStatus); logger.Trace("Updating PostDownloadStatus for {0} episode(s) to {1}", episodeIds.Count, postDownloadStatus);
} }
public virtual void UpdateEpisodes(List<Episode> episodes) public void UpdateEpisodes(List<Episode> episodes)
{ {
_episodeRepository.UpdateMany(episodes); _episodeRepository.UpdateMany(episodes);
} }
public virtual Episode GetEpisodeBySceneNumbering(int seriesId, int seasonNumber, int episodeNumber) public Episode GetEpisodeBySceneNumbering(int seriesId, int seasonNumber, int episodeNumber)
{ {
return _episodeRepository.GetEpisodeBySceneNumbering(seriesId, seasonNumber, episodeNumber); return _episodeRepository.GetEpisodeBySceneNumbering(seriesId, seasonNumber, episodeNumber);
} }

View File

@ -53,7 +53,5 @@ public class Series : ModelBase
public int EpisodeFileCount { get; set; } public int EpisodeFileCount { get; set; }
public int SeasonCount { get; set; } public int SeasonCount { get; set; }
public DateTime? NextAiring { get; set; } public DateTime? NextAiring { get; set; }
public List<Episode> Episodes { get; set; }
} }
} }