diff --git a/src/Jackett.Common/Indexers/BaseIndexer.cs b/src/Jackett.Common/Indexers/BaseIndexer.cs index 1618bd39e..81422023c 100644 --- a/src/Jackett.Common/Indexers/BaseIndexer.cs +++ b/src/Jackett.Common/Indexers/BaseIndexer.cs @@ -558,6 +558,19 @@ namespace Jackett.Common.Indexers return response.ContentBytes; } + public virtual async Task DownloadImage(Uri link) + { + var uncleanLink = UncleanLink(link); + var requestLink = uncleanLink.ToString(); + var referer = SiteLink; + + var response = await RequestWithCookiesAsync(requestLink, null, RequestType.GET, referer); + if (response.IsRedirect) + await FollowIfRedirect(response); + + return response; + } + protected async Task RequestWithCookiesAndRetryAsync( string url, string cookieOverride = null, RequestType method = RequestType.GET, string referer = null, IEnumerable> data = null, diff --git a/src/Jackett.Common/Indexers/IIndexer.cs b/src/Jackett.Common/Indexers/IIndexer.cs index bc7112409..a7a7f065b 100644 --- a/src/Jackett.Common/Indexers/IIndexer.cs +++ b/src/Jackett.Common/Indexers/IIndexer.cs @@ -4,6 +4,7 @@ using System.Text; using System.Threading.Tasks; using Jackett.Common.Models; using Jackett.Common.Models.IndexerConfig; +using Jackett.Common.Utils.Clients; using Newtonsoft.Json.Linq; namespace Jackett.Common.Indexers @@ -65,5 +66,7 @@ namespace Jackett.Common.Indexers public interface IWebIndexer : IIndexer { Task Download(Uri link); + + Task DownloadImage(Uri link); } } diff --git a/src/Jackett.Common/Utils/Clients/HttpWebClient.cs b/src/Jackett.Common/Utils/Clients/HttpWebClient.cs index 1de621859..3f5053261 100644 --- a/src/Jackett.Common/Utils/Clients/HttpWebClient.cs +++ b/src/Jackett.Common/Utils/Clients/HttpWebClient.cs @@ -157,10 +157,9 @@ namespace Jackett.Common.Utils.Clients }; foreach (var header in response.Headers) - { - var value = header.Value; - result.Headers[header.Key.ToLowerInvariant()] = value.ToArray(); - } + result.Headers[header.Key.ToLowerInvariant()] = header.Value.ToArray(); + foreach (var header in response.Content.Headers) + result.Headers[header.Key.ToLowerInvariant()] = header.Value.ToArray(); // some cloudflare clients are using a refresh header // Pull it out manually diff --git a/src/Jackett.Common/Utils/Clients/HttpWebClient2.cs b/src/Jackett.Common/Utils/Clients/HttpWebClient2.cs index 080b1b17b..9bea61fc7 100644 --- a/src/Jackett.Common/Utils/Clients/HttpWebClient2.cs +++ b/src/Jackett.Common/Utils/Clients/HttpWebClient2.cs @@ -183,10 +183,9 @@ namespace Jackett.Common.Utils.Clients }; foreach (var header in response.Headers) - { - var value = header.Value; - result.Headers[header.Key.ToLowerInvariant()] = value.ToArray(); - } + result.Headers[header.Key.ToLowerInvariant()] = header.Value.ToArray(); + foreach (var header in response.Content.Headers) + result.Headers[header.Key.ToLowerInvariant()] = header.Value.ToArray(); // some cloudflare clients are using a refresh header // Pull it out manually diff --git a/src/Jackett.Server/Controllers/ImageController.cs b/src/Jackett.Server/Controllers/ImageController.cs new file mode 100644 index 000000000..69c709a7f --- /dev/null +++ b/src/Jackett.Server/Controllers/ImageController.cs @@ -0,0 +1,72 @@ +using System; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Jackett.Common.Models.Config; +using Jackett.Common.Services.Interfaces; +using Jackett.Server.ActionFilters; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.WebUtilities; +using NLog; + +namespace Jackett.Server.Controllers +{ + [AllowAnonymous] + [DownloadActionFilter] + [ResponseCache(Location = ResponseCacheLocation.None, NoStore = true)] + [Route("img/{indexerID}")] + public class ImageController : Controller + { + private readonly ServerConfig serverConfig; + private readonly Logger logger; + private readonly IIndexerManagerService indexerService; + private readonly IProtectionService protectionService; + + public ImageController(IIndexerManagerService i, Logger l, IProtectionService ps, ServerConfig sConfig) + { + serverConfig = sConfig; + logger = l; + indexerService = i; + protectionService = ps; + } + + [HttpGet] + public async Task DownloadImage(string indexerID, string path, string jackett_apikey, string file) + { + try + { + if (serverConfig.APIKey != jackett_apikey) + return Unauthorized(); + + var indexer = indexerService.GetWebIndexer(indexerID); + if (!indexer.IsConfigured) + { + logger.Warn($"Rejected a request to {indexer.DisplayName} which is unconfigured."); + return Forbid("This indexer is not configured."); + } + + path = Encoding.UTF8.GetString(WebEncoders.Base64UrlDecode(path)); + path = protectionService.UnProtect(path); + + var target = new Uri(path, UriKind.RelativeOrAbsolute); + var response = await indexer.DownloadImage(target); + + if (response.Status != System.Net.HttpStatusCode.OK && + response.Status != System.Net.HttpStatusCode.Continue && + response.Status != System.Net.HttpStatusCode.PartialContent) + return new StatusCodeResult((int)response.Status); + + var contentType = response.Headers.ContainsKey("content-type") ? + response.Headers["content-type"].First() : + "image/jpeg"; + return File(response.ContentBytes, contentType); + } + catch (Exception e) + { + logger.Debug($"Error downloading image. indexer: {indexerID} path: {path}\n{e}"); + return new StatusCodeResult((int)System.Net.HttpStatusCode.InternalServerError); + } + } + } +} diff --git a/src/Jackett.Server/Controllers/IndexerApiController.cs b/src/Jackett.Server/Controllers/IndexerApiController.cs index 908af579e..80dac97b6 100644 --- a/src/Jackett.Server/Controllers/IndexerApiController.cs +++ b/src/Jackett.Server/Controllers/IndexerApiController.cs @@ -167,11 +167,11 @@ namespace Jackett.Server.Controllers var serverUrl = serverService.GetServerUrl(Request); foreach (var result in results) { - var link = result.Link; var file = StringUtil.MakeValidFileName(result.Title, '_', false); - result.Link = serverService.ConvertToProxyLink(link, serverUrl, result.TrackerId, "dl", file); + result.Link = serverService.ConvertToProxyLink(result.Link, serverUrl, result.TrackerId, "dl", file); + result.Poster = serverService.ConvertToProxyLink(result.Poster, serverUrl, result.TrackerId, "img", "poster"); if (result.Link != null && result.Link.Scheme != "magnet" && !string.IsNullOrWhiteSpace(serverService.GetBlackholeDirectory())) - result.BlackholeLink = serverService.ConvertToProxyLink(link, serverUrl, result.TrackerId, "bh", file); + result.BlackholeLink = serverService.ConvertToProxyLink(result.Link, serverUrl, result.TrackerId, "bh", file); } } diff --git a/src/Jackett.Server/Controllers/ResultsController.cs b/src/Jackett.Server/Controllers/ResultsController.cs index 3463be57e..368cd8880 100644 --- a/src/Jackett.Server/Controllers/ResultsController.cs +++ b/src/Jackett.Server/Controllers/ResultsController.cs @@ -414,6 +414,7 @@ namespace Jackett.Server.Controllers var proxiedReleases = result.Releases.Select(r => MapperUtil.Mapper.Map(r)).Select(r => { r.Link = serverService.ConvertToProxyLink(r.Link, serverUrl, r.Origin.Id, "dl", r.Title); + r.Poster = serverService.ConvertToProxyLink(r.Poster, serverUrl, r.Origin.Id, "img", "poster"); return r; }); @@ -498,6 +499,9 @@ namespace Jackett.Server.Controllers { var release = MapperUtil.Mapper.Map(r); release.Link = serverService.ConvertToProxyLink(release.Link, serverUrl, CurrentIndexer.Id, "dl", release.Title); + // Poster is not used in Potato response + //release.Poster = serverService.ConvertToProxyLink(release.Poster, serverUrl, CurrentIndexer.Id, "img", "poster"); + // IMPORTANT: We can't use Uri.ToString(), because it generates URLs without URL encode (links with unicode // characters are broken). We must use Uri.AbsoluteUri instead that handles encoding correctly var item = new TorrentPotatoResponseItem() @@ -531,13 +535,13 @@ namespace Jackett.Server.Controllers var serverUrl = serverService.GetServerUrl(Request); foreach (var result in results) { - var link = result.Link; var file = StringUtil.MakeValidFileName(result.Title, '_', false); - result.Link = serverService.ConvertToProxyLink(link, serverUrl, result.TrackerId, "dl", file); + result.Link = serverService.ConvertToProxyLink(result.Link, serverUrl, result.TrackerId, "dl", file); + result.Poster = serverService.ConvertToProxyLink(result.Poster, serverUrl, result.TrackerId, "img", "poster"); if (!string.IsNullOrWhiteSpace(serverConfig.BlackholeDir)) { if (result.Link != null) - result.BlackholeLink = serverService.ConvertToProxyLink(link, serverUrl, result.TrackerId, "bh", file); + result.BlackholeLink = serverService.ConvertToProxyLink(result.Link, serverUrl, result.TrackerId, "bh", file); else if (result.MagnetUri != null) result.BlackholeLink = serverService.ConvertToProxyLink(result.MagnetUri, serverUrl, result.TrackerId, "bh", file); }