From e2d17ac1096926aae75a4aa23f0e3896d7231c28 Mon Sep 17 00:00:00 2001 From: "kay.one" Date: Tue, 28 May 2013 21:10:23 -0700 Subject: [PATCH] covers are re-downloaded if remote size is different than local size. --- NzbDrone.Common/HttpProvider.cs | 24 ++++++- NzbDrone.Common/IDiskProvider.cs | 4 +- .../CoverExistsSpecificationFixture.cs | 72 +++++++++++++++++++ NzbDrone.Core.Test/NzbDrone.Core.Test.csproj | 1 + .../ImportFileFixture.cs | 2 +- .../CoverAlreadyExistsSpecification.cs | 47 ++++++++++++ NzbDrone.Core/MediaCover/MediaCoverService.cs | 7 +- NzbDrone.Core/MediaFiles/DiskScanService.cs | 2 +- NzbDrone.Core/MetadataSource/TraktProxy.cs | 2 +- NzbDrone.Core/NzbDrone.Core.csproj | 1 + 10 files changed, 154 insertions(+), 8 deletions(-) create mode 100644 NzbDrone.Core.Test/MediaCoverTests/CoverExistsSpecificationFixture.cs create mode 100644 NzbDrone.Core/MediaCover/CoverAlreadyExistsSpecification.cs diff --git a/NzbDrone.Common/HttpProvider.cs b/NzbDrone.Common/HttpProvider.cs index 65e7f4999..0897ca079 100644 --- a/NzbDrone.Common/HttpProvider.cs +++ b/NzbDrone.Common/HttpProvider.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Net; @@ -12,6 +13,8 @@ namespace NzbDrone.Common string DownloadString(string address); string DownloadString(string address, string username, string password); string DownloadString(string address, ICredentials identity); + Dictionary DownloadHeader(string url); + Stream DownloadStream(string url, NetworkCredential credential = null); void DownloadFile(string url, string fileName); string PostCommand(string address, string username, string password, string command); @@ -19,6 +22,9 @@ namespace NzbDrone.Common public class HttpProvider : IHttpProvider { + + public const string ContentLenghtHeader = "Content-Length"; + private readonly IEnvironmentProvider _environmentProvider; private static readonly Logger logger = LogManager.GetCurrentClassLogger(); private readonly string _userAgent; @@ -54,6 +60,22 @@ namespace NzbDrone.Common } } + public Dictionary DownloadHeader(string url) + { + var headers = new Dictionary(); + var request = WebRequest.Create(url); + request.Method = "HEAD"; + + var response = request.GetResponse(); + + foreach (var key in headers.Keys) + { + headers.Add(key, response.Headers[key]); + } + + return headers; + } + public Stream DownloadStream(string url, NetworkCredential credential = null) { var request = (HttpWebRequest)WebRequest.Create(url); @@ -70,7 +92,7 @@ namespace NzbDrone.Common try { var fileInfo = new FileInfo(fileName); - if (!fileInfo.Directory.Exists) + if (fileInfo.Directory != null && !fileInfo.Directory.Exists) { fileInfo.Directory.Create(); } diff --git a/NzbDrone.Common/IDiskProvider.cs b/NzbDrone.Common/IDiskProvider.cs index ea17dbfac..ae3a2db60 100644 --- a/NzbDrone.Common/IDiskProvider.cs +++ b/NzbDrone.Common/IDiskProvider.cs @@ -18,7 +18,7 @@ namespace NzbDrone.Common string[] GetDirectories(string path); string[] GetFiles(string path, SearchOption searchOption); long GetDirectorySize(string path); - long GetSize(string path); + long GetFileSize(string path); String CreateFolder(string path); void CopyDirectory(string source, string target); void MoveDirectory(string source, string destination); @@ -131,7 +131,7 @@ namespace NzbDrone.Common return GetFiles(path, SearchOption.AllDirectories).Sum(e => new FileInfo(e).Length); } - public virtual long GetSize(string path) + public virtual long GetFileSize(string path) { Ensure.That(() => path).IsValidPath(); diff --git a/NzbDrone.Core.Test/MediaCoverTests/CoverExistsSpecificationFixture.cs b/NzbDrone.Core.Test/MediaCoverTests/CoverExistsSpecificationFixture.cs new file mode 100644 index 000000000..da0fa63f8 --- /dev/null +++ b/NzbDrone.Core.Test/MediaCoverTests/CoverExistsSpecificationFixture.cs @@ -0,0 +1,72 @@ +using System.Collections.Generic; +using FluentAssertions; +using Moq; +using NUnit.Framework; +using NzbDrone.Common; +using NzbDrone.Core.MediaCover; +using NzbDrone.Core.Test.Framework; + +namespace NzbDrone.Core.Test.MediaCoverTests +{ + [TestFixture] + public class CoverAlreadyExistsSpecificationFixture : CoreTest + { + private Dictionary _headers; + + [SetUp] + public void Setup() + { + _headers = new Dictionary(); + Mocker.GetMock().Setup(c => c.GetFileSize(It.IsAny())).Returns(100); + Mocker.GetMock().Setup(c => c.DownloadHeader(It.IsAny())).Returns(_headers); + + } + + + private void GivenFileExistsOnDisk() + { + Mocker.GetMock().Setup(c => c.FileExists(It.IsAny())).Returns(true); + } + + + private void GivenExistingFileSize(long bytes) + { + GivenFileExistsOnDisk(); + Mocker.GetMock().Setup(c => c.GetFileSize(It.IsAny())).Returns(bytes); + + } + + + [Test] + public void should_return_false_if_file_not_exists() + { + Subject.AlreadyExists("http://url", "c:\\file.exe").Should().BeFalse(); + } + + [Test] + public void should_return_false_if_file_exists_but_diffrent_size() + { + GivenExistingFileSize(100); + _headers.Add(HttpProvider.ContentLenghtHeader, "200"); + + Subject.AlreadyExists("http://url", "c:\\file.exe").Should().BeFalse(); + } + + + [Test] + public void should_return_ture_if_file_exists_and_same_size() + { + GivenExistingFileSize(100); + _headers.Add(HttpProvider.ContentLenghtHeader, "100"); + + Subject.AlreadyExists("http://url", "c:\\file.exe").Should().BeTrue(); + } + + [Test] + public void should_return_true_if_there_is_no_size_header_and_file_exist() + { + GivenExistingFileSize(100); + Subject.AlreadyExists("http://url", "c:\\file.exe").Should().BeTrue(); + } + } +} \ No newline at end of file diff --git a/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj b/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj index 2c60baa70..d4a7c2088 100644 --- a/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj +++ b/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj @@ -142,6 +142,7 @@ + diff --git a/NzbDrone.Core.Test/ProviderTests/DiskScanProviderTests/ImportFileFixture.cs b/NzbDrone.Core.Test/ProviderTests/DiskScanProviderTests/ImportFileFixture.cs index e3c9f513d..d9b58696e 100644 --- a/NzbDrone.Core.Test/ProviderTests/DiskScanProviderTests/ImportFileFixture.cs +++ b/NzbDrone.Core.Test/ProviderTests/DiskScanProviderTests/ImportFileFixture.cs @@ -58,7 +58,7 @@ namespace NzbDrone.Core.Test.ProviderTests.DiskScanProviderTests _fileSize = size; Mocker.GetMock() - .Setup(d => d.GetSize(It.IsAny())) + .Setup(d => d.GetFileSize(It.IsAny())) .Returns(size); } diff --git a/NzbDrone.Core/MediaCover/CoverAlreadyExistsSpecification.cs b/NzbDrone.Core/MediaCover/CoverAlreadyExistsSpecification.cs new file mode 100644 index 000000000..df824fe61 --- /dev/null +++ b/NzbDrone.Core/MediaCover/CoverAlreadyExistsSpecification.cs @@ -0,0 +1,47 @@ +using NzbDrone.Common; + +namespace NzbDrone.Core.MediaCover +{ + public interface ICoverExistsSpecification + { + bool AlreadyExists(string url, string paht); + } + + public class CoverAlreadyExistsSpecification : ICoverExistsSpecification + { + private readonly IDiskProvider _diskProvider; + private readonly IHttpProvider _httpProvider; + + public CoverAlreadyExistsSpecification(IDiskProvider diskProvider, IHttpProvider httpProvider) + { + _diskProvider = diskProvider; + _httpProvider = httpProvider; + } + + public bool AlreadyExists(string url, string path) + { + if (!_diskProvider.FileExists(path)) + { + return false; + } + + var headers = _httpProvider.DownloadHeader(url); + + string sizeString = null; + + if (headers.TryGetValue(HttpProvider.ContentLenghtHeader, out sizeString)) + { + int size; + int.TryParse(sizeString, out size); + var fileSize = _diskProvider.GetFileSize(path); + + if (fileSize != size) + { + return false; + } + } + + return true; + } + } +} \ No newline at end of file diff --git a/NzbDrone.Core/MediaCover/MediaCoverService.cs b/NzbDrone.Core/MediaCover/MediaCoverService.cs index 7fe14893c..a212194d2 100644 --- a/NzbDrone.Core/MediaCover/MediaCoverService.cs +++ b/NzbDrone.Core/MediaCover/MediaCoverService.cs @@ -14,14 +14,17 @@ namespace NzbDrone.Core.MediaCover { private readonly IHttpProvider _httpProvider; private readonly IDiskProvider _diskProvider; + private readonly ICoverExistsSpecification _coverExistsSpecification; private readonly Logger _logger; private readonly string _coverRootFolder; - public MediaCoverService(IHttpProvider httpProvider, IDiskProvider diskProvider, IEnvironmentProvider environmentProvider, Logger logger) + public MediaCoverService(IHttpProvider httpProvider, IDiskProvider diskProvider, IEnvironmentProvider environmentProvider, + ICoverExistsSpecification coverExistsSpecification, Logger logger) { _httpProvider = httpProvider; _diskProvider = diskProvider; + _coverExistsSpecification = coverExistsSpecification; _logger = logger; _coverRootFolder = environmentProvider.GetMediaCoverPath(); @@ -37,7 +40,7 @@ namespace NzbDrone.Core.MediaCover foreach (var cover in series.Images) { var fileName = GetCoverPath(series.Id, cover.CoverType); - if (!_diskProvider.FileExists(fileName)) + if (!_coverExistsSpecification.AlreadyExists(cover.Url, fileName)) { DownloadCover(series, cover); } diff --git a/NzbDrone.Core/MediaFiles/DiskScanService.cs b/NzbDrone.Core/MediaFiles/DiskScanService.cs index d876ac723..815c2cb44 100644 --- a/NzbDrone.Core/MediaFiles/DiskScanService.cs +++ b/NzbDrone.Core/MediaFiles/DiskScanService.cs @@ -86,7 +86,7 @@ namespace NzbDrone.Core.MediaFiles return null; } - var size = _diskProvider.GetSize(filePath); + var size = _diskProvider.GetFileSize(filePath); if (series.SeriesType == SeriesTypes.Daily || parsedEpisode.SeasonNumber > 0) { diff --git a/NzbDrone.Core/MetadataSource/TraktProxy.cs b/NzbDrone.Core/MetadataSource/TraktProxy.cs index b90de4fb2..b017126b1 100644 --- a/NzbDrone.Core/MetadataSource/TraktProxy.cs +++ b/NzbDrone.Core/MetadataSource/TraktProxy.cs @@ -87,7 +87,7 @@ namespace NzbDrone.Core.MetadataSource var extension = Path.GetExtension(posterUrl); var withoutExtension = posterUrl.Substring(0, posterUrl.Length - extension.Length); - return withoutExtension + "-138" + extension; + return withoutExtension + "-300" + extension; } private static SeriesStatusType GetSeriesStatus(string status) diff --git a/NzbDrone.Core/NzbDrone.Core.csproj b/NzbDrone.Core/NzbDrone.Core.csproj index 43085f269..818b18aa7 100644 --- a/NzbDrone.Core/NzbDrone.Core.csproj +++ b/NzbDrone.Core/NzbDrone.Core.csproj @@ -249,6 +249,7 @@ +