diff --git a/NzbDrone.Api/AutomapperBootstraper.cs b/NzbDrone.Api/AutomapperBootstraper.cs index 336ade642..616a5ae77 100644 --- a/NzbDrone.Api/AutomapperBootstraper.cs +++ b/NzbDrone.Api/AutomapperBootstraper.cs @@ -39,7 +39,8 @@ namespace NzbDrone.Api .ForMember(dest => dest.Id, opt => opt.MapFrom(src => src.Id)) .ForMember(dest => dest.CustomStartDate, opt => opt.ResolveUsing().FromMember(src => src.CustomStartDate)) .ForMember(dest => dest.BacklogSetting, opt => opt.MapFrom(src => (Int32)src.BacklogSetting)) - .ForMember(dest => dest.NextAiring, opt => opt.ResolveUsing()); + .ForMember(dest => dest.NextAiring, opt => opt.ResolveUsing()) + .ForMember(dest => dest.QualityProfileName, opt => opt.MapFrom(src => src.QualityProfile.Name)); //Calendar Mapper.CreateMap() diff --git a/NzbDrone.Api/Calendar/CalendarModule.cs b/NzbDrone.Api/Calendar/CalendarModule.cs index 6d14ab384..68fb8e280 100644 --- a/NzbDrone.Api/Calendar/CalendarModule.cs +++ b/NzbDrone.Api/Calendar/CalendarModule.cs @@ -22,7 +22,7 @@ namespace NzbDrone.Api.Calendar private Response GetEpisodesBetweenStartAndEndDate() { - var start = DateTime.Today; + var start = DateTime.Today.AddDays(-1); var end = DateTime.Today.AddDays(7); var queryStart = Request.Query.Start; diff --git a/NzbDrone.Api/Series/SeriesResource.cs b/NzbDrone.Api/Series/SeriesResource.cs index f4f28103f..84eca11ea 100644 --- a/NzbDrone.Api/Series/SeriesResource.cs +++ b/NzbDrone.Api/Series/SeriesResource.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Text; using NzbDrone.Api.QualityProfiles; using NzbDrone.Core.Model; +using NzbDrone.Core.Qualities; namespace NzbDrone.Api.Series { diff --git a/NzbDrone.Backbone/Calendar/CalendarCollectionView.js b/NzbDrone.Backbone/Calendar/CalendarCollectionView.js index 053829baf..0a86ab9c1 100644 --- a/NzbDrone.Backbone/Calendar/CalendarCollectionView.js +++ b/NzbDrone.Backbone/Calendar/CalendarCollectionView.js @@ -20,6 +20,7 @@ define(['app', 'Calendar/CalendarItemView'], function (app) { allDayDefault: false, ignoreTimezone: false, weekMode: 'variable', + timeFormat: 'h(:mm)tt', header: { left: 'prev,next today', center: 'title', @@ -31,6 +32,9 @@ define(['app', 'Calendar/CalendarItemView'], function (app) { }, events: this.getEvents, eventRender: function (event, element) { + $(element).addClass(event.statusLevel); + $(element).children('.fc-event-inner').addClass(event.statusLevel); + element.popover({ title: '{seriesTitle} - {season}x{episode} - {episodeTitle}'.assign({ seriesTitle: event.seriesTitle, diff --git a/NzbDrone.Backbone/Calendar/CalendarItemTemplate.html b/NzbDrone.Backbone/Calendar/CalendarItemTemplate.html index 0a64d1e30..4182e5047 100644 --- a/NzbDrone.Backbone/Calendar/CalendarItemTemplate.html +++ b/NzbDrone.Backbone/Calendar/CalendarItemTemplate.html @@ -3,4 +3,4 @@

{{month}}

{{seriesTitle}}

-

{{startTime}}{{seasonNumber}}x{{paddedEpisodeNumber}}
{{episodeTitle}}

+

{{startTime}} {{bestDateString}}{{seasonNumber}}x{{paddedEpisodeNumber}}
{{episodeTitle}}

