New: Support for running from a sub folder (reverse proxy)
This commit is contained in:
parent
cec479923f
commit
b5c9a811dd
|
@ -1,4 +1,5 @@
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
using Nancy;
|
using Nancy;
|
||||||
using NLog;
|
using NLog;
|
||||||
using NzbDrone.Common;
|
using NzbDrone.Common;
|
||||||
|
@ -12,6 +13,7 @@ namespace NzbDrone.Api.Frontend.Mappers
|
||||||
private readonly IDiskProvider _diskProvider;
|
private readonly IDiskProvider _diskProvider;
|
||||||
private readonly IConfigFileProvider _configFileProvider;
|
private readonly IConfigFileProvider _configFileProvider;
|
||||||
private readonly string _indexPath;
|
private readonly string _indexPath;
|
||||||
|
private static readonly Regex ReplaceRegex = new Regex("(?<=(?:href|src|data-main)=\").*?(?=\")", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||||
|
|
||||||
public IndexHtmlMapper(IAppFolderInfo appFolderInfo,
|
public IndexHtmlMapper(IAppFolderInfo appFolderInfo,
|
||||||
IDiskProvider diskProvider,
|
IDiskProvider diskProvider,
|
||||||
|
@ -47,13 +49,15 @@ namespace NzbDrone.Api.Frontend.Mappers
|
||||||
return StringToStream(GetIndexText());
|
return StringToStream(GetIndexText());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private string GetIndexText()
|
private string GetIndexText()
|
||||||
{
|
{
|
||||||
var text = _diskProvider.ReadAllText(_indexPath);
|
var text = _diskProvider.ReadAllText(_indexPath);
|
||||||
|
|
||||||
|
text = ReplaceRegex.Replace(text, match => _configFileProvider.UrlBase + match.Value);
|
||||||
|
|
||||||
text = text.Replace(".css", ".css?v=" + BuildInfo.Version);
|
text = text.Replace(".css", ".css?v=" + BuildInfo.Version);
|
||||||
text = text.Replace(".js", ".js?v=" + BuildInfo.Version);
|
text = text.Replace(".js", ".js?v=" + BuildInfo.Version);
|
||||||
|
text = text.Replace("API_ROOT", _configFileProvider.UrlBase + "/api");
|
||||||
text = text.Replace("API_KEY", _configFileProvider.ApiKey);
|
text = text.Replace("API_KEY", _configFileProvider.ApiKey);
|
||||||
text = text.Replace("APP_VERSION", BuildInfo.Version.ToString());
|
text = text.Replace("APP_VERSION", BuildInfo.Version.ToString());
|
||||||
|
|
||||||
|
|
|
@ -1,21 +1,25 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using Nancy.Responses;
|
||||||
using NLog;
|
using NLog;
|
||||||
using Nancy;
|
using Nancy;
|
||||||
using NzbDrone.Api.Frontend.Mappers;
|
using NzbDrone.Api.Frontend.Mappers;
|
||||||
|
using NzbDrone.Core.Configuration;
|
||||||
|
|
||||||
namespace NzbDrone.Api.Frontend
|
namespace NzbDrone.Api.Frontend
|
||||||
{
|
{
|
||||||
public class StaticResourceModule : NancyModule
|
public class StaticResourceModule : NancyModule
|
||||||
{
|
{
|
||||||
private readonly IEnumerable<IMapHttpRequestsToDisk> _requestMappers;
|
private readonly IEnumerable<IMapHttpRequestsToDisk> _requestMappers;
|
||||||
|
private readonly IConfigFileProvider _configFileProvider;
|
||||||
private readonly Logger _logger;
|
private readonly Logger _logger;
|
||||||
|
|
||||||
|
|
||||||
public StaticResourceModule(IEnumerable<IMapHttpRequestsToDisk> requestMappers, Logger logger)
|
public StaticResourceModule(IEnumerable<IMapHttpRequestsToDisk> requestMappers, IConfigFileProvider configFileProvider, Logger logger)
|
||||||
{
|
{
|
||||||
_requestMappers = requestMappers;
|
_requestMappers = requestMappers;
|
||||||
|
_configFileProvider = configFileProvider;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
|
|
||||||
Get["/{resource*}"] = x => Index();
|
Get["/{resource*}"] = x => Index();
|
||||||
|
@ -34,8 +38,21 @@ namespace NzbDrone.Api.Frontend
|
||||||
return new NotFoundResponse();
|
return new NotFoundResponse();
|
||||||
}
|
}
|
||||||
|
|
||||||
var mapper = _requestMappers.SingleOrDefault(m => m.CanHandle(path));
|
//Redirect to the subfolder if the request went to the base URL
|
||||||
|
if (path.Equals("/"))
|
||||||
|
{
|
||||||
|
var urlBase = _configFileProvider.UrlBase;
|
||||||
|
|
||||||
|
if (!String.IsNullOrEmpty(urlBase))
|
||||||
|
{
|
||||||
|
if (Request.Url.BasePath != urlBase)
|
||||||
|
{
|
||||||
|
return new RedirectResponse(urlBase + "/");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var mapper = _requestMappers.SingleOrDefault(m => m.CanHandle(path));
|
||||||
|
|
||||||
if (mapper != null)
|
if (mapper != null)
|
||||||
{
|
{
|
||||||
|
|
|
@ -43,7 +43,8 @@ namespace NzbDrone.Api.System
|
||||||
IsWindows = OsInfo.IsWindows,
|
IsWindows = OsInfo.IsWindows,
|
||||||
Branch = _configFileProvider.Branch,
|
Branch = _configFileProvider.Branch,
|
||||||
Authentication = _configFileProvider.AuthenticationEnabled,
|
Authentication = _configFileProvider.AuthenticationEnabled,
|
||||||
StartOfWeek = (int)OsInfo.FirstDayOfWeek
|
StartOfWeek = (int)OsInfo.FirstDayOfWeek,
|
||||||
|
UrlBase = _configFileProvider.UrlBase
|
||||||
}.AsResponse();
|
}.AsResponse();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,7 @@ namespace NzbDrone.Core.Configuration
|
||||||
string ApiKey { get; }
|
string ApiKey { get; }
|
||||||
bool Torrent { get; }
|
bool Torrent { get; }
|
||||||
string SslCertHash { get; }
|
string SslCertHash { get; }
|
||||||
|
string UrlBase { get; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ConfigFileProvider : IConfigFileProvider
|
public class ConfigFileProvider : IConfigFileProvider
|
||||||
|
@ -152,6 +153,21 @@ namespace NzbDrone.Core.Configuration
|
||||||
get { return GetValue("SslCertHash", ""); }
|
get { return GetValue("SslCertHash", ""); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public string UrlBase
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var urlBase = GetValue("UrlBase", "");
|
||||||
|
|
||||||
|
if (String.IsNullOrEmpty(urlBase))
|
||||||
|
{
|
||||||
|
return urlBase;
|
||||||
|
}
|
||||||
|
|
||||||
|
return "/" + urlBase.Trim('/').ToLower();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public int GetValueInt(string key, int defaultValue)
|
public int GetValueInt(string key, int defaultValue)
|
||||||
{
|
{
|
||||||
return Convert.ToInt32(GetValue(key, defaultValue));
|
return Convert.ToInt32(GetValue(key, defaultValue));
|
||||||
|
|
|
@ -5,6 +5,7 @@ using System.Net;
|
||||||
using NLog;
|
using NLog;
|
||||||
using NzbDrone.Common;
|
using NzbDrone.Common;
|
||||||
using NzbDrone.Common.EnvironmentInfo;
|
using NzbDrone.Common.EnvironmentInfo;
|
||||||
|
using NzbDrone.Core.Configuration;
|
||||||
using NzbDrone.Core.Messaging.Events;
|
using NzbDrone.Core.Messaging.Events;
|
||||||
using NzbDrone.Core.Tv;
|
using NzbDrone.Core.Tv;
|
||||||
using NzbDrone.Core.Tv.Events;
|
using NzbDrone.Core.Tv.Events;
|
||||||
|
@ -19,16 +20,18 @@ namespace NzbDrone.Core.MediaCover
|
||||||
private readonly IHttpProvider _httpProvider;
|
private readonly IHttpProvider _httpProvider;
|
||||||
private readonly IDiskProvider _diskProvider;
|
private readonly IDiskProvider _diskProvider;
|
||||||
private readonly ICoverExistsSpecification _coverExistsSpecification;
|
private readonly ICoverExistsSpecification _coverExistsSpecification;
|
||||||
|
private readonly IConfigFileProvider _configFileProvider;
|
||||||
private readonly Logger _logger;
|
private readonly Logger _logger;
|
||||||
|
|
||||||
private readonly string _coverRootFolder;
|
private readonly string _coverRootFolder;
|
||||||
|
|
||||||
public MediaCoverService(IHttpProvider httpProvider, IDiskProvider diskProvider, IAppFolderInfo appFolderInfo,
|
public MediaCoverService(IHttpProvider httpProvider, IDiskProvider diskProvider, IAppFolderInfo appFolderInfo,
|
||||||
ICoverExistsSpecification coverExistsSpecification, Logger logger)
|
ICoverExistsSpecification coverExistsSpecification, IConfigFileProvider configFileProvider, Logger logger)
|
||||||
{
|
{
|
||||||
_httpProvider = httpProvider;
|
_httpProvider = httpProvider;
|
||||||
_diskProvider = diskProvider;
|
_diskProvider = diskProvider;
|
||||||
_coverExistsSpecification = coverExistsSpecification;
|
_coverExistsSpecification = coverExistsSpecification;
|
||||||
|
_configFileProvider = configFileProvider;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
|
|
||||||
_coverRootFolder = appFolderInfo.GetMediaCoverPath();
|
_coverRootFolder = appFolderInfo.GetMediaCoverPath();
|
||||||
|
@ -96,7 +99,7 @@ namespace NzbDrone.Core.MediaCover
|
||||||
{
|
{
|
||||||
var filePath = GetCoverPath(seriesId, mediaCover.CoverType);
|
var filePath = GetCoverPath(seriesId, mediaCover.CoverType);
|
||||||
|
|
||||||
mediaCover.Url = @"/MediaCover/" + seriesId + "/" + mediaCover.CoverType.ToString().ToLower() + ".jpg";
|
mediaCover.Url = _configFileProvider.UrlBase + @"/MediaCover/" + seriesId + "/" + mediaCover.CoverType.ToString().ToLower() + ".jpg";
|
||||||
|
|
||||||
if (_diskProvider.FileExists(filePath))
|
if (_diskProvider.FileExists(filePath))
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using NLog;
|
using NLog;
|
||||||
using NzbDrone.Common.EnvironmentInfo;
|
using NzbDrone.Common.EnvironmentInfo;
|
||||||
|
@ -9,8 +10,7 @@ namespace NzbDrone.Host.AccessControl
|
||||||
public interface IUrlAclAdapter
|
public interface IUrlAclAdapter
|
||||||
{
|
{
|
||||||
void ConfigureUrl();
|
void ConfigureUrl();
|
||||||
string Url { get; }
|
List<String> Urls { get; }
|
||||||
string HttpsUrl { get; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class UrlAclAdapter : IUrlAclAdapter
|
public class UrlAclAdapter : IUrlAclAdapter
|
||||||
|
@ -20,13 +20,7 @@ namespace NzbDrone.Host.AccessControl
|
||||||
private readonly IRuntimeInfo _runtimeInfo;
|
private readonly IRuntimeInfo _runtimeInfo;
|
||||||
private readonly Logger _logger;
|
private readonly Logger _logger;
|
||||||
|
|
||||||
public string Url { get; private set; }
|
public List<String> Urls { get; private set; }
|
||||||
public string HttpsUrl { get; private set; }
|
|
||||||
|
|
||||||
private string _localUrl;
|
|
||||||
private string _wildcardUrl;
|
|
||||||
private string _localHttpsUrl;
|
|
||||||
private string _wildcardHttpsUrl;
|
|
||||||
|
|
||||||
public UrlAclAdapter(INetshProvider netshProvider,
|
public UrlAclAdapter(INetshProvider netshProvider,
|
||||||
IConfigFileProvider configFileProvider,
|
IConfigFileProvider configFileProvider,
|
||||||
|
@ -38,25 +32,31 @@ namespace NzbDrone.Host.AccessControl
|
||||||
_runtimeInfo = runtimeInfo;
|
_runtimeInfo = runtimeInfo;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
|
|
||||||
_localUrl = String.Format("http://localhost:{0}/", _configFileProvider.Port);
|
Urls = new List<String>();
|
||||||
_wildcardUrl = String.Format("http://*:{0}/", _configFileProvider.Port);
|
|
||||||
_localHttpsUrl = String.Format("https://localhost:{0}/", _configFileProvider.SslPort);
|
|
||||||
_wildcardHttpsUrl = String.Format("https://*:{0}/", _configFileProvider.SslPort);
|
|
||||||
|
|
||||||
Url = _wildcardUrl;
|
|
||||||
HttpsUrl = _wildcardHttpsUrl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ConfigureUrl()
|
public void ConfigureUrl()
|
||||||
{
|
{
|
||||||
|
var localHttpUrls = BuildUrls("http", "localhost", _configFileProvider.Port);
|
||||||
|
var wildcardHttpUrls = BuildUrls("http", "*", _configFileProvider.Port);
|
||||||
|
|
||||||
|
var localHttpsUrls = BuildUrls("https", "localhost", _configFileProvider.SslPort);
|
||||||
|
var wildcardHttpsUrls = BuildUrls("https", "*", _configFileProvider.SslPort);
|
||||||
|
|
||||||
if (!_runtimeInfo.IsAdmin)
|
if (!_runtimeInfo.IsAdmin)
|
||||||
{
|
{
|
||||||
if (!IsRegistered(_wildcardUrl)) Url = _localUrl;
|
var httpUrls = wildcardHttpUrls.All(IsRegistered) ? wildcardHttpUrls : localHttpUrls;
|
||||||
if (!IsRegistered(_wildcardHttpsUrl)) HttpsUrl = _localHttpsUrl;
|
var httpsUrls = wildcardHttpsUrls.All(IsRegistered) ? wildcardHttpsUrls : localHttpsUrls;
|
||||||
|
|
||||||
|
Urls.AddRange(httpUrls);
|
||||||
|
Urls.AddRange(httpsUrls);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_runtimeInfo.IsAdmin)
|
else
|
||||||
{
|
{
|
||||||
|
Urls.AddRange(wildcardHttpUrls);
|
||||||
|
Urls.AddRange(wildcardHttpsUrls);
|
||||||
|
|
||||||
RefreshRegistration();
|
RefreshRegistration();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -66,8 +66,7 @@ namespace NzbDrone.Host.AccessControl
|
||||||
if (OsInfo.Version.Major < 6)
|
if (OsInfo.Version.Major < 6)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
RegisterUrl(Url);
|
Urls.ForEach(RegisterUrl);
|
||||||
RegisterUrl(HttpsUrl);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool IsRegistered(string urlAcl)
|
private bool IsRegistered(string urlAcl)
|
||||||
|
@ -85,5 +84,28 @@ namespace NzbDrone.Host.AccessControl
|
||||||
var arguments = String.Format("http add urlacl {0} sddl=D:(A;;GX;;;S-1-1-0)", urlAcl);
|
var arguments = String.Format("http add urlacl {0} sddl=D:(A;;GX;;;S-1-1-0)", urlAcl);
|
||||||
_netshProvider.Run(arguments);
|
_netshProvider.Run(arguments);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private string BuildUrl(string protocol, string url, int port, string urlBase)
|
||||||
|
{
|
||||||
|
var result = protocol + "://" + url + ":" + port;
|
||||||
|
result += String.IsNullOrEmpty(urlBase) ? "/" : urlBase + "/";
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<String> BuildUrls(string protocol, string url, int port)
|
||||||
|
{
|
||||||
|
var urls = new List<String>();
|
||||||
|
var urlBase = _configFileProvider.UrlBase;
|
||||||
|
|
||||||
|
if (!String.IsNullOrEmpty(urlBase))
|
||||||
|
{
|
||||||
|
urls.Add(BuildUrl(protocol, url, port, urlBase));
|
||||||
|
}
|
||||||
|
|
||||||
|
urls.Add(BuildUrl(protocol, url, port, ""));
|
||||||
|
|
||||||
|
return urls;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -57,25 +57,21 @@ namespace NzbDrone.Host.Owin
|
||||||
_urlAclAdapter.ConfigureUrl();
|
_urlAclAdapter.ConfigureUrl();
|
||||||
}
|
}
|
||||||
|
|
||||||
var options = new StartOptions(_urlAclAdapter.Url)
|
var options = new StartOptions()
|
||||||
{
|
{
|
||||||
ServerFactory = "Microsoft.Owin.Host.HttpListener"
|
ServerFactory = "Microsoft.Owin.Host.HttpListener"
|
||||||
};
|
};
|
||||||
|
|
||||||
if (_configFileProvider.EnableSsl)
|
_urlAclAdapter.Urls.ForEach(options.Urls.Add);
|
||||||
|
|
||||||
|
_logger.Info("Listening on the following URLs:");
|
||||||
|
foreach (var url in options.Urls)
|
||||||
{
|
{
|
||||||
_logger.Trace("SSL enabled, listening on: {0}", _urlAclAdapter.HttpsUrl);
|
_logger.Info(" {0}", url);
|
||||||
options.Urls.Add(_urlAclAdapter.HttpsUrl);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_logger.Info("starting server on {0}", _urlAclAdapter.Url);
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// options.ServerFactory = new
|
|
||||||
//_host = WebApp.Start(OwinServiceProviderFactory.Create(), options, BuildApp);
|
|
||||||
//_host = WebApp.Start(options, BuildApp);
|
|
||||||
|
|
||||||
_host = WebApp.Start(OwinServiceProviderFactory.Create(), options, BuildApp);
|
_host = WebApp.Start(OwinServiceProviderFactory.Create(), options, BuildApp);
|
||||||
}
|
}
|
||||||
catch (TargetInvocationException ex)
|
catch (TargetInvocationException ex)
|
||||||
|
|
|
@ -2,46 +2,46 @@
|
||||||
font-family: 'Open Sans';
|
font-family: 'Open Sans';
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 300;
|
font-weight: 300;
|
||||||
src: url('/Content/fonts/opensans-light.eot');
|
src: url('./fonts/opensans-light.eot');
|
||||||
src: local('Open Sans Light'),
|
src: local('Open Sans Light'),
|
||||||
local('OpenSans-Light'),
|
local('OpenSans-Light'),
|
||||||
url('/Content/fonts/opensans-light.eot?#iefix') format('embedded-opentype'),
|
url('./fonts/opensans-light.eot?#iefix') format('embedded-opentype'),
|
||||||
url('/Content/fonts/opensans-light.woff') format('woff'),
|
url('./fonts/opensans-light.woff') format('woff'),
|
||||||
url('/Content/fonts/opensans-light.ttf') format('truetype');
|
url('./fonts/opensans-light.ttf') format('truetype');
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Open Sans';
|
font-family: 'Open Sans';
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
src: url('/Content/fonts/opensans-regular.eot');
|
src: url('./fonts/opensans-regular.eot');
|
||||||
src: local('Open Sans'),
|
src: local('Open Sans'),
|
||||||
local('OpenSans'),
|
local('OpenSans'),
|
||||||
url('/Content/fonts/opensans-regular.eot?#iefix') format('embedded-opentype'),
|
url('./fonts/opensans-regular.eot?#iefix') format('embedded-opentype'),
|
||||||
url('/Content/fonts/opensans-regular.woff') format('woff'),
|
url('./fonts/opensans-regular.woff') format('woff'),
|
||||||
url('/Content/fonts/opensans-regular.ttf') format('truetype')
|
url('./fonts/opensans-regular.ttf') format('truetype')
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Open Sans';
|
font-family: 'Open Sans';
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
src: url('/Content/fonts/opensans-semibold.eot');
|
src: url('./fonts/opensans-semibold.eot');
|
||||||
src: local('Open Sans SemiBold'),
|
src: local('Open Sans SemiBold'),
|
||||||
local('OpenSans-SemiBold'),
|
local('OpenSans-SemiBold'),
|
||||||
url('/Content/fonts/opensans-semibold.eot?#iefix') format('embedded-opentype'),
|
url('./fonts/opensans-semibold.eot?#iefix') format('embedded-opentype'),
|
||||||
url('/Content/fonts/opensans-semibold.woff') format('woff'),
|
url('./fonts/opensans-semibold.woff') format('woff'),
|
||||||
url('/Content/fonts/opensans-semibold.ttf') format('truetype')
|
url('./fonts/opensans-semibold.ttf') format('truetype')
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Ubuntu Mono';
|
font-family: 'Ubuntu Mono';
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
src: url('/Content/fonts/ubuntumono-regular.eot');
|
src: url('./fonts/ubuntumono-regular.eot');
|
||||||
src: local('Open Sans'),
|
src: local('Open Sans'),
|
||||||
local('OpenSans'),
|
local('OpenSans'),
|
||||||
url('/Content/fonts/ubuntumono-regular.eot?#iefix') format('embedded-opentype'),
|
url('./fonts/ubuntumono-regular.eot?#iefix') format('embedded-opentype'),
|
||||||
url('/Content/fonts/ubuntumono-regular.woff') format('woff'),
|
url('./fonts/ubuntumono-regular.woff') format('woff'),
|
||||||
url('/Content/fonts/ubuntumono-regular.ttf') format('truetype')
|
url('./fonts/ubuntumono-regular.ttf') format('truetype')
|
||||||
}
|
}
|
|
@ -2,10 +2,11 @@
|
||||||
|
|
||||||
define(
|
define(
|
||||||
[
|
[
|
||||||
'handlebars'
|
'handlebars',
|
||||||
], function (Handlebars) {
|
'System/StatusModel'
|
||||||
|
], function (Handlebars, StatusModel) {
|
||||||
|
|
||||||
var placeHolder = '/Content/Images/poster-dark.jpg';
|
var placeHolder = StatusModel.get('urlBase') + '/Content/Images/poster-dark.jpg';
|
||||||
|
|
||||||
window.NzbDrone.imageError = function (img) {
|
window.NzbDrone.imageError = function (img) {
|
||||||
if (!img.src.contains(placeHolder)) {
|
if (!img.src.contains(placeHolder)) {
|
||||||
|
@ -17,4 +18,8 @@ define(
|
||||||
Handlebars.registerHelper('defaultImg', function () {
|
Handlebars.registerHelper('defaultImg', function () {
|
||||||
return new Handlebars.SafeString('onerror=window.NzbDrone.imageError(this)');
|
return new Handlebars.SafeString('onerror=window.NzbDrone.imageError(this)');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Handlebars.registerHelper('UrlBase', function () {
|
||||||
|
return new Handlebars.SafeString(StatusModel.get('urlBase'));
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -2,8 +2,9 @@
|
||||||
define(
|
define(
|
||||||
[
|
[
|
||||||
'handlebars',
|
'handlebars',
|
||||||
|
'System/StatusModel',
|
||||||
'underscore'
|
'underscore'
|
||||||
], function (Handlebars, _) {
|
], function (Handlebars, StatusModel, _) {
|
||||||
Handlebars.registerHelper('poster', function () {
|
Handlebars.registerHelper('poster', function () {
|
||||||
|
|
||||||
var poster = _.where(this.images, {coverType: 'poster'});
|
var poster = _.where(this.images, {coverType: 'poster'});
|
||||||
|
@ -32,7 +33,7 @@ define(
|
||||||
});
|
});
|
||||||
|
|
||||||
Handlebars.registerHelper('route', function () {
|
Handlebars.registerHelper('route', function () {
|
||||||
return '/series/' + this.titleSlug;
|
return StatusModel.get('urlBase') + '/series/' + this.titleSlug;
|
||||||
});
|
});
|
||||||
|
|
||||||
Handlebars.registerHelper('percentOfEpisodes', function () {
|
Handlebars.registerHelper('percentOfEpisodes', function () {
|
||||||
|
|
|
@ -3,47 +3,47 @@
|
||||||
<div class="span12">
|
<div class="span12">
|
||||||
<ul id="main-menu-region">
|
<ul id="main-menu-region">
|
||||||
<div class="pull-left logo">
|
<div class="pull-left logo">
|
||||||
<a href="/">
|
<a href="{{UrlBase}}/">
|
||||||
<img src="/Content/Images/logo.png" alt="NzbDrone">
|
<img src="{{UrlBase}}/Content/Images/logo.png" alt="NzbDrone">
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<li>
|
<li>
|
||||||
<a href="/">
|
<a href="{{UrlBase}}/">
|
||||||
<i class="icon-play"></i>
|
<i class="icon-play"></i>
|
||||||
<br>
|
<br>
|
||||||
Series
|
Series
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a href="/calendar">
|
<a href="{{UrlBase}}/calendar">
|
||||||
<i class="icon-calendar"></i>
|
<i class="icon-calendar"></i>
|
||||||
<br>
|
<br>
|
||||||
Calendar
|
Calendar
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a href="/history">
|
<a href="{{UrlBase}}/history">
|
||||||
<i class="icon-time"></i>
|
<i class="icon-time"></i>
|
||||||
<br>
|
<br>
|
||||||
History
|
History
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a href="/missing">
|
<a href="{{UrlBase}}/missing">
|
||||||
<i class="icon-warning-sign"></i>
|
<i class="icon-warning-sign"></i>
|
||||||
<br>
|
<br>
|
||||||
Missing
|
Missing
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a href="/settings">
|
<a href="{{UrlBase}}/settings">
|
||||||
<i class="icon-cogs"></i>
|
<i class="icon-cogs"></i>
|
||||||
<br>
|
<br>
|
||||||
Settings
|
Settings
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a href="/system">
|
<a href="{{UrlBase}}/system">
|
||||||
<i class="icon-laptop"></i>
|
<i class="icon-laptop"></i>
|
||||||
<br>
|
<br>
|
||||||
System
|
System
|
||||||
|
|
|
@ -29,7 +29,7 @@ define(
|
||||||
//look down for <a/>
|
//look down for <a/>
|
||||||
var href = event.target.getAttribute('href');
|
var href = event.target.getAttribute('href');
|
||||||
|
|
||||||
//if couldn't find it look up
|
//if couldn't find it look up'
|
||||||
if (!href && target.parent('a') && target.parent('a')[0]) {
|
if (!href && target.parent('a') && target.parent('a')[0]) {
|
||||||
|
|
||||||
var linkElement = target.parent('a')[0];
|
var linkElement = target.parent('a')[0];
|
||||||
|
|
|
@ -17,7 +17,6 @@ define(
|
||||||
this.route('series/:query', this.seriesDetails);
|
this.route('series/:query', this.seriesDetails);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
series: function () {
|
series: function () {
|
||||||
this.setTitle('NzbDrone');
|
this.setTitle('NzbDrone');
|
||||||
AppLayout.mainRegion.show(new SeriesIndexLayout());
|
AppLayout.mainRegion.show(new SeriesIndexLayout());
|
||||||
|
|
|
@ -6,8 +6,9 @@ define(
|
||||||
'Settings/Indexers/ItemView',
|
'Settings/Indexers/ItemView',
|
||||||
'Settings/Indexers/EditView',
|
'Settings/Indexers/EditView',
|
||||||
'Settings/Indexers/Collection',
|
'Settings/Indexers/Collection',
|
||||||
|
'System/StatusModel',
|
||||||
'underscore'
|
'underscore'
|
||||||
], function (AppLayout, Marionette, IndexerItemView, IndexerEditView, IndexerCollection, _) {
|
], function (AppLayout, Marionette, IndexerItemView, IndexerEditView, IndexerCollection, StatusModel, _) {
|
||||||
return Marionette.CompositeView.extend({
|
return Marionette.CompositeView.extend({
|
||||||
itemView : IndexerItemView,
|
itemView : IndexerItemView,
|
||||||
itemViewContainer: '#x-indexers',
|
itemViewContainer: '#x-indexers',
|
||||||
|
@ -29,10 +30,10 @@ define(
|
||||||
var self = this;
|
var self = this;
|
||||||
//TODO: Is there a better way to deal with changing URLs?
|
//TODO: Is there a better way to deal with changing URLs?
|
||||||
var schemaCollection = new IndexerCollection();
|
var schemaCollection = new IndexerCollection();
|
||||||
schemaCollection.url = '/api/indexer/schema';
|
schemaCollection.url = StatusModel.get('urlBase') + '/api/indexer/schema';
|
||||||
schemaCollection.fetch({
|
schemaCollection.fetch({
|
||||||
success: function (collection) {
|
success: function (collection) {
|
||||||
collection.url = '/api/indexer';
|
collection.url = './api/indexer';
|
||||||
var model = _.first(collection.models);
|
var model = _.first(collection.models);
|
||||||
|
|
||||||
model.set({
|
model.set({
|
||||||
|
|
|
@ -2,15 +2,16 @@
|
||||||
define([
|
define([
|
||||||
'AppLayout',
|
'AppLayout',
|
||||||
'Settings/Notifications/Collection',
|
'Settings/Notifications/Collection',
|
||||||
'Settings/Notifications/AddView'
|
'Settings/Notifications/AddView',
|
||||||
], function (AppLayout, NotificationCollection, AddSelectionNotificationView) {
|
'System/StatusModel'
|
||||||
|
], function (AppLayout, NotificationCollection, AddSelectionNotificationView, StatusModel) {
|
||||||
return ({
|
return ({
|
||||||
|
|
||||||
open: function (collection) {
|
open: function (collection) {
|
||||||
var schemaCollection = new NotificationCollection();
|
var schemaCollection = new NotificationCollection();
|
||||||
schemaCollection.url = '/api/notification/schema';
|
schemaCollection.url = StatusModel.get('urlBase') + '/api/notification/schema';
|
||||||
schemaCollection.fetch();
|
schemaCollection.fetch();
|
||||||
schemaCollection.url = '/api/notification';
|
schemaCollection.url = StatusModel.get('urlBase') + '/api/notification';
|
||||||
|
|
||||||
var view = new AddSelectionNotificationView({ collection: schemaCollection, notificationCollection: collection});
|
var view = new AddSelectionNotificationView({ collection: schemaCollection, notificationCollection: collection});
|
||||||
AppLayout.modalRegion.show(view);
|
AppLayout.modalRegion.show(view);
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
<div>
|
<div>
|
||||||
<img src="/Content/Images/404.png" style="height:400px; margin-top: 50px"/>
|
<img src="{{UrlBase}}/Content/Images/404.png" style="height:400px; margin-top: 50px"/>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -31,7 +31,7 @@ define(
|
||||||
var messengerId = 'signalR';
|
var messengerId = 'signalR';
|
||||||
var reconnectTimeout;
|
var reconnectTimeout;
|
||||||
|
|
||||||
this.signalRconnection = $.connection('/signalr');
|
this.signalRconnection = $.connection(StatusModel.get('urlBase') + '/signalr');
|
||||||
|
|
||||||
this.signalRconnection.stateChanged(function (change) {
|
this.signalRconnection.stateChanged(function (change) {
|
||||||
console.debug('SignalR: [{0}]'.format(getStatus(change.newState)));
|
console.debug('SignalR: [{0}]'.format(getStatus(change.newState)));
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
define(
|
define(
|
||||||
[
|
[
|
||||||
'backbone'
|
'backbone',
|
||||||
], function (Backbone) {
|
'System/StatusModel'
|
||||||
|
], function (Backbone, StatusModel) {
|
||||||
return Backbone.Model.extend({
|
return Backbone.Model.extend({
|
||||||
url: function () {
|
url: function () {
|
||||||
return '/log/' + this.get('filename');
|
return StatusModel.get('urlBase') + '/log/' + this.get('filename');
|
||||||
},
|
},
|
||||||
|
|
||||||
parse: function (contents) {
|
parse: function (contents) {
|
||||||
|
|
|
@ -1,15 +1,16 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
define(
|
define(
|
||||||
[
|
[
|
||||||
'Cells/NzbDroneCell'
|
'Cells/NzbDroneCell',
|
||||||
], function (NzbDroneCell) {
|
'System/StatusModel'
|
||||||
|
], function (NzbDroneCell, StatusModel) {
|
||||||
return NzbDroneCell.extend({
|
return NzbDroneCell.extend({
|
||||||
|
|
||||||
className: 'download-log-cell',
|
className: 'download-log-cell',
|
||||||
|
|
||||||
render: function () {
|
render: function () {
|
||||||
this.$el.empty();
|
this.$el.empty();
|
||||||
this.$el.html('<a href="/log/{0}" class="no-router" target="_blank">Download</a>'.format(this.cellValue));
|
this.$el.html('<a href="{0}/log/{1}" class="no-router" target="_blank">Download</a>'.format(StatusModel.get('urlBase'), this.cellValue));
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
|
@ -231,7 +231,7 @@ define(
|
||||||
});
|
});
|
||||||
|
|
||||||
app.addInitializer(function () {
|
app.addInitializer(function () {
|
||||||
Backbone.history.start({ pushState: true });
|
Backbone.history.start({ pushState: true, root: serverStatusModel.get('urlBase') });
|
||||||
RouteBinder.bind();
|
RouteBinder.bind();
|
||||||
AppLayout.navbarRegion.show(new NavbarView());
|
AppLayout.navbarRegion.show(new NavbarView());
|
||||||
$('body').addClass('started');
|
$('body').addClass('started');
|
||||||
|
|
|
@ -65,7 +65,7 @@
|
||||||
<div id="errors"></div>
|
<div id="errors"></div>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
window.NzbDrone = {
|
window.NzbDrone = {
|
||||||
ApiRoot: '/api',
|
ApiRoot: 'API_ROOT',
|
||||||
ApiKey : 'API_KEY',
|
ApiKey : 'API_KEY',
|
||||||
Version: 'APP_VERSION'
|
Version: 'APP_VERSION'
|
||||||
};
|
};
|
||||||
|
|
|
@ -2,8 +2,9 @@
|
||||||
define(
|
define(
|
||||||
[
|
[
|
||||||
'backbone',
|
'backbone',
|
||||||
'jquery'
|
'jquery',
|
||||||
], function (Backbone,$) {
|
'System/StatusModel'
|
||||||
|
], function (Backbone, $, StatusModel) {
|
||||||
//This module will automatically route all relative links through backbone router rather than
|
//This module will automatically route all relative links through backbone router rather than
|
||||||
//causing links to reload pages.
|
//causing links to reload pages.
|
||||||
|
|
||||||
|
@ -45,7 +46,9 @@ define(
|
||||||
|
|
||||||
|
|
||||||
if (!href.startsWith('http')) {
|
if (!href.startsWith('http')) {
|
||||||
Backbone.history.navigate(href, { trigger: true });
|
var relativeHref = href.replace(StatusModel.get('urlBase'), '');
|
||||||
|
|
||||||
|
Backbone.history.navigate(relativeHref, { trigger: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
else {
|
else {
|
||||||
|
|
Loading…
Reference in New Issue