Merge remote-tracking branch 'upstream/master' into support-running-without-web-content

This commit is contained in:
Mark Monteiro
2020-03-15 18:07:02 +01:00
469 changed files with 521 additions and 648 deletions

View File

@@ -1,3 +1,5 @@
#pragma warning disable CS1591
using MediaBrowser.Common.Plugins;
using MediaBrowser.Controller.Plugins;
using MediaBrowser.Model.Plugins;
@@ -6,29 +8,6 @@ namespace MediaBrowser.WebDashboard.Api
{
public class ConfigurationPageInfo
{
/// <summary>
/// Gets the name.
/// </summary>
/// <value>The name.</value>
public string Name { get; set; }
public bool EnableInMainMenu { get; set; }
public string MenuSection { get; set; }
public string MenuIcon { get; set; }
public string DisplayName { get; set; }
/// <summary>
/// Gets the type of the configuration page.
/// </summary>
/// <value>The type of the configuration page.</value>
public ConfigurationPageType ConfigurationPageType { get; set; }
/// <summary>
/// Gets or sets the plugin id.
/// </summary>
/// <value>The plugin id.</value>
public string PluginId { get; set; }
public ConfigurationPageInfo(IPluginConfigurationPage page)
{
Name = page.Name;
@@ -54,5 +33,31 @@ namespace MediaBrowser.WebDashboard.Api
// Don't use "N" because it needs to match Plugin.Id
PluginId = plugin.Id.ToString();
}
/// <summary>
/// Gets or sets the name.
/// </summary>
/// <value>The name.</value>
public string Name { get; set; }
public bool EnableInMainMenu { get; set; }
public string MenuSection { get; set; }
public string MenuIcon { get; set; }
public string DisplayName { get; set; }
/// <summary>
/// Gets or sets the type of the configuration page.
/// </summary>
/// <value>The type of the configuration page.</value>
public ConfigurationPageType ConfigurationPageType { get; set; }
/// <summary>
/// Gets or sets the plugin id.
/// </summary>
/// <value>The plugin id.</value>
public string PluginId { get; set; }
}
}

View File