diff --git a/NzbDrone.Backbone/Calendar/CalendarModel.js b/NzbDrone.Backbone/Calendar/CalendarModel.js index 4cd80b5c6..bc591901e 100644 --- a/NzbDrone.Backbone/Calendar/CalendarModel.js +++ b/NzbDrone.Backbone/Calendar/CalendarModel.js @@ -33,11 +33,16 @@ if (currentTime.isBetween(start, end)) return 'warning'; - if (status === 'Missing') return 'danger'; + if (start.isBefore(currentTime) || status === 'Missing') + return 'danger'; + if (status === 'Ready') return 'success'; - return 'info'; - } + return 'primary'; + }, + bestDateString: function () { + return bestDateString(this.get('start')); + }, }, defaults: { status: 0 diff --git a/NzbDrone.Backbone/Content/theme.css b/NzbDrone.Backbone/Content/theme.css index 40fbb74ea..d24d7d099 100644 --- a/NzbDrone.Backbone/Content/theme.css +++ b/NzbDrone.Backbone/Content/theme.css @@ -824,12 +824,51 @@ ul.stat-list { border-color: #EEE; } -#calendar .fc-event-skin { - background-color: #007ccd; - border: 1px solid #007ccd; - border-radius: 4px; - text-align: center; -} + #calendar .fc-event-skin { + background-color: #007ccd; + border: 1px solid #007ccd; + border-radius: 4px; + text-align: center; + } + + #calendar .success { + border-color: #4cb158; + background-color: #4cb158; + } + + #calendar .danger { + border-color: #ea494a; + background-color: #ea494a; + } + + #calendar .info { + border-color: #14b8d4; + background-color: #14b8d4; + } + + #calendar .primary { + border-color: #007ccd; + background-color: #007ccd; + } + + #calendar .warning { + border-color: #ffa93c; + background-color: #ffa93c; + } + + #calendar .purple { + border-color: #7932ea; + background-color: #7932ea; + } + + #calendar .inverse { + border-color: #333; + background-color: #333; + } + + #calendar .fc-state-highlight { + background: rgba(20, 184, 212, .2); + } /* ============== tags ============== */ .tag { diff --git a/NzbDrone.Backbone/Controller.js b/NzbDrone.Backbone/Controller.js index 814c25e6a..cdd6f3901 100644 --- a/NzbDrone.Backbone/Controller.js +++ b/NzbDrone.Backbone/Controller.js @@ -1,6 +1,6 @@ define(['app', 'Shared/ModalRegion', 'AddSeries/AddSeriesLayout', 'Series/SeriesCollectionView', 'Upcoming/UpcomingCollectionView', 'Calendar/CalendarCollectionView', 'Shared/NotificationView', - 'Shared/NotFoundView', 'MainMenuView'], function (app, modalRegion) { + 'Shared/NotFoundView', 'MainMenuView', 'HeaderView'], function (app, modalRegion) { var controller = Backbone.Marionette.Controller.extend({ diff --git a/NzbDrone.Backbone/HeaderView.js b/NzbDrone.Backbone/HeaderView.js new file mode 100644 index 000000000..ed7683f01 --- /dev/null +++ b/NzbDrone.Backbone/HeaderView.js @@ -0,0 +1,31 @@ +define(['app'], function () { + NzbDrone.HeaderView = Backbone.Marionette.ItemView.extend({ + events: { + 'click #logo': 'onClick' + }, + + onClick: function (event) { + + event.preventDefault(); + + var target = $(event.target); + var href = undefined; + + //look down for + href = event.target.getAttribute('href'); + + if (href && href.startsWith('http')) { + window.location.href = href; + } else { + NzbDrone.Router.navigate(href, { trigger: true, replace: true }); + } + + }, + + initialize: function () { + this.setElement($('#in-nav')); + } + }); + + return new NzbDrone.HeaderView(); +}); diff --git a/NzbDrone.Backbone/Index.html b/NzbDrone.Backbone/Index.html index 439262bc0..c5b87e15c 100644 --- a/NzbDrone.Backbone/Index.html +++ b/NzbDrone.Backbone/Index.html @@ -34,9 +34,11 @@ @@ -109,6 +111,7 @@ + diff --git a/NzbDrone.Backbone/Mixins/spoon.js b/NzbDrone.Backbone/Mixins/spoon.js new file mode 100644 index 000000000..12be1f1c0 --- /dev/null +++ b/NzbDrone.Backbone/Mixins/spoon.js @@ -0,0 +1,12 @@ +function bestDateString(sourceDate){ + if (!sourceDate) return ''; + + var date = Date.create(sourceDate); + + if (date.isYesterday()) return 'Yesterday'; + if (date.isToday()) return 'Today'; + if (date.isTomorrow()) return 'Tomorrow'; + if (date.isBefore(Date.create().addDays(7))) return date.format('{Weekday}'); + + return date.format('{MM}/{dd}/{yyyy}'); +} \ No newline at end of file diff --git a/NzbDrone.Backbone/Series/SeriesModel.js b/NzbDrone.Backbone/Series/SeriesModel.js index 87537a67b..0ada8e38f 100644 --- a/NzbDrone.Backbone/Series/SeriesModel.js +++ b/NzbDrone.Backbone/Series/SeriesModel.js @@ -3,18 +3,7 @@ mutators: { bestDateString: function () { - var dateSource = this.get('nextAiring'); - - if (!dateSource) return ''; - - var date = Date.create(dateSource); - - if (date.isYesterday()) return 'Yesterday'; - if (date.isToday()) return 'Today'; - if (date.isTomorrow()) return 'Tomorrow'; - if (date.isBefore(Date.create().addDays(7))) return date.format('{Weekday}'); - - return date.format('{MM}/{dd}/{yyyy}'); + return bestDateString(this.get('nextAiring')); }, percentOfEpisodes: function () { diff --git a/NzbDrone.Core/Tv/EpisodeService.cs b/NzbDrone.Core/Tv/EpisodeService.cs index 268a5257a..b4073356d 100644 --- a/NzbDrone.Core/Tv/EpisodeService.cs +++ b/NzbDrone.Core/Tv/EpisodeService.cs @@ -182,7 +182,6 @@ namespace NzbDrone.Core.Tv var tvdbEpisodes = _tvDbProvider.GetEpisodes(series.TvDbId); - var seriesEpisodes = GetEpisodeBySeries(series.Id); var updateList = new List(); var newList = new List(); @@ -237,10 +236,15 @@ namespace NzbDrone.Core.Tv episodeToUpdate.SeasonNumber = episode.SeasonNumber; episodeToUpdate.AbsoluteEpisodeNumber = episode.AbsoluteEpisodeNumber; episodeToUpdate.Title = episode.Title; - episodeToUpdate.Overview = episode.Overview; episodeToUpdate.AirDate = episode.AirDate; + if(!String.IsNullOrWhiteSpace(series.AirTime) && episodeToUpdate.AirDate.HasValue) + { + episodeToUpdate.AirDate = episodeToUpdate.AirDate.Value.Add(Convert.ToDateTime(series.AirTime).TimeOfDay) + .AddHours(series.UtcOffset * -1); + } + successCount++; } catch (Exception e) diff --git a/NzbDrone.Core/Tv/Series.cs b/NzbDrone.Core/Tv/Series.cs index d657fcb65..38d3b06d4 100644 --- a/NzbDrone.Core/Tv/Series.cs +++ b/NzbDrone.Core/Tv/Series.cs @@ -1,4 +1,5 @@ -using System.Linq; +using System.Collections.Generic; +using System.Linq; using System; using NzbDrone.Core.Datastore; using NzbDrone.Core.Model; @@ -8,8 +9,6 @@ using Sqo.Attributes; namespace NzbDrone.Core.Tv { - - public enum SeriesType { Standard =0, @@ -17,71 +16,44 @@ namespace NzbDrone.Core.Tv Anime = 2, } - public class Series : ModelBase { public int TvDbId { get; set; } - public string Title { get; set; } - public string CleanTitle { get; set; } - public string Status { get; set; } [Text] public string Overview { get; set; } - //public DayOfWeek? AirsDayOfWeek { get; set; } - public String AirTime { get; set; } - public string Language { get; set; } - public string Path { get; set; } - public bool Monitored { get; set; } - - public virtual int QualityProfileId { get; set; } - + public int QualityProfileId { get; set; } public bool SeasonFolder { get; set; } - public DateTime? LastInfoSync { get; set; } - public DateTime? LastDiskSync { get; set; } - public int Runtime { get; set; } - public string BannerUrl { get; set; } - public SeriesType SeriesType { get; set; } - public BacklogSettingType BacklogSetting { get; set; } - public string Network { get; set; } - public DateTime? CustomStartDate { get; set; } - public bool UseSceneNumbering { get; set; } - public int TvRageId { get; set; } - public string TvRageTitle { get; set; } //Todo: This should be a double since there are timezones that aren't on a full hour offset public int UtcOffset { get; set; } public DateTime? FirstAired { get; set; } - - public bool Hidden { get; set; } - public QualityProfile QualityProfile { get; set; } - public int EpisodeCount { get; set; } - public int EpisodeFileCount { get; set; } - public int SeasonCount { get; set; } - public DateTime? NextAiring { get; set; } + + public List Episodes { get; set; } } } \ No newline at end of file diff --git a/NzbDrone.Core/Tv/SeriesService.cs b/NzbDrone.Core/Tv/SeriesService.cs index 3df08a61e..09d7e906d 100644 --- a/NzbDrone.Core/Tv/SeriesService.cs +++ b/NzbDrone.Core/Tv/SeriesService.cs @@ -10,6 +10,7 @@ using NzbDrone.Core.Datastore; using NzbDrone.Core.Model; using NzbDrone.Core.Providers; using NzbDrone.Core.Providers.Core; +using NzbDrone.Core.Qualities; using NzbDrone.Core.Tv.Events; namespace NzbDrone.Core.Tv @@ -31,6 +32,7 @@ namespace NzbDrone.Core.Tv private readonly MetadataProvider _metadataProvider; private readonly TvRageMappingProvider _tvRageMappingProvider; private readonly IEventAggregator _eventAggregator; + private readonly IQualityProfileService _qualityProfileService; private static readonly Logger logger = LogManager.GetCurrentClassLogger(); @@ -38,7 +40,7 @@ namespace NzbDrone.Core.Tv public SeriesService(ISeriesRepository seriesRepository, IConfigService configServiceService, TvDbProvider tvDbProviderProvider, SceneMappingProvider sceneNameMappingProvider, MetadataProvider metadataProvider, - TvRageMappingProvider tvRageMappingProvider, IEventAggregator eventAggregator) + TvRageMappingProvider tvRageMappingProvider, IEventAggregator eventAggregator, IQualityProfileService qualityProfileService) { _seriesRepository = seriesRepository; _configService = configServiceService; @@ -47,6 +49,7 @@ namespace NzbDrone.Core.Tv _metadataProvider = metadataProvider; _tvRageMappingProvider = tvRageMappingProvider; _eventAggregator = eventAggregator; + _qualityProfileService = qualityProfileService; } @@ -63,7 +66,6 @@ namespace NzbDrone.Core.Tv series.Title = tvDbSeries.SeriesName; series.AirTime = CleanAirsTime(tvDbSeries.AirsTime); - //series.AirsDayOfWeek = tvDbSeries.AirsDayOfWeek; series.Overview = tvDbSeries.Overview; series.Status = tvDbSeries.Status; series.Language = tvDbSeries.Language != null ? tvDbSeries.Language.Abbriviation : string.Empty; @@ -114,8 +116,7 @@ namespace NzbDrone.Core.Tv logger.Info("Adding Series [{0}] Path: [{1}]", tvDbSeriesId, path); Ensure.That(() => tvDbSeriesId).IsGreaterThan(0); - //Todo: We can't validate the title if we're passing in an empty string - //Ensure.That(() => title).IsNotNullOrWhiteSpace(); + Ensure.That(() => title).IsNotNullOrWhiteSpace(); Ensure.That(() => path).IsNotNullOrWhiteSpace(); var repoSeries = new Series(); @@ -127,6 +128,7 @@ namespace NzbDrone.Core.Tv if (qualityProfileId == 0) repoSeries.QualityProfileId = _configService.DefaultQualityProfile; + repoSeries.QualityProfile = _qualityProfileService.Get(repoSeries.QualityProfileId); repoSeries.SeasonFolder = _configService.UseSeasonFolder; repoSeries.BacklogSetting = BacklogSettingType.Inherit; @@ -138,7 +140,6 @@ namespace NzbDrone.Core.Tv _eventAggregator.Publish(new SeriesAddedEvent(repoSeries)); } - public void UpdateFromSeriesEditor(IList editedSeries) { var allSeries = _seriesRepository.All();