From 38589742e3a355c1705beb4236bcd338691b2395 Mon Sep 17 00:00:00 2001 From: Keivan Beigi Date: Wed, 12 Jun 2013 18:37:05 -0700 Subject: [PATCH] added caching breaker to media cover images. --- .../Frontend/IMapHttpRequestsToDisk.cs | 6 +-- NzbDrone.Api/Series/SeriesModule.cs | 27 +++++++++-- .../Reflection/ReflectionExtensions.cs | 3 +- .../MediaCoverServiceFixture.cs | 48 +++++++++++++++++-- .../NotificationTests/GrowlProviderTest.cs | 16 +------ .../NotificationTests/PlexProviderTest.cs | 4 +- .../NotificationTests/ProwlProviderTest.cs | 14 +----- NzbDrone.Core.Test/NzbDrone.Core.Test.csproj | 3 -- NzbDrone.Core/MediaCover/MediaCoverService.cs | 25 +++++++++- UI/Series/SeriesModel.js | 23 +++++++-- 10 files changed, 115 insertions(+), 54 deletions(-) diff --git a/NzbDrone.Api/Frontend/IMapHttpRequestsToDisk.cs b/NzbDrone.Api/Frontend/IMapHttpRequestsToDisk.cs index fc5811cdd..9abbc2e8c 100644 --- a/NzbDrone.Api/Frontend/IMapHttpRequestsToDisk.cs +++ b/NzbDrone.Api/Frontend/IMapHttpRequestsToDisk.cs @@ -1,8 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - + namespace NzbDrone.Api.Frontend { public interface IMapHttpRequestsToDisk diff --git a/NzbDrone.Api/Series/SeriesModule.cs b/NzbDrone.Api/Series/SeriesModule.cs index 75d43b0d5..217bd7e4e 100644 --- a/NzbDrone.Api/Series/SeriesModule.cs +++ b/NzbDrone.Api/Series/SeriesModule.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using FluentValidation; using Nancy; +using NzbDrone.Core.MediaCover; using NzbDrone.Core.SeriesStats; using NzbDrone.Core.Tv; using NzbDrone.Api.Validation; @@ -14,12 +15,14 @@ namespace NzbDrone.Api.Series { private readonly ISeriesService _seriesService; private readonly ISeriesStatisticsService _seriesStatisticsService; + private readonly IMapCoversToLocal _coverMapper; - public SeriesModule(ISeriesService seriesService, ISeriesStatisticsService seriesStatisticsService) + public SeriesModule(ISeriesService seriesService, ISeriesStatisticsService seriesStatisticsService, IMapCoversToLocal coverMapper) : base("/Series") { _seriesService = seriesService; _seriesStatisticsService = seriesStatisticsService; + _coverMapper = coverMapper; GetResourceAll = AllSeries; GetResourceById = GetSeries; @@ -51,9 +54,9 @@ namespace NzbDrone.Api.Series private List AllSeries() { var seriesStats = _seriesStatisticsService.SeriesStatistics(); - var seriesModels = ToListResource(_seriesService.GetAllSeries); + var seriesResources = ToListResource(_seriesService.GetAllSeries); - foreach (var s in seriesModels) + foreach (var s in seriesResources) { var stats = seriesStats.SingleOrDefault(ss => ss.SeriesId == s.Id); if (stats == null) continue; @@ -64,12 +67,18 @@ namespace NzbDrone.Api.Series s.NextAiring = stats.NextAiring; } - return seriesModels; + MapCoversToLocal(seriesResources.ToArray()); + + return seriesResources; } private SeriesResource GetSeries(int id) { - return ToResource(_seriesService.GetSeries, id); + var resource = ToResource(_seriesService.GetSeries, id); + + MapCoversToLocal(resource); + + return resource; } private SeriesResource AddSeries(SeriesResource seriesResource) @@ -92,6 +101,14 @@ namespace NzbDrone.Api.Series var deleteFiles = Convert.ToBoolean(Request.Headers["deleteFiles"].FirstOrDefault()); _seriesService.DeleteSeries(id, deleteFiles); } + + private void MapCoversToLocal(params SeriesResource[] series) + { + foreach (var seriesResource in series) + { + _coverMapper.ConvertToLocalUrls(seriesResource.Id, seriesResource.Images); + } + } } } diff --git a/NzbDrone.Common/Reflection/ReflectionExtensions.cs b/NzbDrone.Common/Reflection/ReflectionExtensions.cs index c04da73fc..98ff9ff12 100644 --- a/NzbDrone.Common/Reflection/ReflectionExtensions.cs +++ b/NzbDrone.Common/Reflection/ReflectionExtensions.cs @@ -33,8 +33,7 @@ namespace NzbDrone.Common.Reflection || type == typeof(string) || type == typeof(DateTime) || type == typeof(Version) - || type == typeof(Decimal) - || type.GetInterface("IEmbeddedDocument") != null; + || type == typeof(Decimal); } public static bool IsReadable(this PropertyInfo propertyInfo) diff --git a/NzbDrone.Core.Test/MediaCoverTests/MediaCoverServiceFixture.cs b/NzbDrone.Core.Test/MediaCoverTests/MediaCoverServiceFixture.cs index c60425fac..220ca98d5 100644 --- a/NzbDrone.Core.Test/MediaCoverTests/MediaCoverServiceFixture.cs +++ b/NzbDrone.Core.Test/MediaCoverTests/MediaCoverServiceFixture.cs @@ -1,7 +1,12 @@ -using NUnit.Framework; +using System; +using System.Collections.Generic; +using FluentAssertions; +using Moq; +using NUnit.Framework; using NzbDrone.Common; using NzbDrone.Core.MediaCover; using NzbDrone.Core.Test.Framework; +using System.Linq; namespace NzbDrone.Core.Test.MediaCoverTests { @@ -11,9 +16,44 @@ namespace NzbDrone.Core.Test.MediaCoverTests [SetUp] public void Setup() { - Mocker.SetConstant(new HttpProvider(new EnvironmentProvider())); - Mocker.SetConstant(new DiskProvider()); - Mocker.SetConstant(new EnvironmentProvider()); + //Mocker.SetConstant(new HttpProvider(new EnvironmentProvider())); + //Mocker.SetConstant(new DiskProvider()); + Mocker.SetConstant(new EnvironmentProvider()); + } + + [Test] + public void should_convert_trakts_urls_to_local() + { + var covers = new List + { + new MediaCover.MediaCover {CoverType = MediaCoverTypes.Banner} + }; + + Mocker.GetMock().Setup(c => c.GetLastFileWrite(It.IsAny())) + .Returns(new DateTime(1234)); + + Mocker.GetMock().Setup(c => c.FileExists(It.IsAny())) + .Returns(true); + + Subject.ConvertToLocalUrls(12, covers); + + + covers.Single().Url.Should().Be("/mediacover/12/banner.jpg?lastWrite=1234"); + } + + [Test] + public void should_convert_trakts_urls_to_local_without_time_if_file_doesnt_exist() + { + var covers = new List + { + new MediaCover.MediaCover {CoverType = MediaCoverTypes.Banner} + }; + + + Subject.ConvertToLocalUrls(12, covers); + + + covers.Single().Url.Should().Be("/mediacover/12/banner.jpg"); } } diff --git a/NzbDrone.Core.Test/NotificationTests/GrowlProviderTest.cs b/NzbDrone.Core.Test/NotificationTests/GrowlProviderTest.cs index f8e69d6c8..7e602d357 100644 --- a/NzbDrone.Core.Test/NotificationTests/GrowlProviderTest.cs +++ b/NzbDrone.Core.Test/NotificationTests/GrowlProviderTest.cs @@ -1,20 +1,8 @@ -using System; - -using FizzWare.NBuilder; -using FluentAssertions; -using Moq; -using NUnit.Framework; -using NzbDrone.Core.Model; -using NzbDrone.Core.Notifications; +using NUnit.Framework; using NzbDrone.Core.Notifications.Growl; -using NzbDrone.Core.Providers; - using NzbDrone.Core.Test.Framework; -using NzbDrone.Test.Common.AutoMoq; - - -namespace NzbDrone.Core.Test.ProviderTests +namespace NzbDrone.Core.Test.NotificationTests { [Explicit] [TestFixture] diff --git a/NzbDrone.Core.Test/NotificationTests/PlexProviderTest.cs b/NzbDrone.Core.Test/NotificationTests/PlexProviderTest.cs index d933d71e7..fe2daa2a5 100644 --- a/NzbDrone.Core.Test/NotificationTests/PlexProviderTest.cs +++ b/NzbDrone.Core.Test/NotificationTests/PlexProviderTest.cs @@ -1,9 +1,7 @@ using System; using System.IO; using System.Linq; -using System.Net; using System.Text; -using FizzWare.NBuilder; using FluentAssertions; using Moq; using NUnit.Framework; @@ -11,7 +9,7 @@ using NzbDrone.Common; using NzbDrone.Core.Notifications.Plex; using NzbDrone.Core.Test.Framework; -namespace NzbDrone.Core.Test.ProviderTests +namespace NzbDrone.Core.Test.NotificationTests { [TestFixture] diff --git a/NzbDrone.Core.Test/NotificationTests/ProwlProviderTest.cs b/NzbDrone.Core.Test/NotificationTests/ProwlProviderTest.cs index 3fdd2d419..c9e79a5b1 100644 --- a/NzbDrone.Core.Test/NotificationTests/ProwlProviderTest.cs +++ b/NzbDrone.Core.Test/NotificationTests/ProwlProviderTest.cs @@ -1,21 +1,11 @@ -using System; - -using FizzWare.NBuilder; -using FluentAssertions; -using Moq; +using FluentAssertions; using NUnit.Framework; -using NzbDrone.Core.Model; using NzbDrone.Core.Notifications.Prowl; -using NzbDrone.Core.Providers; - using NzbDrone.Core.Test.Framework; using NzbDrone.Test.Common; -using NzbDrone.Test.Common.AutoMoq; using Prowlin; - - -namespace NzbDrone.Core.Test.ProviderTests +namespace NzbDrone.Core.Test.NotificationTests { [Explicit] [TestFixture] diff --git a/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj b/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj index bd60a304b..ac25a5495 100644 --- a/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj +++ b/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj @@ -150,12 +150,10 @@ - - @@ -198,7 +196,6 @@ - diff --git a/NzbDrone.Core/MediaCover/MediaCoverService.cs b/NzbDrone.Core/MediaCover/MediaCoverService.cs index 127f8a42f..80017f1f6 100644 --- a/NzbDrone.Core/MediaCover/MediaCoverService.cs +++ b/NzbDrone.Core/MediaCover/MediaCoverService.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.IO; using NLog; using NzbDrone.Common; @@ -10,7 +11,8 @@ namespace NzbDrone.Core.MediaCover { public class MediaCoverService : IHandleAsync, - IHandleAsync + IHandleAsync, + IMapCoversToLocal { private readonly IHttpProvider _httpProvider; private readonly IDiskProvider _diskProvider; @@ -80,5 +82,26 @@ namespace NzbDrone.Core.MediaCover { return Path.Combine(_coverRootFolder, seriesId.ToString()); } + + public void ConvertToLocalUrls(int seriesId, IEnumerable covers) + { + foreach (var mediaCover in covers) + { + var filePath = GetCoverPath(seriesId, mediaCover.CoverType); + + mediaCover.Url = @"/mediacover/" + seriesId + "/" + mediaCover.CoverType.ToString().ToLower() + ".jpg"; + + if (_diskProvider.FileExists(filePath)) + { + var lastWrite = _diskProvider.GetLastFileWrite(filePath); + mediaCover.Url += "?lastWrite=" + lastWrite.Ticks; + } + } + } + } + + public interface IMapCoversToLocal + { + void ConvertToLocalUrls(int seriesId, IEnumerable covers); } } diff --git a/UI/Series/SeriesModel.js b/UI/Series/SeriesModel.js index 88f4a7f77..df5aa84a3 100644 --- a/UI/Series/SeriesModel.js +++ b/UI/Series/SeriesModel.js @@ -17,14 +17,27 @@ define(['app', 'Quality/QualityProfileCollection'], function (app, qualityProfil return percent; }, - banner : function () { - return "/mediacover/" + this.get('id') + "/banner.jpg"; - }, poster : function () { - return "/mediacover/" + this.get('id') + "/poster.jpg"; + var poster = _.find(this.get('images'), function (image) { + return image.coverType === 'poster'; + }); + + if (poster) { + return poster.url; + } + + return undefined; }, fanArt : function () { - return "/mediacover/" + this.get('id') + "/fanart.jpg"; + var poster = _.find(this.get('images'), function (image) { + return image.coverType === 3; + }); + + if (poster) { + return poster.url; + } + + return undefined; }, traktUrl : function () { return "http://trakt.tv/show/" + this.get('titleSlug');