@@ -1,5 +1,10 @@
#pragma warning disable CS1591
#pragma warning disable SA1402
#pragma warning disable SA1649
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
@@ -20,7 +25,7 @@ using Microsoft.Extensions.Logging;
namespace MediaBrowser.WebDashboard.Api
{
/// <summary>
/// Class GetDashboardConfigurationPages
/// Class GetDashboardConfigurationPages.
/// </summary>
[Route("/web/ConfigurationPages", "GET")]
public class GetDashboardConfigurationPages : IReturn<List<ConfigurationPageInfo>>
@@ -30,11 +35,12 @@ namespace MediaBrowser.WebDashboard.Api
/// </summary>
/// <value>The type of the page.</value>
public ConfigurationPageType? PageType { get; set; }
public bool? EnableInMainMenu { get; set; }
}
/// <summary>
/// Class GetDashboardConfigurationPage
/// Class GetDashboardConfigurationPage.
/// </summary>
[Route("/web/ConfigurationPage", "GET")]
public class GetDashboardConfigurationPage
@@ -58,7 +64,7 @@ namespace MediaBrowser.WebDashboard.Api
}
/// <summary>
/// Class GetDashboardResource
/// Class GetDashboardResource.
/// </summary>
[Route("/web/{ResourceName*}", "GET", IsHidden = true)]
public class GetDashboardResource
@@ -68,6 +74,7 @@ namespace MediaBrowser.WebDashboard.Api
/// </summary>
/// <value>The name.</value>
public string ResourceName { get; set; }
/// <summary>
/// Gets or sets the V.
/// </summary>
@@ -81,7 +88,7 @@ namespace MediaBrowser.WebDashboard.Api
}
/// <summary>
/// Class DashboardService
/// Class DashboardService.
/// </summary>
public class DashboardService : IService, IRequiresRequest
{
@@ -96,46 +103,38 @@ namespace MediaBrowser.WebDashboard.Api
/// </summary>
/// <value>The HTTP result factory.</value>
private readonly IHttpResultFactory _resultFactory;
/// <summary>
/// Gets or sets the request context.
/// </summary>
/// <value>The request context.</value>
public IRequest Request { get; set; }
/// <summary>
/// The _app host
/// </summary>
private readonly IServerApplicationHost _appHost;
/// <summary>
/// The _server configuration manager
/// </summary>
private readonly IServerConfigurationManager _serverConfigurationManager;
private readonly IFileSystem _fileSystem;
private IResourceFileManager _resourceFileManager;
private readonly IConfiguration _appConfig;
private readonly IServerConfigurationManager _serverConfigurationManager;
private readonly IFileSystem _fileSystem;
private readonly IResourceFileManager _resourceFileManager;
/// <summary>
/// Initializes a new instance of the <see cref="DashboardService" /> class.
/// </summary>
/// <param name="logger">The logger.</param>
/// <param name="appHost">The application host.</param>
/// <param name="appConfig">The application configuration.</param>
/// <param name="resourceFileManager">The resource file manager.</param>
/// <param name="serverConfigurationManager">The server configuration manager.</param>
/// <param name="fileSystem">The file system.</param>
/// <param name="resultFactory">The result factory.</param>
public DashboardService(
ILogger<DashboardService> logger,
IServerApplicationHost appHost,
IConfiguration appConfig,
IResourceFileManager resourceFileManager,
IServerConfigurationManager serverConfigurationManager,
IFileSystem fileSystem,
ILogger<DashboardService> logger,
IHttpResultFactory resultFactory,
IConfiguration appConfig)
IHttpResultFactory resultFactory)
{
_logger = logger;
_appHost = appHost;
_appConfig = appConfig;
_resourceFileManager = resourceFileManager;
_serverConfigurationManager = serverConfigurationManager;
_fileSystem = fileSystem;
_logger = logger;
_resultFactory = resultFactory;
_resourceFileManager = resourceFileManager;
_appConfig = appConfig;
// Validate web content path
string webContentPath = DashboardUIPath;
@@ -149,6 +148,12 @@ namespace MediaBrowser.WebDashboard.Api
}
}
/// <summary>
/// Gets or sets the request context.
/// </summary>
/// <value>The request context.</value>
public IRequest Request { get; set; }
/// <summary>
/// Gets the path of the directory containing the static web interface content, or null if the server is not
/// hosting the static web content.
@@ -171,6 +176,7 @@ namespace MediaBrowser.WebDashboard.Api
}
}
[SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "request", Justification = "Required for ServiceStack")]
public object Get(GetFavIcon request)
{
return Get(new GetDashboardResource
@@ -184,6 +190,7 @@ namespace MediaBrowser.WebDashboard.Api
/// </summary>
/// <param name="request">The request.</param>
/// <returns>System.Object.</returns>
[SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "request", Justification = "Required for ServiceStack")]
public Task<object> Get(GetDashboardConfigurationPage request)
{
IPlugin plugin = null;
@@ -208,7 +215,7 @@ namespace MediaBrowser.WebDashboard.Api
stream = plugin.GetType().Assembly.GetManifestResourceStream(altPage.Item1.EmbeddedResourcePath);
isJs = string.Equals(Path.GetExtension(altPage.Item1.EmbeddedResourcePath), ".js", StringComparison.OrdinalIgnoreCase);
isTemplate = altPage.Item1.EmbeddedResourcePath.EndsWith(".template.html");
isTemplate = altPage.Item1.EmbeddedResourcePath.EndsWith(".template.html", StringComparison.Ordinal);
}
}
@@ -256,7 +263,6 @@ namespace MediaBrowser.WebDashboard.Api
// Don't allow a failing plugin to fail them all
var configPages = pages.Select(p =>
{
try
{
return new ConfigurationPageInfo(p);
@@ -307,6 +313,7 @@ namespace MediaBrowser.WebDashboard.Api
return GetPluginPages(plugin).Select(i => new ConfigurationPageInfo(plugin, i.Item1));
}
[SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "request", Justification = "Required for ServiceStack")]
public object Get(GetRobotsTxt request)
{
return Get(new GetDashboardResource
@@ -374,7 +381,7 @@ namespace MediaBrowser.WebDashboard.Api
return await _resultFactory.GetStaticResult(Request, cacheKey, null, cacheDuration, contentType, () => GetResourceStream(basePath, path, localizationCulture)).ConfigureAwait(false);
}
return await _resultFactory.GetStaticFileResult(Request, _resourceFileManager.GetResourcePath(basePath, path));
return await _resultFactory.GetStaticFileResult(Request, _resourceFileManager.GetResourcePath(basePath, path)).ConfigureAwait(false);
}
private string GetLocalizationCulture()
@@ -421,9 +428,9 @@ namespace MediaBrowser.WebDashboard.Api
{
Directory.Delete(targetPath, true);
}
catch (IOException)
catch (IOException ex)
{
_logger.LogError(ex, "Error deleting {Path}", targetPath);
}
CopyDirectory(inputPath, targetPath);
@@ -431,9 +438,9 @@ namespace MediaBrowser.WebDashboard.Api
var appVersion = _appHost.ApplicationVersionString;
await DumpHtml(packageCreator, inputPath, targetPath, mode, appVersion);
await DumpHtml(packageCreator, inputPath, targetPath, mode, appVersion).ConfigureAwait(false);
return "";
return string.Empty;
}
private async Task DumpHtml(PackageCreator packageCreator, string source, string destination, string mode, string appVersion)
@@ -456,7 +463,7 @@ namespace MediaBrowser.WebDashboard.Api
using (var stream = await packageCreator.GetResource(resourceVirtualPath, mode, null, appVersion).ConfigureAwait(false))
using (var fs = new FileStream(destinationFilePath, FileMode.Create, FileAccess.Write, FileShare.Read))
{
await stream.CopyToAsync(fs);
await stream.CopyToAsync(fs).ConfigureAwait(false);
}
}
@@ -464,14 +471,17 @@ namespace MediaBrowser.WebDashboard.Api
{
Directory.CreateDirectory(destination);
//Now Create all of the directories
// Now Create all of the directories
foreach (var dirPath in _fileSystem.GetDirectories(source, true))
Directory.CreateDirectory(dirPath.FullName.Replace(source, destination));
{
Directory.CreateDirectory(dirPath.FullName.Replace(source, destination, StringComparison.Ordinal));
}
//Copy all the files & Replaces any files with the same name
// Copy all the files & Replaces any files with the same name
foreach (var newPath in _fileSystem.GetFiles(source, true))
File.Copy(newPath.FullName, newPath.FullName.Replace(source, destination), true);
{
File.Copy(newPath.FullName, newPath.FullName.Replace(source, destination, StringComparison.Ordinal), true);
}
}
}
}

