Преглед изворни кода

Merge pull request #4035 from crobibero/api-doc-base-url

Fix apidoc routes with base url
Joshua M. Boniface пре 4 година
родитељ
комит
376e4793e6

+ 2 - 100
Jellyfin.Api/Controllers/DashboardController.cs

@@ -15,6 +15,7 @@ using Microsoft.AspNetCore.Http.Extensions;
 using Microsoft.AspNetCore.Mvc;
 using Microsoft.AspNetCore.Mvc;
 using Microsoft.Extensions.Configuration;
 using Microsoft.Extensions.Configuration;
 using Microsoft.Extensions.Logging;
 using Microsoft.Extensions.Logging;
+using Microsoft.Net.Http.Headers;
 
 
 namespace Jellyfin.Api.Controllers
 namespace Jellyfin.Api.Controllers
 {
 {
@@ -26,38 +27,20 @@ namespace Jellyfin.Api.Controllers
     {
     {
         private readonly ILogger<DashboardController> _logger;
         private readonly ILogger<DashboardController> _logger;
         private readonly IServerApplicationHost _appHost;
         private readonly IServerApplicationHost _appHost;
-        private readonly IConfiguration _appConfig;
-        private readonly IServerConfigurationManager _serverConfigurationManager;
-        private readonly IResourceFileManager _resourceFileManager;
 
 
         /// <summary>
         /// <summary>
         /// Initializes a new instance of the <see cref="DashboardController"/> class.
         /// Initializes a new instance of the <see cref="DashboardController"/> class.
         /// </summary>
         /// </summary>
         /// <param name="logger">Instance of <see cref="ILogger{DashboardController}"/> interface.</param>
         /// <param name="logger">Instance of <see cref="ILogger{DashboardController}"/> interface.</param>
         /// <param name="appHost">Instance of <see cref="IServerApplicationHost"/> interface.</param>
         /// <param name="appHost">Instance of <see cref="IServerApplicationHost"/> interface.</param>
-        /// <param name="appConfig">Instance of <see cref="IConfiguration"/> interface.</param>
-        /// <param name="resourceFileManager">Instance of <see cref="IResourceFileManager"/> interface.</param>
-        /// <param name="serverConfigurationManager">Instance of <see cref="IServerConfigurationManager"/> interface.</param>
         public DashboardController(
         public DashboardController(
             ILogger<DashboardController> logger,
             ILogger<DashboardController> logger,
-            IServerApplicationHost appHost,
-            IConfiguration appConfig,
-            IResourceFileManager resourceFileManager,
-            IServerConfigurationManager serverConfigurationManager)
+            IServerApplicationHost appHost)
         {
         {
             _logger = logger;
             _logger = logger;
             _appHost = appHost;
             _appHost = appHost;
-            _appConfig = appConfig;
-            _resourceFileManager = resourceFileManager;
-            _serverConfigurationManager = serverConfigurationManager;
         }
         }
 
 
-        /// <summary>
-        /// Gets the path of the directory containing the static web interface content, or null if the server is not
-        /// hosting the web client.
-        /// </summary>
-        private string? WebClientUiPath => GetWebClientUiPath(_appConfig, _serverConfigurationManager);
-
         /// <summary>
         /// <summary>
         /// Gets the configuration pages.
         /// Gets the configuration pages.
         /// </summary>
         /// </summary>
@@ -169,87 +152,6 @@ namespace Jellyfin.Api.Controllers
             return NotFound();
             return NotFound();
         }
         }
 
 
-        /// <summary>
-        /// Gets the robots.txt.
-        /// </summary>
-        /// <response code="200">Robots.txt returned.</response>
-        /// <returns>The robots.txt.</returns>
-        [HttpGet("robots.txt")]
-        [ProducesResponseType(StatusCodes.Status200OK)]
-        [ApiExplorerSettings(IgnoreApi = true)]
-        public ActionResult GetRobotsTxt()
-        {
-            return GetWebClientResource("robots.txt");
-        }
-
-        /// <summary>
-        /// Gets a resource from the web client.
-        /// </summary>
-        /// <param name="resourceName">The resource name.</param>
-        /// <response code="200">Web client returned.</response>
-        /// <response code="404">Server does not host a web client.</response>
-        /// <returns>The resource.</returns>
-        [HttpGet("web/{*resourceName}")]
-        [ApiExplorerSettings(IgnoreApi = true)]
-        [ProducesResponseType(StatusCodes.Status200OK)]
-        [ProducesResponseType(StatusCodes.Status404NotFound)]
-        public ActionResult GetWebClientResource([FromRoute] string resourceName)
-        {
-            if (!_appConfig.HostWebClient() || WebClientUiPath == null)
-            {
-                return NotFound("Server does not host a web client.");
-            }
-
-            var path = resourceName;
-            var basePath = WebClientUiPath;
-
-            var requestPathAndQuery = Request.GetEncodedPathAndQuery();
-            // Bounce them to the startup wizard if it hasn't been completed yet
-            if (!_serverConfigurationManager.Configuration.IsStartupWizardCompleted
-                && !requestPathAndQuery.Contains("wizard", StringComparison.OrdinalIgnoreCase)
-                && requestPathAndQuery.Contains("index", StringComparison.OrdinalIgnoreCase))
-            {
-                return Redirect("index.html?start=wizard#!/wizardstart.html");
-            }
-
-            var stream = new FileStream(_resourceFileManager.GetResourcePath(basePath, path), FileMode.Open, FileAccess.Read);
-            return File(stream, MimeTypes.GetMimeType(path));
-        }
-
-        /// <summary>
-        /// Gets the favicon.
-        /// </summary>
-        /// <response code="200">Favicon.ico returned.</response>
-        /// <returns>The favicon.</returns>
-        [HttpGet("favicon.ico")]
-        [ProducesResponseType(StatusCodes.Status200OK)]
-        [ApiExplorerSettings(IgnoreApi = true)]
-        public ActionResult GetFavIcon()
-        {
-            return GetWebClientResource("favicon.ico");
-        }
-
-        /// <summary>
-        /// Gets the path of the directory containing the static web interface content.
-        /// </summary>
-        /// <param name="appConfig">The app configuration.</param>
-        /// <param name="serverConfigManager">The server configuration manager.</param>
-        /// <returns>The directory path, or null if the server is not hosting the web client.</returns>
-        public static string? GetWebClientUiPath(IConfiguration appConfig, IServerConfigurationManager serverConfigManager)
-        {
-            if (!appConfig.HostWebClient())
-            {
-                return null;
-            }
-
-            if (!string.IsNullOrEmpty(serverConfigManager.Configuration.DashboardSourcePath))
-            {
-                return serverConfigManager.Configuration.DashboardSourcePath;
-            }
-
-            return serverConfigManager.ApplicationPaths.WebPath;
-        }
-
         private IEnumerable<ConfigurationPageInfo> GetConfigPages(IPlugin plugin)
         private IEnumerable<ConfigurationPageInfo> GetConfigPages(IPlugin plugin)
         {
         {
             return GetPluginPages(plugin).Select(i => new ConfigurationPageInfo(plugin, i.Item1));
             return GetPluginPages(plugin).Select(i => new ConfigurationPageInfo(plugin, i.Item1));

+ 0 - 56
Jellyfin.Api/MvcRoutePrefix.cs

@@ -1,56 +0,0 @@
-using System.Collections.Generic;
-using System.Linq;
-using Microsoft.AspNetCore.Mvc;
-using Microsoft.AspNetCore.Mvc.ApplicationModels;
-
-namespace Jellyfin.Api
-{
-    /// <summary>
-    /// Route prefixing for ASP.NET MVC.
-    /// </summary>
-    public static class MvcRoutePrefix
-    {
-        /// <summary>
-        /// Adds route prefixes to the MVC conventions.
-        /// </summary>
-        /// <param name="opts">The MVC options.</param>
-        /// <param name="prefixes">The list of prefixes.</param>
-        public static void UseGeneralRoutePrefix(this MvcOptions opts, params string[] prefixes)
-        {
-            opts.Conventions.Insert(0, new RoutePrefixConvention(prefixes));
-        }
-
-        private class RoutePrefixConvention : IApplicationModelConvention
-        {
-            private readonly AttributeRouteModel[] _routePrefixes;
-
-            public RoutePrefixConvention(IEnumerable<string> prefixes)
-            {
-                _routePrefixes = prefixes.Select(p => new AttributeRouteModel(new RouteAttribute(p))).ToArray();
-            }
-
-            public void Apply(ApplicationModel application)
-            {
-                foreach (var controller in application.Controllers)
-                {
-                    if (controller.Selectors == null)
-                    {
-                        continue;
-                    }
-
-                    var newSelectors = new List<SelectorModel>();
-                    foreach (var selector in controller.Selectors)
-                    {
-                        newSelectors.AddRange(_routePrefixes.Select(routePrefix => new SelectorModel(selector)
-                        {
-                            AttributeRouteModel = AttributeRouteModel.CombineAttributeRouteModel(routePrefix, selector.AttributeRouteModel)
-                        }));
-                    }
-
-                    controller.Selectors.Clear();
-                    newSelectors.ForEach(selector => controller.Selectors.Add(selector));
-                }
-            }
-        }
-    }
-}

+ 10 - 3
Jellyfin.Server/Extensions/ApiApplicationBuilderExtensions.cs

@@ -1,6 +1,8 @@
+using System.Collections.Generic;
 using Jellyfin.Server.Middleware;
 using Jellyfin.Server.Middleware;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Configuration;
 using Microsoft.AspNetCore.Builder;
 using Microsoft.AspNetCore.Builder;
+using Microsoft.OpenApi.Models;
 
 
 namespace Jellyfin.Server.Extensions
 namespace Jellyfin.Server.Extensions
 {
 {
@@ -23,6 +25,7 @@ namespace Jellyfin.Server.Extensions
             // specifying the Swagger JSON endpoint.
             // specifying the Swagger JSON endpoint.
 
 
             var baseUrl = serverConfigurationManager.Configuration.BaseUrl.Trim('/');
             var baseUrl = serverConfigurationManager.Configuration.BaseUrl.Trim('/');
+            var apiDocBaseUrl = serverConfigurationManager.Configuration.BaseUrl;
             if (!string.IsNullOrEmpty(baseUrl))
             if (!string.IsNullOrEmpty(baseUrl))
             {
             {
                 baseUrl += '/';
                 baseUrl += '/';
@@ -32,21 +35,25 @@ namespace Jellyfin.Server.Extensions
                 .UseSwagger(c =>
                 .UseSwagger(c =>
                 {
                 {
                     // Custom path requires {documentName}, SwaggerDoc documentName is 'api-docs'
                     // Custom path requires {documentName}, SwaggerDoc documentName is 'api-docs'
-                    c.RouteTemplate = $"/{baseUrl}{{documentName}}/openapi.json";
+                    c.RouteTemplate = "{documentName}/openapi.json";
+                    c.PreSerializeFilters.Add((swagger, httpReq) =>
+                    {
+                        swagger.Servers = new List<OpenApiServer> { new OpenApiServer { Url = $"{httpReq.Scheme}://{httpReq.Host.Value}{apiDocBaseUrl}" } };
+                    });
                 })
                 })
                 .UseSwaggerUI(c =>
                 .UseSwaggerUI(c =>
                 {
                 {
                     c.DocumentTitle = "Jellyfin API";
                     c.DocumentTitle = "Jellyfin API";
                     c.SwaggerEndpoint($"/{baseUrl}api-docs/openapi.json", "Jellyfin API");
                     c.SwaggerEndpoint($"/{baseUrl}api-docs/openapi.json", "Jellyfin API");
-                    c.RoutePrefix = $"{baseUrl}api-docs/swagger";
                     c.InjectStylesheet($"/{baseUrl}api-docs/swagger/custom.css");
                     c.InjectStylesheet($"/{baseUrl}api-docs/swagger/custom.css");
+                    c.RoutePrefix = "api-docs/swagger";
                 })
                 })
                 .UseReDoc(c =>
                 .UseReDoc(c =>
                 {
                 {
                     c.DocumentTitle = "Jellyfin API";
                     c.DocumentTitle = "Jellyfin API";
                     c.SpecUrl($"/{baseUrl}api-docs/openapi.json");
                     c.SpecUrl($"/{baseUrl}api-docs/openapi.json");
-                    c.RoutePrefix = $"{baseUrl}api-docs/redoc";
                     c.InjectStylesheet($"/{baseUrl}api-docs/redoc/custom.css");
                     c.InjectStylesheet($"/{baseUrl}api-docs/redoc/custom.css");
+                    c.RoutePrefix = "api-docs/redoc";
                 });
                 });
         }
         }
 
 

+ 2 - 7
Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs

@@ -3,7 +3,6 @@ using System.Collections.Generic;
 using System.IO;
 using System.IO;
 using System.Linq;
 using System.Linq;
 using System.Reflection;
 using System.Reflection;
-using Jellyfin.Api;
 using Jellyfin.Api.Auth;
 using Jellyfin.Api.Auth;
 using Jellyfin.Api.Auth.DefaultAuthorizationPolicy;
 using Jellyfin.Api.Auth.DefaultAuthorizationPolicy;
 using Jellyfin.Api.Auth.DownloadPolicy;
 using Jellyfin.Api.Auth.DownloadPolicy;
@@ -18,7 +17,6 @@ using Jellyfin.Api.Constants;
 using Jellyfin.Api.Controllers;
 using Jellyfin.Api.Controllers;
 using Jellyfin.Server.Formatters;
 using Jellyfin.Server.Formatters;
 using Jellyfin.Server.Models;
 using Jellyfin.Server.Models;
-using MediaBrowser.Common;
 using MediaBrowser.Common.Json;
 using MediaBrowser.Common.Json;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Entities;
 using Microsoft.AspNetCore.Authentication;
 using Microsoft.AspNetCore.Authentication;
@@ -135,10 +133,9 @@ namespace Jellyfin.Server.Extensions
         /// Extension method for adding the jellyfin API to the service collection.
         /// Extension method for adding the jellyfin API to the service collection.
         /// </summary>
         /// </summary>
         /// <param name="serviceCollection">The service collection.</param>
         /// <param name="serviceCollection">The service collection.</param>
-        /// <param name="baseUrl">The base url for the API.</param>
-        /// <param name="pluginAssemblies">An IEnumberable containing all plugin assemblies with API controllers.</param>
+        /// <param name="pluginAssemblies">An IEnumerable containing all plugin assemblies with API controllers.</param>
         /// <returns>The MVC builder.</returns>
         /// <returns>The MVC builder.</returns>
-        public static IMvcBuilder AddJellyfinApi(this IServiceCollection serviceCollection, string baseUrl, IEnumerable<Assembly> pluginAssemblies)
+        public static IMvcBuilder AddJellyfinApi(this IServiceCollection serviceCollection, IEnumerable<Assembly> pluginAssemblies)
         {
         {
             IMvcBuilder mvcBuilder = serviceCollection
             IMvcBuilder mvcBuilder = serviceCollection
                 .AddCors(options =>
                 .AddCors(options =>
@@ -151,8 +148,6 @@ namespace Jellyfin.Server.Extensions
                 })
                 })
                 .AddMvc(opts =>
                 .AddMvc(opts =>
                 {
                 {
-                    opts.UseGeneralRoutePrefix(baseUrl);
-
                     // Allow requester to change between camelCase and PascalCase
                     // Allow requester to change between camelCase and PascalCase
                     opts.RespectBrowserAcceptHeader = true;
                     opts.RespectBrowserAcceptHeader = true;
 
 

+ 1 - 5
Jellyfin.Server/Middleware/BaseUrlRedirectionMiddleware.cs

@@ -44,11 +44,7 @@ namespace Jellyfin.Server.Middleware
             var localPath = httpContext.Request.Path.ToString();
             var localPath = httpContext.Request.Path.ToString();
             var baseUrlPrefix = serverConfigurationManager.Configuration.BaseUrl;
             var baseUrlPrefix = serverConfigurationManager.Configuration.BaseUrl;
 
 
-            if (string.Equals(localPath, baseUrlPrefix + "/", StringComparison.OrdinalIgnoreCase)
-                || string.Equals(localPath, baseUrlPrefix, StringComparison.OrdinalIgnoreCase)
-                || string.Equals(localPath, "/", StringComparison.OrdinalIgnoreCase)
-                || string.IsNullOrEmpty(localPath)
-                || !localPath.StartsWith(baseUrlPrefix, StringComparison.OrdinalIgnoreCase))
+            if (!localPath.StartsWith(baseUrlPrefix, StringComparison.OrdinalIgnoreCase))
             {
             {
                 // Always redirect back to the default path if the base prefix is invalid or missing
                 // Always redirect back to the default path if the base prefix is invalid or missing
                 _logger.LogDebug("Normalizing an URL at {LocalPath}", localPath);
                 _logger.LogDebug("Normalizing an URL at {LocalPath}", localPath);

+ 1 - 1
Jellyfin.Server/Program.cs

@@ -169,7 +169,7 @@ namespace Jellyfin.Server
                 // If hosting the web client, validate the client content path
                 // If hosting the web client, validate the client content path
                 if (startupConfig.HostWebClient())
                 if (startupConfig.HostWebClient())
                 {
                 {
-                    string? webContentPath = DashboardController.GetWebClientUiPath(startupConfig, appHost.ServerConfigurationManager);
+                    string? webContentPath = appHost.ServerConfigurationManager.ApplicationPaths.WebPath;
                     if (!Directory.Exists(webContentPath) || Directory.GetFiles(webContentPath).Length == 0)
                     if (!Directory.Exists(webContentPath) || Directory.GetFiles(webContentPath).Length == 0)
                     {
                     {
                         throw new InvalidOperationException(
                         throw new InvalidOperationException(

+ 58 - 36
Jellyfin.Server/Startup.cs

@@ -9,9 +9,12 @@ using Jellyfin.Server.Models;
 using MediaBrowser.Common.Net;
 using MediaBrowser.Common.Net;
 using MediaBrowser.Controller;
 using MediaBrowser.Controller;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Controller.Extensions;
 using Microsoft.AspNetCore.Builder;
 using Microsoft.AspNetCore.Builder;
 using Microsoft.AspNetCore.Hosting;
 using Microsoft.AspNetCore.Hosting;
+using Microsoft.Extensions.Configuration;
 using Microsoft.Extensions.DependencyInjection;
 using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.FileProviders;
 using Microsoft.Extensions.Hosting;
 using Microsoft.Extensions.Hosting;
 using Prometheus;
 using Prometheus;
 
 
@@ -50,9 +53,7 @@ namespace Jellyfin.Server
             {
             {
                 options.HttpsPort = _serverApplicationHost.HttpsPort;
                 options.HttpsPort = _serverApplicationHost.HttpsPort;
             });
             });
-            services.AddJellyfinApi(
-                _serverConfigurationManager.Configuration.BaseUrl.TrimStart('/'),
-                _serverApplicationHost.GetApiPluginAssemblies());
+            services.AddJellyfinApi(_serverApplicationHost.GetApiPluginAssemblies());
 
 
             services.AddJellyfinApiSwagger();
             services.AddJellyfinApiSwagger();
 
 
@@ -87,57 +88,78 @@ namespace Jellyfin.Server
         /// </summary>
         /// </summary>
         /// <param name="app">The application builder.</param>
         /// <param name="app">The application builder.</param>
         /// <param name="env">The webhost environment.</param>
         /// <param name="env">The webhost environment.</param>
+        /// <param name="appConfig">The application config.</param>
         public void Configure(
         public void Configure(
             IApplicationBuilder app,
             IApplicationBuilder app,
-            IWebHostEnvironment env)
+            IWebHostEnvironment env,
+            IConfiguration appConfig)
         {
         {
-            if (env.IsDevelopment())
+            // Only add base url redirection if a base url is set.
+            if (!string.IsNullOrEmpty(_serverConfigurationManager.Configuration.BaseUrl))
             {
             {
-                app.UseDeveloperExceptionPage();
+                app.UseBaseUrlRedirection();
             }
             }
 
 
-            app.UseMiddleware<ExceptionMiddleware>();
+            // Wrap rest of configuration so everything only listens on BaseUrl.
+            app.Map(_serverConfigurationManager.Configuration.BaseUrl, mainApp =>
+            {
+                if (env.IsDevelopment())
+                {
+                    mainApp.UseDeveloperExceptionPage();
+                }
 
 
-            app.UseMiddleware<ResponseTimeMiddleware>();
+                mainApp.UseMiddleware<ExceptionMiddleware>();
 
 
-            app.UseWebSockets();
+                mainApp.UseMiddleware<ResponseTimeMiddleware>();
 
 
-            app.UseResponseCompression();
+                mainApp.UseWebSockets();
 
 
-            app.UseCors(ServerCorsPolicy.DefaultPolicyName);
+                mainApp.UseResponseCompression();
 
 
-            if (_serverConfigurationManager.Configuration.RequireHttps
-                && _serverApplicationHost.ListenWithHttps)
-            {
-                app.UseHttpsRedirection();
-            }
+                mainApp.UseCors(ServerCorsPolicy.DefaultPolicyName);
 
 
-            app.UseStaticFiles();
-            app.UseAuthentication();
-            app.UseJellyfinApiSwagger(_serverConfigurationManager);
-            app.UseRouting();
-            app.UseAuthorization();
-            if (_serverConfigurationManager.Configuration.EnableMetrics)
-            {
-                // Must be registered after any middleware that could chagne HTTP response codes or the data will be bad
-                app.UseHttpMetrics();
-            }
+                if (_serverConfigurationManager.Configuration.RequireHttps
+                    && _serverApplicationHost.ListenWithHttps)
+                {
+                    mainApp.UseHttpsRedirection();
+                }
 
 
-            app.UseLanFiltering();
-            app.UseIpBasedAccessValidation();
-            app.UseBaseUrlRedirection();
-            app.UseWebSocketHandler();
-            app.UseServerStartupMessage();
+                mainApp.UseStaticFiles();
+                if (appConfig.HostWebClient())
+                {
+                    mainApp.UseStaticFiles(new StaticFileOptions
+                    {
+                        FileProvider = new PhysicalFileProvider(_serverConfigurationManager.ApplicationPaths.WebPath),
+                        RequestPath = "/web"
+                    });
+                }
+
+                mainApp.UseAuthentication();
+                mainApp.UseJellyfinApiSwagger(_serverConfigurationManager);
+                mainApp.UseRouting();
+                mainApp.UseAuthorization();
+
+                mainApp.UseLanFiltering();
+                mainApp.UseIpBasedAccessValidation();
+                mainApp.UseWebSocketHandler();
+                mainApp.UseServerStartupMessage();
 
 
-            app.UseEndpoints(endpoints =>
-            {
-                endpoints.MapControllers();
                 if (_serverConfigurationManager.Configuration.EnableMetrics)
                 if (_serverConfigurationManager.Configuration.EnableMetrics)
                 {
                 {
-                    endpoints.MapMetrics(_serverConfigurationManager.Configuration.BaseUrl.TrimStart('/') + "/metrics");
+                    // Must be registered after any middleware that could change HTTP response codes or the data will be bad
+                    mainApp.UseHttpMetrics();
                 }
                 }
 
 
-                endpoints.MapHealthChecks(_serverConfigurationManager.Configuration.BaseUrl.TrimStart('/') + "/health");
+                mainApp.UseEndpoints(endpoints =>
+                {
+                    endpoints.MapControllers();
+                    if (_serverConfigurationManager.Configuration.EnableMetrics)
+                    {
+                        endpoints.MapMetrics("/metrics");
+                    }
+
+                    endpoints.MapHealthChecks("/health");
+                });
             });
             });
 
 
             // Add type descriptor for legacy datetime parsing.
             // Add type descriptor for legacy datetime parsing.

+ 1 - 4
MediaBrowser.Common/Configuration/IApplicationPaths.cs

@@ -1,5 +1,3 @@
-using MediaBrowser.Model.Configuration;
-
 namespace MediaBrowser.Common.Configuration
 namespace MediaBrowser.Common.Configuration
 {
 {
     /// <summary>
     /// <summary>
@@ -17,8 +15,7 @@ namespace MediaBrowser.Common.Configuration
         /// Gets the path to the web UI resources folder.
         /// Gets the path to the web UI resources folder.
         /// </summary>
         /// </summary>
         /// <remarks>
         /// <remarks>
-        /// This value is not relevant if the server is configured to not host any static web content. Additionally,
-        /// the value for <see cref="ServerConfiguration.DashboardSourcePath"/> takes precedence over this one.
+        /// This value is not relevant if the server is configured to not host any static web content.
         /// </remarks>
         /// </remarks>
         string WebPath { get; }
         string WebPath { get; }
 
 

+ 0 - 6
MediaBrowser.Model/Configuration/ServerConfiguration.cs

@@ -166,12 +166,6 @@ namespace MediaBrowser.Model.Configuration
         /// <value><c>true</c> if [enable dashboard response caching]; otherwise, <c>false</c>.</value>
         /// <value><c>true</c> if [enable dashboard response caching]; otherwise, <c>false</c>.</value>
         public bool EnableDashboardResponseCaching { get; set; }
         public bool EnableDashboardResponseCaching { get; set; }
 
 
-        /// <summary>
-        /// Gets or sets a custom path to serve the dashboard from.
-        /// </summary>
-        /// <value>The dashboard source path, or null if the default path should be used.</value>
-        public string DashboardSourcePath { get; set; }
-
         /// <summary>
         /// <summary>
         /// Gets or sets the image saving convention.
         /// Gets or sets the image saving convention.
         /// </summary>
         /// </summary>