From ea9fddd5ca9af8d11c3fd1a6b3e61745bc4bc9aa Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Mon, 4 Nov 2013 16:50:37 -0500 Subject: [PATCH] proxy remote images through the server when previewing --- MediaBrowser.Api/RemoteImageService.cs | 99 ++++++++++++++++++- .../TV/ManualFanartSeasonProvider.cs | 1 + .../TV/ManualFanartSeriesProvider.cs | 1 + .../TV/ManualTvdbEpisodeImageProvider.cs | 9 +- .../TV/ManualTvdbSeasonImageProvider.cs | 3 +- .../TV/ManualTvdbSeriesImageProvider.cs | 3 +- 6 files changed, 108 insertions(+), 8 deletions(-) diff --git a/MediaBrowser.Api/RemoteImageService.cs b/MediaBrowser.Api/RemoteImageService.cs index e64badd050..153b9c47c2 100644 --- a/MediaBrowser.Api/RemoteImageService.cs +++ b/MediaBrowser.Api/RemoteImageService.cs @@ -1,4 +1,11 @@ -using MediaBrowser.Controller.Dto; +using System; +using System.IO; +using MediaBrowser.Common.Configuration; +using MediaBrowser.Common.Extensions; +using MediaBrowser.Common.IO; +using MediaBrowser.Common.Net; +using MediaBrowser.Controller; +using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Providers; @@ -62,16 +69,31 @@ namespace MediaBrowser.Api public string ImageUrl { get; set; } } + [Route("/Images/Remote", "GET")] + [Api(Description = "Gets a remote image")] + public class GetRemoteImage + { + [ApiMember(Name = "Url", Description = "The image url", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")] + public string Url { get; set; } + } + public class RemoteImageService : BaseApiService { private readonly IProviderManager _providerManager; + private readonly IServerApplicationPaths _appPaths; + private readonly IHttpClient _httpClient; + private readonly IFileSystem _fileSystem; + private readonly IDtoService _dtoService; - public RemoteImageService(IProviderManager providerManager, IDtoService dtoService) + public RemoteImageService(IProviderManager providerManager, IDtoService dtoService, IServerApplicationPaths appPaths, IHttpClient httpClient, IFileSystem fileSystem) { _providerManager = providerManager; _dtoService = dtoService; + _appPaths = appPaths; + _httpClient = httpClient; + _fileSystem = fileSystem; } public object Get(GetRemoteImages request) @@ -128,5 +150,78 @@ namespace MediaBrowser.Api await item.RefreshMetadata(CancellationToken.None, forceSave: true, allowSlowProviders: false) .ConfigureAwait(false); } + + public object Get(GetRemoteImage request) + { + var task = GetRemoteImage(request); + + return task.Result; + } + + private async Task GetRemoteImage(GetRemoteImage request) + { + var urlHash = request.Url.GetMD5(); + var pointerCachePath = GetFullCachePath(urlHash.ToString()); + + string contentPath; + + try + { + using (var reader = new StreamReader(pointerCachePath)) + { + contentPath = await reader.ReadToEndAsync().ConfigureAwait(false); + } + + if (File.Exists(contentPath)) + { + return ToStaticFileResult(contentPath); + } + } + catch (FileNotFoundException) + { + // Means the file isn't cached yet + } + + await DownloadImage(request.Url, urlHash, pointerCachePath).ConfigureAwait(false); + + // Read the pointer file again + using (var reader = new StreamReader(pointerCachePath)) + { + contentPath = await reader.ReadToEndAsync().ConfigureAwait(false); + } + + return ToStaticFileResult(contentPath); + } + + private async Task DownloadImage(string url, Guid urlHash, string pointerCachePath) + { + var result = await _httpClient.GetResponse(new HttpRequestOptions + { + Url = url + + }).ConfigureAwait(false); + + var ext = result.ContentType.Split('/').Last(); + + var fullCachePath = GetFullCachePath(urlHash + "." + ext); + + using (var stream = result.Content) + { + using (var filestream = _fileSystem.GetFileStream(fullCachePath, FileMode.Create, FileAccess.Write, FileShare.Read, true)) + { + await stream.CopyToAsync(filestream).ConfigureAwait(false); + } + } + + using (var writer = new StreamWriter(pointerCachePath)) + { + await writer.WriteAsync(fullCachePath).ConfigureAwait(false); + } + } + + private string GetFullCachePath(string filename) + { + return Path.Combine(_appPaths.DownloadedImagesDataPath, filename.Substring(0, 1), filename); + } } } diff --git a/MediaBrowser.Providers/TV/ManualFanartSeasonProvider.cs b/MediaBrowser.Providers/TV/ManualFanartSeasonProvider.cs index 06115a6dee..f9b779011b 100644 --- a/MediaBrowser.Providers/TV/ManualFanartSeasonProvider.cs +++ b/MediaBrowser.Providers/TV/ManualFanartSeasonProvider.cs @@ -100,6 +100,7 @@ namespace MediaBrowser.Providers.TV return 0; }) .ThenByDescending(i => i.CommunityRating ?? 0) + .ThenByDescending(i => i.VoteCount ?? 0) .ToList(); return Task.FromResult>(list); diff --git a/MediaBrowser.Providers/TV/ManualFanartSeriesProvider.cs b/MediaBrowser.Providers/TV/ManualFanartSeriesProvider.cs index 718e7849e2..cb7a4efd11 100644 --- a/MediaBrowser.Providers/TV/ManualFanartSeriesProvider.cs +++ b/MediaBrowser.Providers/TV/ManualFanartSeriesProvider.cs @@ -97,6 +97,7 @@ namespace MediaBrowser.Providers.TV return 0; }) .ThenByDescending(i => i.CommunityRating ?? 0) + .ThenByDescending(i => i.VoteCount ?? 0) .ToList(); return Task.FromResult>(list); diff --git a/MediaBrowser.Providers/TV/ManualTvdbEpisodeImageProvider.cs b/MediaBrowser.Providers/TV/ManualTvdbEpisodeImageProvider.cs index 1b6d37639d..d63fb5091f 100644 --- a/MediaBrowser.Providers/TV/ManualTvdbEpisodeImageProvider.cs +++ b/MediaBrowser.Providers/TV/ManualTvdbEpisodeImageProvider.cs @@ -1,5 +1,4 @@ -using System.Globalization; -using MediaBrowser.Controller.Configuration; +using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Library; @@ -7,6 +6,7 @@ using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Providers; using System.Collections.Generic; +using System.Globalization; using System.IO; using System.Linq; using System.Text; @@ -28,7 +28,7 @@ namespace MediaBrowser.Providers.TV public string Name { - get { return "TvDb"; } + get { return "TheTVDB"; } } public bool Supports(BaseItem item) @@ -56,7 +56,8 @@ namespace MediaBrowser.Providers.TV var files = TvdbEpisodeProvider.Current.GetEpisodeXmlFiles(episode, seriesDataPath); - var result = files.Select(i => GetImageInfo(i, cancellationToken)).Where(i => i != null); + var result = files.Select(i => GetImageInfo(i, cancellationToken)) + .Where(i => i != null); return Task.FromResult(result); } diff --git a/MediaBrowser.Providers/TV/ManualTvdbSeasonImageProvider.cs b/MediaBrowser.Providers/TV/ManualTvdbSeasonImageProvider.cs index 9c4b31d096..3efd0a3e36 100644 --- a/MediaBrowser.Providers/TV/ManualTvdbSeasonImageProvider.cs +++ b/MediaBrowser.Providers/TV/ManualTvdbSeasonImageProvider.cs @@ -35,7 +35,7 @@ namespace MediaBrowser.Providers.TV public static string ProviderName { - get { return "TvDb"; } + get { return "TheTVDB"; } } public bool Supports(BaseItem item) @@ -147,6 +147,7 @@ namespace MediaBrowser.Providers.TV return 0; }) .ThenByDescending(i => i.CommunityRating ?? 0) + .ThenByDescending(i => i.VoteCount ?? 0) .ToList(); } diff --git a/MediaBrowser.Providers/TV/ManualTvdbSeriesImageProvider.cs b/MediaBrowser.Providers/TV/ManualTvdbSeriesImageProvider.cs index fa09681e79..5987215d1b 100644 --- a/MediaBrowser.Providers/TV/ManualTvdbSeriesImageProvider.cs +++ b/MediaBrowser.Providers/TV/ManualTvdbSeriesImageProvider.cs @@ -35,7 +35,7 @@ namespace MediaBrowser.Providers.TV public static string ProviderName { - get { return "TvDb"; } + get { return "TheTVDB"; } } public bool Supports(BaseItem item) @@ -145,6 +145,7 @@ namespace MediaBrowser.Providers.TV return 0; }) .ThenByDescending(i => i.CommunityRating ?? 0) + .ThenByDescending(i => i.VoteCount ?? 0) .ToList(); }