View File

@@ -1,4 +1,7 @@
#pragma warning disable CS1591
using System;
using System.Globalization;
using System.IO;
using System.Text;
using System.Threading.Tasks;
@@ -48,6 +51,11 @@ namespace MediaBrowser.WebDashboard.Api
/// <summary>
/// Modifies the source HTML stream by adding common meta tags, css and js.
/// </summary>
/// <param name="isMainIndexPage">True if the stream contains content for the main index page.</param>
/// <param name="sourceStream">The stream whose content should be modified.</param>
/// <param name="mode">The client mode ('cordova', 'android', etc).</param>
/// <param name="appVersion">The application version.</param>
/// <param name="localizationCulture">The localization culture.</param>
/// <returns>
/// A task that represents the async operation to read and modify the input stream.
/// The task result contains a stream containing the modified HTML content.
@@ -69,30 +77,29 @@ namespace MediaBrowser.WebDashboard.Api
{
var lang = localizationCulture.Split('-')[0];
html = html.Replace("<html", "<html data-culture=\"" + localizationCulture + "\" lang=\"" + lang + "\"");
html = html.Replace("<html", "<html data-culture=\"" + localizationCulture + "\" lang=\"" + lang + "\"", StringComparison.Ordinal);
}
if (isMainIndexPage)
{
html = html.Replace("<head>", "<head>" + GetMetaTags(mode));
html = html.Replace("<head>", "<head>" + GetMetaTags(mode), StringComparison.Ordinal);
}
// Disable embedded scripts from plugins. We'll run them later once resources have loaded
if (html.IndexOf("<script", StringComparison.OrdinalIgnoreCase) != -1)
{
html = html.Replace("<script", "<!--<script");
html = html.Replace("</script>", "</script>-->");
html = html.Replace("<script", "<!--<script", StringComparison.Ordinal);
html = html.Replace("</script>", "</script>-->", StringComparison.Ordinal);
}
if (isMainIndexPage)
{
html = html.Replace("</body>", GetCommonJavascript(mode, appVersion) + "</body>");
html = html.Replace("</body>", GetCommonJavascript(mode, appVersion) + "</body>", StringComparison.Ordinal);
}
var bytes = Encoding.UTF8.GetBytes(html);
return new MemoryStream(bytes);
}
/// <summary>
@@ -125,11 +132,11 @@ namespace MediaBrowser.WebDashboard.Api
builder.Append("<script>");
if (!string.IsNullOrWhiteSpace(mode))
{
builder.AppendFormat("window.appMode='{0}';", mode);
builder.AppendFormat(CultureInfo.InvariantCulture, "window.appMode='{0}';", mode);
}
else
{
builder.AppendFormat("window.dashboardVersion='{0}';", version);
builder.AppendFormat(CultureInfo.InvariantCulture, "window.dashboardVersion='{0}';", version);
}
builder.Append("</script>");

