Fixed: Posters not always showing when searching for new shows
This commit is contained in:
parent
d8446c2d5a
commit
10dc884fa8
|
@ -0,0 +1,66 @@
|
||||||
|
using NzbDrone.Common.Cache;
|
||||||
|
using NzbDrone.Common.Http;
|
||||||
|
using NzbDrone.Core.Configuration;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.MediaCover
|
||||||
|
{
|
||||||
|
public interface IMediaCoverProxy
|
||||||
|
{
|
||||||
|
string RegisterUrl(string url);
|
||||||
|
|
||||||
|
string GetUrl(string hash);
|
||||||
|
byte[] GetImage(string hash);
|
||||||
|
}
|
||||||
|
public class MediaCoverProxy : IMediaCoverProxy
|
||||||
|
{
|
||||||
|
private readonly IHttpClient _httpClient;
|
||||||
|
private readonly IConfigFileProvider _configFileProvider;
|
||||||
|
private readonly ICached<string> _cache;
|
||||||
|
|
||||||
|
public MediaCoverProxy(IHttpClient httpClient, IConfigFileProvider configFileProvider, ICacheManager cacheManager)
|
||||||
|
{
|
||||||
|
_httpClient = httpClient;
|
||||||
|
_configFileProvider = configFileProvider;
|
||||||
|
_cache = cacheManager.GetCache<string>(GetType());
|
||||||
|
}
|
||||||
|
|
||||||
|
public string RegisterUrl(string url)
|
||||||
|
{
|
||||||
|
var hash = url.SHA256Hash();
|
||||||
|
|
||||||
|
_cache.Set(hash, url, TimeSpan.FromHours(24));
|
||||||
|
|
||||||
|
_cache.ClearExpired();
|
||||||
|
|
||||||
|
var fileName = Path.GetFileName(url);
|
||||||
|
return _configFileProvider.UrlBase + @"/MediaCoverProxy/" + hash + "/" + fileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetUrl(string hash)
|
||||||
|
{
|
||||||
|
var result = _cache.Find(hash);
|
||||||
|
|
||||||
|
if (result == null)
|
||||||
|
{
|
||||||
|
throw new KeyNotFoundException("Url no longer in cache");
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] GetImage(string hash)
|
||||||
|
{
|
||||||
|
var url = GetUrl(hash);
|
||||||
|
|
||||||
|
var request = new HttpRequest(url);
|
||||||
|
|
||||||
|
return _httpClient.Get(request).ResponseData;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -26,6 +26,7 @@ namespace NzbDrone.Core.MediaCover
|
||||||
IHandleAsync<SeriesDeletedEvent>,
|
IHandleAsync<SeriesDeletedEvent>,
|
||||||
IMapCoversToLocal
|
IMapCoversToLocal
|
||||||
{
|
{
|
||||||
|
private readonly IMediaCoverProxy _mediaCoverProxy;
|
||||||
private readonly IImageResizer _resizer;
|
private readonly IImageResizer _resizer;
|
||||||
private readonly IHttpClient _httpClient;
|
private readonly IHttpClient _httpClient;
|
||||||
private readonly IDiskProvider _diskProvider;
|
private readonly IDiskProvider _diskProvider;
|
||||||
|
@ -40,7 +41,8 @@ namespace NzbDrone.Core.MediaCover
|
||||||
// So limit the number of concurrent resizing tasks
|
// So limit the number of concurrent resizing tasks
|
||||||
private static SemaphoreSlim _semaphore = new SemaphoreSlim((int)Math.Ceiling(Environment.ProcessorCount / 2.0));
|
private static SemaphoreSlim _semaphore = new SemaphoreSlim((int)Math.Ceiling(Environment.ProcessorCount / 2.0));
|
||||||
|
|
||||||
public MediaCoverService(IImageResizer resizer,
|
public MediaCoverService(IMediaCoverProxy mediaCoverProxy,
|
||||||
|
IImageResizer resizer,
|
||||||
IHttpClient httpClient,
|
IHttpClient httpClient,
|
||||||
IDiskProvider diskProvider,
|
IDiskProvider diskProvider,
|
||||||
IAppFolderInfo appFolderInfo,
|
IAppFolderInfo appFolderInfo,
|
||||||
|
@ -49,6 +51,7 @@ namespace NzbDrone.Core.MediaCover
|
||||||
IEventAggregator eventAggregator,
|
IEventAggregator eventAggregator,
|
||||||
Logger logger)
|
Logger logger)
|
||||||
{
|
{
|
||||||
|
_mediaCoverProxy = mediaCoverProxy;
|
||||||
_resizer = resizer;
|
_resizer = resizer;
|
||||||
_httpClient = httpClient;
|
_httpClient = httpClient;
|
||||||
_diskProvider = diskProvider;
|
_diskProvider = diskProvider;
|
||||||
|
@ -69,16 +72,27 @@ namespace NzbDrone.Core.MediaCover
|
||||||
|
|
||||||
public void ConvertToLocalUrls(int seriesId, IEnumerable<MediaCover> covers)
|
public void ConvertToLocalUrls(int seriesId, IEnumerable<MediaCover> covers)
|
||||||
{
|
{
|
||||||
foreach (var mediaCover in covers)
|
if (seriesId == 0)
|
||||||
{
|
{
|
||||||
var filePath = GetCoverPath(seriesId, mediaCover.CoverType);
|
// Series isn't in Sonarr yet, map via a proxy to circument referrer issues
|
||||||
|
foreach (var mediaCover in covers)
|
||||||
mediaCover.Url = _configFileProvider.UrlBase + @"/MediaCover/" + seriesId + "/" + mediaCover.CoverType.ToString().ToLower() + ".jpg";
|
|
||||||
|
|
||||||
if (_diskProvider.FileExists(filePath))
|
|
||||||
{
|
{
|
||||||
var lastWrite = _diskProvider.FileGetLastWrite(filePath);
|
mediaCover.Url = _mediaCoverProxy.RegisterUrl(mediaCover.Url);
|
||||||
mediaCover.Url += "?lastWrite=" + lastWrite.Ticks;
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
foreach (var mediaCover in covers)
|
||||||
|
{
|
||||||
|
var filePath = GetCoverPath(seriesId, mediaCover.CoverType);
|
||||||
|
|
||||||
|
mediaCover.Url = _configFileProvider.UrlBase + @"/MediaCover/" + seriesId + "/" + mediaCover.CoverType.ToString().ToLower() + ".jpg";
|
||||||
|
|
||||||
|
if (_diskProvider.FileExists(filePath))
|
||||||
|
{
|
||||||
|
var lastWrite = _diskProvider.FileGetLastWrite(filePath);
|
||||||
|
mediaCover.Url += "?lastWrite=" + lastWrite.Ticks;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -100,7 +100,7 @@ namespace NzbDrone.Core.MetadataSource.SkyHook
|
||||||
|
|
||||||
var httpResponse = _httpClient.Get<List<ShowResource>>(httpRequest);
|
var httpResponse = _httpClient.Get<List<ShowResource>>(httpRequest);
|
||||||
|
|
||||||
return httpResponse.Resource.SelectList(MapSearhResult);
|
return httpResponse.Resource.SelectList(MapSearchResult);
|
||||||
}
|
}
|
||||||
catch (HttpException)
|
catch (HttpException)
|
||||||
{
|
{
|
||||||
|
@ -113,7 +113,7 @@ namespace NzbDrone.Core.MetadataSource.SkyHook
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Series MapSearhResult(ShowResource show)
|
private Series MapSearchResult(ShowResource show)
|
||||||
{
|
{
|
||||||
var series = _seriesService.FindByTvdbId(show.TvdbId);
|
var series = _seriesService.FindByTvdbId(show.TvdbId);
|
||||||
|
|
||||||
|
|
|
@ -13,12 +13,14 @@ namespace Sonarr.Api.V3.Series
|
||||||
{
|
{
|
||||||
private readonly ISearchForNewSeries _searchProxy;
|
private readonly ISearchForNewSeries _searchProxy;
|
||||||
private readonly IBuildFileNames _fileNameBuilder;
|
private readonly IBuildFileNames _fileNameBuilder;
|
||||||
|
private readonly IMapCoversToLocal _coverMapper;
|
||||||
|
|
||||||
public SeriesLookupModule(ISearchForNewSeries searchProxy, IBuildFileNames fileNameBuilder)
|
public SeriesLookupModule(ISearchForNewSeries searchProxy, IBuildFileNames fileNameBuilder, IMapCoversToLocal coverMapper)
|
||||||
: base("/series/lookup")
|
: base("/series/lookup")
|
||||||
{
|
{
|
||||||
_searchProxy = searchProxy;
|
_searchProxy = searchProxy;
|
||||||
_fileNameBuilder = fileNameBuilder;
|
_fileNameBuilder = fileNameBuilder;
|
||||||
|
_coverMapper = coverMapper;
|
||||||
Get("/", x => Search());
|
Get("/", x => Search());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,6 +35,9 @@ namespace Sonarr.Api.V3.Series
|
||||||
foreach (var currentSeries in series)
|
foreach (var currentSeries in series)
|
||||||
{
|
{
|
||||||
var resource = currentSeries.ToResource();
|
var resource = currentSeries.ToResource();
|
||||||
|
|
||||||
|
_coverMapper.ConvertToLocalUrls(resource.Id, resource.Images);
|
||||||
|
|
||||||
var poster = currentSeries.Images.FirstOrDefault(c => c.CoverType == MediaCoverTypes.Poster);
|
var poster = currentSeries.Images.FirstOrDefault(c => c.CoverType == MediaCoverTypes.Poster);
|
||||||
|
|
||||||
if (poster != null)
|
if (poster != null)
|
||||||
|
|
|
@ -43,7 +43,7 @@ namespace Sonarr.Http.Frontend.Mappers
|
||||||
|
|
||||||
public override bool CanHandle(string resourceUrl)
|
public override bool CanHandle(string resourceUrl)
|
||||||
{
|
{
|
||||||
return resourceUrl.StartsWith("/MediaCover", StringComparison.InvariantCultureIgnoreCase);
|
return resourceUrl.StartsWith("/MediaCover/", StringComparison.InvariantCultureIgnoreCase);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using Nancy;
|
||||||
|
using Nancy.Responses;
|
||||||
|
using NzbDrone.Core.MediaCover;
|
||||||
|
|
||||||
|
namespace Sonarr.Http.Frontend.Mappers
|
||||||
|
{
|
||||||
|
public class MediaCoverProxyMapper : IMapHttpRequestsToDisk
|
||||||
|
{
|
||||||
|
private readonly Regex _regex = new Regex(@"/MediaCoverProxy/(?<hash>\w+)/(?<filename>(.+)\.(jpg|png|gif))");
|
||||||
|
|
||||||
|
private readonly IMediaCoverProxy _mediaCoverProxy;
|
||||||
|
|
||||||
|
public MediaCoverProxyMapper(IMediaCoverProxy mediaCoverProxy)
|
||||||
|
{
|
||||||
|
_mediaCoverProxy = mediaCoverProxy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Map(string resourceUrl)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool CanHandle(string resourceUrl)
|
||||||
|
{
|
||||||
|
return resourceUrl.StartsWith("/MediaCoverProxy/", StringComparison.InvariantCultureIgnoreCase);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Response GetResponse(string resourceUrl)
|
||||||
|
{
|
||||||
|
var match = _regex.Match(resourceUrl);
|
||||||
|
|
||||||
|
if (!match.Success)
|
||||||
|
{
|
||||||
|
return new NotFoundResponse();
|
||||||
|
}
|
||||||
|
|
||||||
|
var hash = match.Groups["hash"].Value;
|
||||||
|
var filename = match.Groups["filename"].Value;
|
||||||
|
|
||||||
|
var imageData = _mediaCoverProxy.GetImage(hash);
|
||||||
|
|
||||||
|
return new StreamResponse(() => new MemoryStream(imageData), MimeTypes.GetMimeType(filename));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue