mirror of
https://github.com/Prowlarr/Prowlarr.git
synced 2025-09-17 17:14:18 +02:00
Initial Push
This commit is contained in:
74
src/Prowlarr.Http/Frontend/CacheableSpecification.cs
Normal file
74
src/Prowlarr.Http/Frontend/CacheableSpecification.cs
Normal file
@@ -0,0 +1,74 @@
|
||||
using System;
|
||||
using Nancy;
|
||||
using NzbDrone.Common.EnvironmentInfo;
|
||||
using NzbDrone.Common.Extensions;
|
||||
|
||||
namespace Prowlarr.Http.Frontend
|
||||
{
|
||||
public interface ICacheableSpecification
|
||||
{
|
||||
bool IsCacheable(NancyContext context);
|
||||
}
|
||||
|
||||
public class CacheableSpecification : ICacheableSpecification
|
||||
{
|
||||
public bool IsCacheable(NancyContext context)
|
||||
{
|
||||
if (!RuntimeInfo.IsProduction)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (((DynamicDictionary)context.Request.Query).ContainsKey("h"))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (context.Request.Path.StartsWith("/api", StringComparison.CurrentCultureIgnoreCase))
|
||||
{
|
||||
if (context.Request.Path.ContainsIgnoreCase("/MediaCover"))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (context.Request.Path.StartsWith("/signalr", StringComparison.CurrentCultureIgnoreCase))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (context.Request.Path.EndsWith("index.js"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (context.Request.Path.EndsWith("initialize.js"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (context.Request.Path.StartsWith("/feed", StringComparison.CurrentCultureIgnoreCase))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (context.Request.Path.StartsWith("/log", StringComparison.CurrentCultureIgnoreCase) &&
|
||||
context.Request.Path.EndsWith(".txt", StringComparison.CurrentCultureIgnoreCase))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (context.Response != null)
|
||||
{
|
||||
if (context.Response.ContentType.Contains("text/html"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
77
src/Prowlarr.Http/Frontend/InitializeJsModule.cs
Normal file
77
src/Prowlarr.Http/Frontend/InitializeJsModule.cs
Normal file
@@ -0,0 +1,77 @@
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using Nancy;
|
||||
using Nancy.Responses;
|
||||
using NzbDrone.Common;
|
||||
using NzbDrone.Common.EnvironmentInfo;
|
||||
using NzbDrone.Core.Analytics;
|
||||
using NzbDrone.Core.Configuration;
|
||||
|
||||
namespace Prowlarr.Http.Frontend
|
||||
{
|
||||
public class InitializeJsModule : NancyModule
|
||||
{
|
||||
private readonly IConfigFileProvider _configFileProvider;
|
||||
private readonly IAnalyticsService _analyticsService;
|
||||
|
||||
private static string _apiKey;
|
||||
private static string _urlBase;
|
||||
private string _generatedContent;
|
||||
|
||||
public InitializeJsModule(IConfigFileProvider configFileProvider,
|
||||
IAnalyticsService analyticsService)
|
||||
{
|
||||
_configFileProvider = configFileProvider;
|
||||
_analyticsService = analyticsService;
|
||||
|
||||
_apiKey = configFileProvider.ApiKey;
|
||||
_urlBase = configFileProvider.UrlBase;
|
||||
|
||||
Get("/initialize.js", x => Index());
|
||||
}
|
||||
|
||||
private Response Index()
|
||||
{
|
||||
// TODO: Move away from window.Sonarr and prefetch the information returned here when starting the UI
|
||||
return new StreamResponse(GetContentStream, "application/javascript");
|
||||
}
|
||||
|
||||
private Stream GetContentStream()
|
||||
{
|
||||
var text = GetContent();
|
||||
|
||||
var stream = new MemoryStream();
|
||||
var writer = new StreamWriter(stream);
|
||||
writer.Write(text);
|
||||
writer.Flush();
|
||||
stream.Position = 0;
|
||||
|
||||
return stream;
|
||||
}
|
||||
|
||||
private string GetContent()
|
||||
{
|
||||
if (RuntimeInfo.IsProduction && _generatedContent != null)
|
||||
{
|
||||
return _generatedContent;
|
||||
}
|
||||
|
||||
var builder = new StringBuilder();
|
||||
builder.AppendLine("window.Prowlarr = {");
|
||||
builder.AppendLine($" apiRoot: '{_urlBase}/api/v1',");
|
||||
builder.AppendLine($" apiKey: '{_apiKey}',");
|
||||
builder.AppendLine($" release: '{BuildInfo.Release}',");
|
||||
builder.AppendLine($" version: '{BuildInfo.Version.ToString()}',");
|
||||
builder.AppendLine($" branch: '{_configFileProvider.Branch.ToLower()}',");
|
||||
builder.AppendLine($" analytics: {_analyticsService.IsEnabled.ToString().ToLowerInvariant()},");
|
||||
builder.AppendLine($" userHash: '{HashUtil.AnonymousToken()}',");
|
||||
builder.AppendLine($" urlBase: '{_urlBase}',");
|
||||
builder.AppendLine($" isProduction: {RuntimeInfo.IsProduction.ToString().ToLowerInvariant()}");
|
||||
builder.AppendLine("};");
|
||||
|
||||
_generatedContent = builder.ToString();
|
||||
|
||||
return _generatedContent;
|
||||
}
|
||||
}
|
||||
}
|
30
src/Prowlarr.Http/Frontend/Mappers/BackupFileMapper.cs
Normal file
30
src/Prowlarr.Http/Frontend/Mappers/BackupFileMapper.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
using System.IO;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Disk;
|
||||
using NzbDrone.Core.Backup;
|
||||
|
||||
namespace Prowlarr.Http.Frontend.Mappers
|
||||
{
|
||||
public class BackupFileMapper : StaticResourceMapperBase
|
||||
{
|
||||
private readonly IBackupService _backupService;
|
||||
|
||||
public BackupFileMapper(IBackupService backupService, IDiskProvider diskProvider, Logger logger)
|
||||
: base(diskProvider, logger)
|
||||
{
|
||||
_backupService = backupService;
|
||||
}
|
||||
|
||||
public override string Map(string resourceUrl)
|
||||
{
|
||||
var path = resourceUrl.Replace("/backup/", "").Replace('/', Path.DirectorySeparatorChar);
|
||||
|
||||
return Path.Combine(_backupService.GetBackupFolder(), path);
|
||||
}
|
||||
|
||||
public override bool CanHandle(string resourceUrl)
|
||||
{
|
||||
return resourceUrl.StartsWith("/backup/") && BackupService.BackupFileRegex.IsMatch(resourceUrl);
|
||||
}
|
||||
}
|
||||
}
|
34
src/Prowlarr.Http/Frontend/Mappers/BrowserConfig.cs
Normal file
34
src/Prowlarr.Http/Frontend/Mappers/BrowserConfig.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
using System.IO;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Disk;
|
||||
using NzbDrone.Common.EnvironmentInfo;
|
||||
using NzbDrone.Core.Configuration;
|
||||
|
||||
namespace Prowlarr.Http.Frontend.Mappers
|
||||
{
|
||||
public class BrowserConfig : StaticResourceMapperBase
|
||||
{
|
||||
private readonly IAppFolderInfo _appFolderInfo;
|
||||
private readonly IConfigFileProvider _configFileProvider;
|
||||
|
||||
public BrowserConfig(IAppFolderInfo appFolderInfo, IDiskProvider diskProvider, IConfigFileProvider configFileProvider, Logger logger)
|
||||
: base(diskProvider, logger)
|
||||
{
|
||||
_appFolderInfo = appFolderInfo;
|
||||
_configFileProvider = configFileProvider;
|
||||
}
|
||||
|
||||
public override string Map(string resourceUrl)
|
||||
{
|
||||
var path = resourceUrl.Replace('/', Path.DirectorySeparatorChar);
|
||||
path = path.Trim(Path.DirectorySeparatorChar);
|
||||
|
||||
return Path.ChangeExtension(Path.Combine(_appFolderInfo.StartUpFolder, _configFileProvider.UiFolder, path), "xml");
|
||||
}
|
||||
|
||||
public override bool CanHandle(string resourceUrl)
|
||||
{
|
||||
return resourceUrl.StartsWith("/content/images/icons/browserconfig");
|
||||
}
|
||||
}
|
||||
}
|
43
src/Prowlarr.Http/Frontend/Mappers/CacheBreakerProvider.cs
Normal file
43
src/Prowlarr.Http/Frontend/Mappers/CacheBreakerProvider.cs
Normal file
@@ -0,0 +1,43 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NzbDrone.Common.Crypto;
|
||||
using NzbDrone.Common.Extensions;
|
||||
|
||||
namespace Prowlarr.Http.Frontend.Mappers
|
||||
{
|
||||
public interface ICacheBreakerProvider
|
||||
{
|
||||
string AddCacheBreakerToPath(string resourceUrl);
|
||||
}
|
||||
|
||||
public class CacheBreakerProvider : ICacheBreakerProvider
|
||||
{
|
||||
private readonly IEnumerable<IMapHttpRequestsToDisk> _diskMappers;
|
||||
private readonly IHashProvider _hashProvider;
|
||||
|
||||
public CacheBreakerProvider(IEnumerable<IMapHttpRequestsToDisk> diskMappers, IHashProvider hashProvider)
|
||||
{
|
||||
_diskMappers = diskMappers;
|
||||
_hashProvider = hashProvider;
|
||||
}
|
||||
|
||||
public string AddCacheBreakerToPath(string resourceUrl)
|
||||
{
|
||||
if (!ShouldBreakCache(resourceUrl))
|
||||
{
|
||||
return resourceUrl;
|
||||
}
|
||||
|
||||
var mapper = _diskMappers.Single(m => m.CanHandle(resourceUrl));
|
||||
var pathToFile = mapper.Map(resourceUrl);
|
||||
var hash = _hashProvider.ComputeMd5(pathToFile).ToBase64();
|
||||
|
||||
return resourceUrl + "?h=" + hash.Trim('=');
|
||||
}
|
||||
|
||||
private static bool ShouldBreakCache(string path)
|
||||
{
|
||||
return !path.EndsWith(".ics") && !path.EndsWith("main");
|
||||
}
|
||||
}
|
||||
}
|
40
src/Prowlarr.Http/Frontend/Mappers/FaviconMapper.cs
Normal file
40
src/Prowlarr.Http/Frontend/Mappers/FaviconMapper.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
using System.IO;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Disk;
|
||||
using NzbDrone.Common.EnvironmentInfo;
|
||||
using NzbDrone.Core.Configuration;
|
||||
|
||||
namespace Prowlarr.Http.Frontend.Mappers
|
||||
{
|
||||
public class FaviconMapper : StaticResourceMapperBase
|
||||
{
|
||||
private readonly IAppFolderInfo _appFolderInfo;
|
||||
private readonly IConfigFileProvider _configFileProvider;
|
||||
|
||||
public FaviconMapper(IAppFolderInfo appFolderInfo, IDiskProvider diskProvider, IConfigFileProvider configFileProvider, Logger logger)
|
||||
: base(diskProvider, logger)
|
||||
{
|
||||
_appFolderInfo = appFolderInfo;
|
||||
_configFileProvider = configFileProvider;
|
||||
}
|
||||
|
||||
public override string Map(string resourceUrl)
|
||||
{
|
||||
var fileName = "favicon.ico";
|
||||
|
||||
if (BuildInfo.IsDebug)
|
||||
{
|
||||
fileName = "favicon-debug.ico";
|
||||
}
|
||||
|
||||
var path = Path.Combine("Content", "Images", "Icons", fileName);
|
||||
|
||||
return Path.Combine(_appFolderInfo.StartUpFolder, _configFileProvider.UiFolder, path);
|
||||
}
|
||||
|
||||
public override bool CanHandle(string resourceUrl)
|
||||
{
|
||||
return resourceUrl.Equals("/favicon.ico");
|
||||
}
|
||||
}
|
||||
}
|
82
src/Prowlarr.Http/Frontend/Mappers/HtmlMapperBase.cs
Normal file
82
src/Prowlarr.Http/Frontend/Mappers/HtmlMapperBase.cs
Normal file
@@ -0,0 +1,82 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text.RegularExpressions;
|
||||
using Nancy;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Disk;
|
||||
using NzbDrone.Common.EnvironmentInfo;
|
||||
|
||||
namespace Prowlarr.Http.Frontend.Mappers
|
||||
{
|
||||
public abstract class HtmlMapperBase : StaticResourceMapperBase
|
||||
{
|
||||
private readonly IDiskProvider _diskProvider;
|
||||
private readonly Func<ICacheBreakerProvider> _cacheBreakProviderFactory;
|
||||
private static readonly Regex ReplaceRegex = new Regex(@"(?:(?<attribute>href|src)=\"")(?<path>.*?(?<extension>css|js|png|ico|ics|svg|json))(?:\"")(?:\s(?<nohash>data-no-hash))?", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
|
||||
private string _generatedContent;
|
||||
|
||||
protected HtmlMapperBase(IDiskProvider diskProvider,
|
||||
Func<ICacheBreakerProvider> cacheBreakProviderFactory,
|
||||
Logger logger)
|
||||
: base(diskProvider, logger)
|
||||
{
|
||||
_diskProvider = diskProvider;
|
||||
_cacheBreakProviderFactory = cacheBreakProviderFactory;
|
||||
}
|
||||
|
||||
protected string HtmlPath;
|
||||
protected string UrlBase;
|
||||
|
||||
protected override Stream GetContentStream(string filePath)
|
||||
{
|
||||
var text = GetHtmlText();
|
||||
|
||||
var stream = new MemoryStream();
|
||||
var writer = new StreamWriter(stream);
|
||||
writer.Write(text);
|
||||
writer.Flush();
|
||||
stream.Position = 0;
|
||||
return stream;
|
||||
}
|
||||
|
||||
public override Response GetResponse(string resourceUrl)
|
||||
{
|
||||
var response = base.GetResponse(resourceUrl);
|
||||
response.Headers["X-UA-Compatible"] = "IE=edge";
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
protected string GetHtmlText()
|
||||
{
|
||||
if (RuntimeInfo.IsProduction && _generatedContent != null)
|
||||
{
|
||||
return _generatedContent;
|
||||
}
|
||||
|
||||
var text = _diskProvider.ReadAllText(HtmlPath);
|
||||
var cacheBreakProvider = _cacheBreakProviderFactory();
|
||||
|
||||
text = ReplaceRegex.Replace(text, match =>
|
||||
{
|
||||
string url;
|
||||
|
||||
if (match.Groups["nohash"].Success)
|
||||
{
|
||||
url = match.Groups["path"].Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
url = cacheBreakProvider.AddCacheBreakerToPath(match.Groups["path"].Value);
|
||||
}
|
||||
|
||||
return string.Format("{0}=\"{1}{2}\"", match.Groups["attribute"].Value, UrlBase, url);
|
||||
});
|
||||
|
||||
_generatedContent = text;
|
||||
|
||||
return _generatedContent;
|
||||
}
|
||||
}
|
||||
}
|
11
src/Prowlarr.Http/Frontend/Mappers/IMapHttpRequestsToDisk.cs
Normal file
11
src/Prowlarr.Http/Frontend/Mappers/IMapHttpRequestsToDisk.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using Nancy;
|
||||
|
||||
namespace Prowlarr.Http.Frontend.Mappers
|
||||
{
|
||||
public interface IMapHttpRequestsToDisk
|
||||
{
|
||||
string Map(string resourceUrl);
|
||||
bool CanHandle(string resourceUrl);
|
||||
Response GetResponse(string resourceUrl);
|
||||
}
|
||||
}
|
42
src/Prowlarr.Http/Frontend/Mappers/IndexHtmlMapper.cs
Normal file
42
src/Prowlarr.Http/Frontend/Mappers/IndexHtmlMapper.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Disk;
|
||||
using NzbDrone.Common.EnvironmentInfo;
|
||||
using NzbDrone.Core.Configuration;
|
||||
|
||||
namespace Prowlarr.Http.Frontend.Mappers
|
||||
{
|
||||
public class IndexHtmlMapper : HtmlMapperBase
|
||||
{
|
||||
private readonly IConfigFileProvider _configFileProvider;
|
||||
|
||||
public IndexHtmlMapper(IAppFolderInfo appFolderInfo,
|
||||
IDiskProvider diskProvider,
|
||||
IConfigFileProvider configFileProvider,
|
||||
Func<ICacheBreakerProvider> cacheBreakProviderFactory,
|
||||
Logger logger)
|
||||
: base(diskProvider, cacheBreakProviderFactory, logger)
|
||||
{
|
||||
_configFileProvider = configFileProvider;
|
||||
|
||||
HtmlPath = Path.Combine(appFolderInfo.StartUpFolder, _configFileProvider.UiFolder, "index.html");
|
||||
UrlBase = configFileProvider.UrlBase;
|
||||
}
|
||||
|
||||
public override string Map(string resourceUrl)
|
||||
{
|
||||
return HtmlPath;
|
||||
}
|
||||
|
||||
public override bool CanHandle(string resourceUrl)
|
||||
{
|
||||
resourceUrl = resourceUrl.ToLowerInvariant();
|
||||
|
||||
return !resourceUrl.StartsWith("/content") &&
|
||||
!resourceUrl.StartsWith("/mediacover") &&
|
||||
!resourceUrl.Contains(".") &&
|
||||
!resourceUrl.StartsWith("/login");
|
||||
}
|
||||
}
|
||||
}
|
32
src/Prowlarr.Http/Frontend/Mappers/LogFileMapper.cs
Normal file
32
src/Prowlarr.Http/Frontend/Mappers/LogFileMapper.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
using System.IO;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Disk;
|
||||
using NzbDrone.Common.EnvironmentInfo;
|
||||
using NzbDrone.Common.Extensions;
|
||||
|
||||
namespace Prowlarr.Http.Frontend.Mappers
|
||||
{
|
||||
public class UpdateLogFileMapper : StaticResourceMapperBase
|
||||
{
|
||||
private readonly IAppFolderInfo _appFolderInfo;
|
||||
|
||||
public UpdateLogFileMapper(IAppFolderInfo appFolderInfo, IDiskProvider diskProvider, Logger logger)
|
||||
: base(diskProvider, logger)
|
||||
{
|
||||
_appFolderInfo = appFolderInfo;
|
||||
}
|
||||
|
||||
public override string Map(string resourceUrl)
|
||||
{
|
||||
var path = resourceUrl.Replace('/', Path.DirectorySeparatorChar);
|
||||
path = Path.GetFileName(path);
|
||||
|
||||
return Path.Combine(_appFolderInfo.GetUpdateLogFolder(), path);
|
||||
}
|
||||
|
||||
public override bool CanHandle(string resourceUrl)
|
||||
{
|
||||
return resourceUrl.StartsWith("/updatelogfile/") && resourceUrl.EndsWith(".txt");
|
||||
}
|
||||
}
|
||||
}
|
33
src/Prowlarr.Http/Frontend/Mappers/LoginHtmlMapper.cs
Normal file
33
src/Prowlarr.Http/Frontend/Mappers/LoginHtmlMapper.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Disk;
|
||||
using NzbDrone.Common.EnvironmentInfo;
|
||||
using NzbDrone.Core.Configuration;
|
||||
|
||||
namespace Prowlarr.Http.Frontend.Mappers
|
||||
{
|
||||
public class LoginHtmlMapper : HtmlMapperBase
|
||||
{
|
||||
public LoginHtmlMapper(IAppFolderInfo appFolderInfo,
|
||||
IDiskProvider diskProvider,
|
||||
Func<ICacheBreakerProvider> cacheBreakProviderFactory,
|
||||
IConfigFileProvider configFileProvider,
|
||||
Logger logger)
|
||||
: base(diskProvider, cacheBreakProviderFactory, logger)
|
||||
{
|
||||
HtmlPath = Path.Combine(appFolderInfo.StartUpFolder, configFileProvider.UiFolder, "login.html");
|
||||
UrlBase = configFileProvider.UrlBase;
|
||||
}
|
||||
|
||||
public override string Map(string resourceUrl)
|
||||
{
|
||||
return HtmlPath;
|
||||
}
|
||||
|
||||
public override bool CanHandle(string resourceUrl)
|
||||
{
|
||||
return resourceUrl.StartsWith("/login");
|
||||
}
|
||||
}
|
||||
}
|
34
src/Prowlarr.Http/Frontend/Mappers/ManifestMapper.cs
Normal file
34
src/Prowlarr.Http/Frontend/Mappers/ManifestMapper.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
using System.IO;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Disk;
|
||||
using NzbDrone.Common.EnvironmentInfo;
|
||||
using NzbDrone.Core.Configuration;
|
||||
|
||||
namespace Prowlarr.Http.Frontend.Mappers
|
||||
{
|
||||
public class ManifestMapper : StaticResourceMapperBase
|
||||
{
|
||||
private readonly IAppFolderInfo _appFolderInfo;
|
||||
private readonly IConfigFileProvider _configFileProvider;
|
||||
|
||||
public ManifestMapper(IAppFolderInfo appFolderInfo, IDiskProvider diskProvider, IConfigFileProvider configFileProvider, Logger logger)
|
||||
: base(diskProvider, logger)
|
||||
{
|
||||
_appFolderInfo = appFolderInfo;
|
||||
_configFileProvider = configFileProvider;
|
||||
}
|
||||
|
||||
public override string Map(string resourceUrl)
|
||||
{
|
||||
var path = resourceUrl.Replace('/', Path.DirectorySeparatorChar);
|
||||
path = path.Trim(Path.DirectorySeparatorChar);
|
||||
|
||||
return Path.ChangeExtension(Path.Combine(_appFolderInfo.StartUpFolder, _configFileProvider.UiFolder, path), "json");
|
||||
}
|
||||
|
||||
public override bool CanHandle(string resourceUrl)
|
||||
{
|
||||
return resourceUrl.StartsWith("/Content/Images/Icons/manifest");
|
||||
}
|
||||
}
|
||||
}
|
49
src/Prowlarr.Http/Frontend/Mappers/MediaCoverMapper.cs
Normal file
49
src/Prowlarr.Http/Frontend/Mappers/MediaCoverMapper.cs
Normal file
@@ -0,0 +1,49 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text.RegularExpressions;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Disk;
|
||||
using NzbDrone.Common.EnvironmentInfo;
|
||||
using NzbDrone.Common.Extensions;
|
||||
|
||||
namespace Prowlarr.Http.Frontend.Mappers
|
||||
{
|
||||
public class MediaCoverMapper : StaticResourceMapperBase
|
||||
{
|
||||
private static readonly Regex RegexResizedImage = new Regex(@"-\d+\.jpg($|\?)", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
|
||||
private readonly IAppFolderInfo _appFolderInfo;
|
||||
private readonly IDiskProvider _diskProvider;
|
||||
|
||||
public MediaCoverMapper(IAppFolderInfo appFolderInfo, IDiskProvider diskProvider, Logger logger)
|
||||
: base(diskProvider, logger)
|
||||
{
|
||||
_appFolderInfo = appFolderInfo;
|
||||
_diskProvider = diskProvider;
|
||||
}
|
||||
|
||||
public override string Map(string resourceUrl)
|
||||
{
|
||||
var path = resourceUrl.Replace('/', Path.DirectorySeparatorChar);
|
||||
path = path.Trim(Path.DirectorySeparatorChar);
|
||||
|
||||
var resourcePath = Path.Combine(_appFolderInfo.GetAppDataPath(), path);
|
||||
|
||||
if (!_diskProvider.FileExists(resourcePath) || _diskProvider.GetFileSize(resourcePath) == 0)
|
||||
{
|
||||
var baseResourcePath = RegexResizedImage.Replace(resourcePath, ".jpg$1");
|
||||
if (baseResourcePath != resourcePath)
|
||||
{
|
||||
return baseResourcePath;
|
||||
}
|
||||
}
|
||||
|
||||
return resourcePath;
|
||||
}
|
||||
|
||||
public override bool CanHandle(string resourceUrl)
|
||||
{
|
||||
return resourceUrl.StartsWith("/MediaCover/", StringComparison.InvariantCultureIgnoreCase);
|
||||
}
|
||||
}
|
||||
}
|
33
src/Prowlarr.Http/Frontend/Mappers/RobotsTxtMapper.cs
Normal file
33
src/Prowlarr.Http/Frontend/Mappers/RobotsTxtMapper.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
using System.IO;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Disk;
|
||||
using NzbDrone.Common.EnvironmentInfo;
|
||||
using NzbDrone.Core.Configuration;
|
||||
|
||||
namespace Prowlarr.Http.Frontend.Mappers
|
||||
{
|
||||
public class RobotsTxtMapper : StaticResourceMapperBase
|
||||
{
|
||||
private readonly IAppFolderInfo _appFolderInfo;
|
||||
private readonly IConfigFileProvider _configFileProvider;
|
||||
|
||||
public RobotsTxtMapper(IAppFolderInfo appFolderInfo, IDiskProvider diskProvider, IConfigFileProvider configFileProvider, Logger logger)
|
||||
: base(diskProvider, logger)
|
||||
{
|
||||
_appFolderInfo = appFolderInfo;
|
||||
_configFileProvider = configFileProvider;
|
||||
}
|
||||
|
||||
public override string Map(string resourceUrl)
|
||||
{
|
||||
var path = Path.Combine("Content", "robots.txt");
|
||||
|
||||
return Path.Combine(_appFolderInfo.StartUpFolder, _configFileProvider.UiFolder, path);
|
||||
}
|
||||
|
||||
public override bool CanHandle(string resourceUrl)
|
||||
{
|
||||
return resourceUrl.Equals("/robots.txt");
|
||||
}
|
||||
}
|
||||
}
|
48
src/Prowlarr.Http/Frontend/Mappers/StaticResourceMapper.cs
Normal file
48
src/Prowlarr.Http/Frontend/Mappers/StaticResourceMapper.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
using System.IO;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Disk;
|
||||
using NzbDrone.Common.EnvironmentInfo;
|
||||
using NzbDrone.Core.Configuration;
|
||||
|
||||
namespace Prowlarr.Http.Frontend.Mappers
|
||||
{
|
||||
public class StaticResourceMapper : StaticResourceMapperBase
|
||||
{
|
||||
private readonly IAppFolderInfo _appFolderInfo;
|
||||
private readonly IConfigFileProvider _configFileProvider;
|
||||
|
||||
public StaticResourceMapper(IAppFolderInfo appFolderInfo, IDiskProvider diskProvider, IConfigFileProvider configFileProvider, Logger logger)
|
||||
: base(diskProvider, logger)
|
||||
{
|
||||
_appFolderInfo = appFolderInfo;
|
||||
_configFileProvider = configFileProvider;
|
||||
}
|
||||
|
||||
public override string Map(string resourceUrl)
|
||||
{
|
||||
var path = resourceUrl.Replace('/', Path.DirectorySeparatorChar);
|
||||
path = path.Trim(Path.DirectorySeparatorChar);
|
||||
|
||||
return Path.Combine(_appFolderInfo.StartUpFolder, _configFileProvider.UiFolder, path);
|
||||
}
|
||||
|
||||
public override bool CanHandle(string resourceUrl)
|
||||
{
|
||||
resourceUrl = resourceUrl.ToLowerInvariant();
|
||||
|
||||
if (resourceUrl.StartsWith("/content/images/icons/manifest") ||
|
||||
resourceUrl.StartsWith("/content/images/icons/browserconfig"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return resourceUrl.StartsWith("/content") ||
|
||||
(resourceUrl.EndsWith(".js") && !resourceUrl.EndsWith("initialize.js")) ||
|
||||
resourceUrl.EndsWith(".map") ||
|
||||
resourceUrl.EndsWith(".css") ||
|
||||
(resourceUrl.EndsWith(".ico") && !resourceUrl.Equals("/favicon.ico")) ||
|
||||
resourceUrl.EndsWith(".swf") ||
|
||||
resourceUrl.EndsWith("oauth.html");
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,51 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using Nancy;
|
||||
using Nancy.Responses;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Disk;
|
||||
using NzbDrone.Common.EnvironmentInfo;
|
||||
|
||||
namespace Prowlarr.Http.Frontend.Mappers
|
||||
{
|
||||
public abstract class StaticResourceMapperBase : IMapHttpRequestsToDisk
|
||||
{
|
||||
private readonly IDiskProvider _diskProvider;
|
||||
private readonly Logger _logger;
|
||||
private readonly StringComparison _caseSensitive;
|
||||
|
||||
private static readonly NotFoundResponse NotFoundResponse = new NotFoundResponse();
|
||||
|
||||
protected StaticResourceMapperBase(IDiskProvider diskProvider, Logger logger)
|
||||
{
|
||||
_diskProvider = diskProvider;
|
||||
_logger = logger;
|
||||
|
||||
_caseSensitive = RuntimeInfo.IsProduction ? DiskProviderBase.PathStringComparison : StringComparison.OrdinalIgnoreCase;
|
||||
}
|
||||
|
||||
public abstract string Map(string resourceUrl);
|
||||
|
||||
public abstract bool CanHandle(string resourceUrl);
|
||||
|
||||
public virtual Response GetResponse(string resourceUrl)
|
||||
{
|
||||
var filePath = Map(resourceUrl);
|
||||
|
||||
if (_diskProvider.FileExists(filePath, _caseSensitive))
|
||||
{
|
||||
var response = new StreamResponse(() => GetContentStream(filePath), MimeTypes.GetMimeType(filePath));
|
||||
return new MaterialisingResponse(response);
|
||||
}
|
||||
|
||||
_logger.Warn("File {0} not found", filePath);
|
||||
|
||||
return NotFoundResponse;
|
||||
}
|
||||
|
||||
protected virtual Stream GetContentStream(string filePath)
|
||||
{
|
||||
return File.OpenRead(filePath);
|
||||
}
|
||||
}
|
||||
}
|
32
src/Prowlarr.Http/Frontend/Mappers/UpdateLogFileMapper.cs
Normal file
32
src/Prowlarr.Http/Frontend/Mappers/UpdateLogFileMapper.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
using System.IO;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Disk;
|
||||
using NzbDrone.Common.EnvironmentInfo;
|
||||
using NzbDrone.Common.Extensions;
|
||||
|
||||
namespace Prowlarr.Http.Frontend.Mappers
|
||||
{
|
||||
public class LogFileMapper : StaticResourceMapperBase
|
||||
{
|
||||
private readonly IAppFolderInfo _appFolderInfo;
|
||||
|
||||
public LogFileMapper(IAppFolderInfo appFolderInfo, IDiskProvider diskProvider, Logger logger)
|
||||
: base(diskProvider, logger)
|
||||
{
|
||||
_appFolderInfo = appFolderInfo;
|
||||
}
|
||||
|
||||
public override string Map(string resourceUrl)
|
||||
{
|
||||
var path = resourceUrl.Replace('/', Path.DirectorySeparatorChar);
|
||||
path = Path.GetFileName(path);
|
||||
|
||||
return Path.Combine(_appFolderInfo.GetLogFolder(), path);
|
||||
}
|
||||
|
||||
public override bool CanHandle(string resourceUrl)
|
||||
{
|
||||
return resourceUrl.StartsWith("/logfile/") && resourceUrl.EndsWith(".txt");
|
||||
}
|
||||
}
|
||||
}
|
48
src/Prowlarr.Http/Frontend/StaticResourceModule.cs
Normal file
48
src/Prowlarr.Http/Frontend/StaticResourceModule.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Nancy;
|
||||
using NLog;
|
||||
using Prowlarr.Http.Frontend.Mappers;
|
||||
|
||||
namespace Prowlarr.Http.Frontend
|
||||
{
|
||||
public class StaticResourceModule : NancyModule
|
||||
{
|
||||
private readonly IEnumerable<IMapHttpRequestsToDisk> _requestMappers;
|
||||
private readonly Logger _logger;
|
||||
|
||||
public StaticResourceModule(IEnumerable<IMapHttpRequestsToDisk> requestMappers, Logger logger)
|
||||
{
|
||||
_requestMappers = requestMappers;
|
||||
_logger = logger;
|
||||
|
||||
Get("/{resource*}", x => Index());
|
||||
Get("/", x => Index());
|
||||
}
|
||||
|
||||
private Response Index()
|
||||
{
|
||||
var path = Request.Url.Path;
|
||||
|
||||
if (
|
||||
string.IsNullOrWhiteSpace(path) ||
|
||||
path.StartsWith("/api", StringComparison.CurrentCultureIgnoreCase) ||
|
||||
path.StartsWith("/signalr", StringComparison.CurrentCultureIgnoreCase))
|
||||
{
|
||||
return new NotFoundResponse();
|
||||
}
|
||||
|
||||
var mapper = _requestMappers.SingleOrDefault(m => m.CanHandle(path));
|
||||
|
||||
if (mapper != null)
|
||||
{
|
||||
return mapper.GetResponse(path);
|
||||
}
|
||||
|
||||
_logger.Warn("Couldn't find handler for {0}", path);
|
||||
|
||||
return new NotFoundResponse();
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user