View File

@@ -19,6 +19,19 @@
<TargetFramework>netstandard2.1</TargetFramework>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>
<!-- Code Analyzers-->
<ItemGroup Condition=" '$(Configuration)' == 'Debug' ">
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.9.8" PrivateAssets="All" />
<PackageReference Include="SerilogAnalyzer" Version="0.15.0" PrivateAssets="All" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="All" />
<PackageReference Include="SmartAnalyzers.MultithreadingAnalyzer" Version="1.1.31" PrivateAssets="All" />
</ItemGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<CodeAnalysisRuleSet>../jellyfin.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
</Project>

View File

@@ -1,3 +1,5 @@
#pragma warning disable CS1591
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
@@ -6,24 +8,25 @@ using MediaBrowser.Controller.Plugins;
namespace MediaBrowser.WebDashboard
{
public class ServerEntryPoint : IServerEntryPoint
public sealed class ServerEntryPoint : IServerEntryPoint
{
/// <summary>
/// Gets the list of plugin configuration pages
/// </summary>
/// <value>The configuration pages.</value>
public List<IPluginConfigurationPage> PluginConfigurationPages { get; private set; }
private readonly IApplicationHost _appHost;
public static ServerEntryPoint Instance { get; private set; }
public ServerEntryPoint(IApplicationHost appHost)
{
_appHost = appHost;
Instance = this;
}
public static ServerEntryPoint Instance { get; private set; }
/// <summary>
/// Gets the list of plugin configuration pages.
/// </summary>
/// <value>The configuration pages.</value>
public List<IPluginConfigurationPage> PluginConfigurationPages { get; private set; }
/// <inheritdoc />
public Task RunAsync()
{
PluginConfigurationPages = _appHost.GetExports<IPluginConfigurationPage>().ToList();
@@ -31,6 +34,7 @@ namespace MediaBrowser.WebDashboard
return Task.CompletedTask;
}
/// <inheritdoc />
public void Dispose()
{
}