mirror of
https://github.com/jellyfin/jellyfin.git
synced 2026-02-19 02:52:28 +00:00
Merge branch 'master' into keyframe_extraction_v1
# Conflicts: # Jellyfin.Api/Controllers/DynamicHlsController.cs # MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs # MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
This commit is contained in:
@@ -22,7 +22,6 @@ using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Net;
|
||||
using MediaBrowser.Controller.Security;
|
||||
using MediaBrowser.Model.Activity;
|
||||
using MediaBrowser.Model.IO;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
@@ -42,67 +41,61 @@ namespace Jellyfin.Server
|
||||
/// <param name="loggerFactory">The <see cref="ILoggerFactory" /> to be used by the <see cref="CoreAppHost" />.</param>
|
||||
/// <param name="options">The <see cref="StartupOptions" /> to be used by the <see cref="CoreAppHost" />.</param>
|
||||
/// <param name="startupConfig">The <see cref="IConfiguration" /> to be used by the <see cref="CoreAppHost" />.</param>
|
||||
/// <param name="fileSystem">The <see cref="IFileSystem" /> to be used by the <see cref="CoreAppHost" />.</param>
|
||||
/// <param name="collection">The <see cref="IServiceCollection"/> to be used by the <see cref="CoreAppHost"/>.</param>
|
||||
public CoreAppHost(
|
||||
IServerApplicationPaths applicationPaths,
|
||||
ILoggerFactory loggerFactory,
|
||||
IStartupOptions options,
|
||||
IConfiguration startupConfig,
|
||||
IFileSystem fileSystem,
|
||||
IServiceCollection collection)
|
||||
IConfiguration startupConfig)
|
||||
: base(
|
||||
applicationPaths,
|
||||
loggerFactory,
|
||||
options,
|
||||
startupConfig,
|
||||
fileSystem,
|
||||
collection)
|
||||
startupConfig)
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void RegisterServices()
|
||||
protected override void RegisterServices(IServiceCollection serviceCollection)
|
||||
{
|
||||
// Register an image encoder
|
||||
bool useSkiaEncoder = SkiaEncoder.IsNativeLibAvailable();
|
||||
Type imageEncoderType = useSkiaEncoder
|
||||
? typeof(SkiaEncoder)
|
||||
: typeof(NullImageEncoder);
|
||||
ServiceCollection.AddSingleton(typeof(IImageEncoder), imageEncoderType);
|
||||
serviceCollection.AddSingleton(typeof(IImageEncoder), imageEncoderType);
|
||||
|
||||
// Log a warning if the Skia encoder could not be used
|
||||
if (!useSkiaEncoder)
|
||||
{
|
||||
Logger.LogWarning($"Skia not available. Will fallback to {nameof(NullImageEncoder)}.");
|
||||
Logger.LogWarning("Skia not available. Will fallback to {ImageEncoder}.", nameof(NullImageEncoder));
|
||||
}
|
||||
|
||||
ServiceCollection.AddDbContextPool<JellyfinDb>(
|
||||
serviceCollection.AddDbContextPool<JellyfinDb>(
|
||||
options => options
|
||||
.UseLoggerFactory(LoggerFactory)
|
||||
.UseSqlite($"Filename={Path.Combine(ApplicationPaths.DataPath, "jellyfin.db")}"));
|
||||
|
||||
ServiceCollection.AddEventServices();
|
||||
ServiceCollection.AddSingleton<IBaseItemManager, BaseItemManager>();
|
||||
ServiceCollection.AddSingleton<IEventManager, EventManager>();
|
||||
ServiceCollection.AddSingleton<JellyfinDbProvider>();
|
||||
serviceCollection.AddEventServices();
|
||||
serviceCollection.AddSingleton<IBaseItemManager, BaseItemManager>();
|
||||
serviceCollection.AddSingleton<IEventManager, EventManager>();
|
||||
serviceCollection.AddSingleton<JellyfinDbProvider>();
|
||||
|
||||
ServiceCollection.AddSingleton<IActivityManager, ActivityManager>();
|
||||
ServiceCollection.AddSingleton<IUserManager, UserManager>();
|
||||
ServiceCollection.AddSingleton<IDisplayPreferencesManager, DisplayPreferencesManager>();
|
||||
ServiceCollection.AddSingleton<IDeviceManager, DeviceManager>();
|
||||
serviceCollection.AddSingleton<IActivityManager, ActivityManager>();
|
||||
serviceCollection.AddSingleton<IUserManager, UserManager>();
|
||||
serviceCollection.AddSingleton<IDisplayPreferencesManager, DisplayPreferencesManager>();
|
||||
serviceCollection.AddSingleton<IDeviceManager, DeviceManager>();
|
||||
|
||||
// TODO search the assemblies instead of adding them manually?
|
||||
ServiceCollection.AddSingleton<IWebSocketListener, SessionWebSocketListener>();
|
||||
ServiceCollection.AddSingleton<IWebSocketListener, ActivityLogWebSocketListener>();
|
||||
ServiceCollection.AddSingleton<IWebSocketListener, ScheduledTasksWebSocketListener>();
|
||||
ServiceCollection.AddSingleton<IWebSocketListener, SessionInfoWebSocketListener>();
|
||||
serviceCollection.AddSingleton<IWebSocketListener, SessionWebSocketListener>();
|
||||
serviceCollection.AddSingleton<IWebSocketListener, ActivityLogWebSocketListener>();
|
||||
serviceCollection.AddSingleton<IWebSocketListener, ScheduledTasksWebSocketListener>();
|
||||
serviceCollection.AddSingleton<IWebSocketListener, SessionInfoWebSocketListener>();
|
||||
|
||||
ServiceCollection.AddSingleton<IAuthorizationContext, AuthorizationContext>();
|
||||
serviceCollection.AddSingleton<IAuthorizationContext, AuthorizationContext>();
|
||||
|
||||
ServiceCollection.AddScoped<IAuthenticationManager, AuthenticationManager>();
|
||||
serviceCollection.AddScoped<IAuthenticationManager, AuthenticationManager>();
|
||||
|
||||
base.RegisterServices();
|
||||
base.RegisterServices(serviceCollection);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -7,6 +7,7 @@ using System.Net.Sockets;
|
||||
using System.Reflection;
|
||||
using Emby.Server.Implementations;
|
||||
using Jellyfin.Api.Auth;
|
||||
using Jellyfin.Api.Auth.AnonymousLanAccessPolicy;
|
||||
using Jellyfin.Api.Auth.DefaultAuthorizationPolicy;
|
||||
using Jellyfin.Api.Auth.DownloadPolicy;
|
||||
using Jellyfin.Api.Auth.FirstTimeOrIgnoreParentalControlSetupPolicy;
|
||||
@@ -61,6 +62,7 @@ namespace Jellyfin.Server.Extensions
|
||||
serviceCollection.AddSingleton<IAuthorizationHandler, IgnoreParentalControlHandler>();
|
||||
serviceCollection.AddSingleton<IAuthorizationHandler, FirstTimeOrIgnoreParentalControlSetupHandler>();
|
||||
serviceCollection.AddSingleton<IAuthorizationHandler, LocalAccessHandler>();
|
||||
serviceCollection.AddSingleton<IAuthorizationHandler, AnonymousLanAccessHandler>();
|
||||
serviceCollection.AddSingleton<IAuthorizationHandler, LocalAccessOrRequiresElevationHandler>();
|
||||
serviceCollection.AddSingleton<IAuthorizationHandler, RequiresElevationHandler>();
|
||||
serviceCollection.AddSingleton<IAuthorizationHandler, SyncPlayAccessHandler>();
|
||||
@@ -157,6 +159,13 @@ namespace Jellyfin.Server.Extensions
|
||||
policy.AddAuthenticationSchemes(AuthenticationSchemes.CustomAuthentication);
|
||||
policy.AddRequirements(new SyncPlayAccessRequirement(SyncPlayAccessRequirementType.IsInGroup));
|
||||
});
|
||||
options.AddPolicy(
|
||||
Policies.AnonymousLanAccessPolicy,
|
||||
policy =>
|
||||
{
|
||||
policy.AddAuthenticationSchemes(AuthenticationSchemes.CustomAuthentication);
|
||||
policy.AddRequirements(new AnonymousLanAccessRequirement());
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -188,7 +197,8 @@ namespace Jellyfin.Server.Extensions
|
||||
// https://github.com/dotnet/aspnetcore/blob/master/src/Middleware/HttpOverrides/src/ForwardedHeadersMiddleware.cs
|
||||
// Enable debug logging on Microsoft.AspNetCore.HttpOverrides.ForwardedHeadersMiddleware to help investigate issues.
|
||||
|
||||
options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
|
||||
options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto | ForwardedHeaders.XForwardedHost;
|
||||
|
||||
if (config.KnownProxies.Length == 0)
|
||||
{
|
||||
options.KnownNetworks.Clear();
|
||||
@@ -406,6 +416,18 @@ namespace Jellyfin.Server.Extensions
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
// Support dictionary with nullable string value.
|
||||
options.MapType<Dictionary<string, string?>>(() =>
|
||||
new OpenApiSchema
|
||||
{
|
||||
Type = "object",
|
||||
AdditionalProperties = new OpenApiSchema
|
||||
{
|
||||
Type = "string",
|
||||
Nullable = true
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,4 +75,4 @@ namespace Jellyfin.Server.Filters
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,6 @@ using System;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Model.IO;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Http.Extensions;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
@@ -14,6 +14,10 @@
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
|
||||
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="..\SharedVersion.cs" />
|
||||
</ItemGroup>
|
||||
@@ -25,26 +29,26 @@
|
||||
<!-- Code Analyzers-->
|
||||
<ItemGroup Condition=" '$(Configuration)' == 'Debug' ">
|
||||
<PackageReference Include="SerilogAnalyzer" Version="0.15.0" PrivateAssets="All" />
|
||||
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="All" />
|
||||
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.376" PrivateAssets="All" />
|
||||
<PackageReference Include="SmartAnalyzers.MultithreadingAnalyzer" Version="1.1.31" PrivateAssets="All" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="CommandLineParser" Version="2.8.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks" Version="5.0.10" />
|
||||
<PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore" Version="5.0.10" />
|
||||
<PackageReference Include="prometheus-net" Version="5.0.1" />
|
||||
<PackageReference Include="prometheus-net.AspNetCore" Version="5.0.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks" Version="6.0.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore" Version="6.0.1" />
|
||||
<PackageReference Include="prometheus-net" Version="5.0.2" />
|
||||
<PackageReference Include="prometheus-net.AspNetCore" Version="5.0.2" />
|
||||
<PackageReference Include="Serilog.AspNetCore" Version="4.1.0" />
|
||||
<PackageReference Include="Serilog.Enrichers.Thread" Version="3.1.0" />
|
||||
<PackageReference Include="Serilog.Settings.Configuration" Version="3.2.0" />
|
||||
<PackageReference Include="Serilog.Settings.Configuration" Version="3.3.0" />
|
||||
<PackageReference Include="Serilog.Sinks.Async" Version="1.5.0" />
|
||||
<PackageReference Include="Serilog.Sinks.Console" Version="4.0.0" />
|
||||
<PackageReference Include="Serilog.Sinks.Console" Version="4.0.1" />
|
||||
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
|
||||
<PackageReference Include="Serilog.Sinks.Graylog" Version="2.2.2" />
|
||||
<PackageReference Include="SQLitePCLRaw.bundle_e_sqlite3" Version="2.0.6" />
|
||||
<PackageReference Include="Serilog.Sinks.Graylog" Version="2.3.0" />
|
||||
<PackageReference Include="SQLitePCLRaw.bundle_e_sqlite3" Version="2.0.7" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -51,4 +51,4 @@ namespace Jellyfin.Server.Middleware
|
||||
await _next(httpContext).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@ namespace Jellyfin.Server.Middleware
|
||||
if (_enableWarning && watch.ElapsedMilliseconds > _warningThreshold)
|
||||
{
|
||||
_logger.LogWarning(
|
||||
"Slow HTTP Response from {url} to {remoteIp} in {elapsed:g} with Status Code {statusCode}",
|
||||
"Slow HTTP Response from {Url} to {RemoteIp} in {Elapsed:g} with Status Code {StatusCode}",
|
||||
context.Request.GetDisplayUrl(),
|
||||
context.GetNormalizedRemoteIp(),
|
||||
watch.Elapsed,
|
||||
|
||||
@@ -44,4 +44,4 @@ namespace Jellyfin.Server.Middleware
|
||||
await _next(httpContext).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using Jellyfin.Extensions;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Http.Features;
|
||||
@@ -52,7 +51,7 @@ namespace Jellyfin.Server.Middleware
|
||||
return;
|
||||
}
|
||||
|
||||
if (!key.Contains('='))
|
||||
if (!key.Contains('=', StringComparison.Ordinal))
|
||||
{
|
||||
_store = value;
|
||||
return;
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Emby.Server.Implementations;
|
||||
using Emby.Server.Implementations.Serialization;
|
||||
using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Model.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
@@ -11,6 +16,14 @@ namespace Jellyfin.Server.Migrations
|
||||
/// </summary>
|
||||
public sealed class MigrationRunner
|
||||
{
|
||||
/// <summary>
|
||||
/// The list of known pre-startup migrations, in order of applicability.
|
||||
/// </summary>
|
||||
private static readonly Type[] _preStartupMigrationTypes =
|
||||
{
|
||||
typeof(PreStartupRoutines.CreateNetworkConfiguration)
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// The list of known migrations, in order of applicability.
|
||||
/// </summary>
|
||||
@@ -41,17 +54,55 @@ namespace Jellyfin.Server.Migrations
|
||||
.Select(m => ActivatorUtilities.CreateInstance(host.ServiceProvider, m))
|
||||
.OfType<IMigrationRoutine>()
|
||||
.ToArray();
|
||||
var migrationOptions = host.ConfigurationManager.GetConfiguration<MigrationOptions>(MigrationsListStore.StoreKey);
|
||||
|
||||
if (!host.ConfigurationManager.Configuration.IsStartupWizardCompleted && migrationOptions.Applied.Count == 0)
|
||||
var migrationOptions = host.ConfigurationManager.GetConfiguration<MigrationOptions>(MigrationsListStore.StoreKey);
|
||||
HandleStartupWizardCondition(migrations, migrationOptions, host.ConfigurationManager.Configuration.IsStartupWizardCompleted, logger);
|
||||
PerformMigrations(migrations, migrationOptions, options => host.ConfigurationManager.SaveConfiguration(MigrationsListStore.StoreKey, options), logger);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Run all needed pre-startup migrations.
|
||||
/// </summary>
|
||||
/// <param name="appPaths">Application paths.</param>
|
||||
/// <param name="loggerFactory">Factory for making the logger.</param>
|
||||
public static void RunPreStartup(ServerApplicationPaths appPaths, ILoggerFactory loggerFactory)
|
||||
{
|
||||
var logger = loggerFactory.CreateLogger<MigrationRunner>();
|
||||
var migrations = _preStartupMigrationTypes
|
||||
.Select(m => Activator.CreateInstance(m, appPaths, loggerFactory))
|
||||
.OfType<IMigrationRoutine>()
|
||||
.ToArray();
|
||||
|
||||
var xmlSerializer = new MyXmlSerializer();
|
||||
var migrationConfigPath = Path.Join(appPaths.ConfigurationDirectoryPath, MigrationsListStore.StoreKey.ToLowerInvariant() + ".xml");
|
||||
var migrationOptions = File.Exists(migrationConfigPath)
|
||||
? (MigrationOptions)xmlSerializer.DeserializeFromFile(typeof(MigrationOptions), migrationConfigPath)!
|
||||
: new MigrationOptions();
|
||||
|
||||
// We have to deserialize it manually since the configuration manager may overwrite it
|
||||
var serverConfig = File.Exists(appPaths.SystemConfigurationFilePath)
|
||||
? (ServerConfiguration)xmlSerializer.DeserializeFromFile(typeof(ServerConfiguration), appPaths.SystemConfigurationFilePath)!
|
||||
: new ServerConfiguration();
|
||||
|
||||
HandleStartupWizardCondition(migrations, migrationOptions, serverConfig.IsStartupWizardCompleted, logger);
|
||||
PerformMigrations(migrations, migrationOptions, options => xmlSerializer.SerializeToFile(options, migrationConfigPath), logger);
|
||||
}
|
||||
|
||||
private static void HandleStartupWizardCondition(IEnumerable<IMigrationRoutine> migrations, MigrationOptions migrationOptions, bool isStartWizardCompleted, ILogger logger)
|
||||
{
|
||||
if (isStartWizardCompleted || migrationOptions.Applied.Count != 0)
|
||||
{
|
||||
// If startup wizard is not finished, this is a fresh install.
|
||||
// Don't run any migrations, just mark all of them as applied.
|
||||
logger.LogInformation("Marking all known migrations as applied because this is a fresh install");
|
||||
migrationOptions.Applied.AddRange(migrations.Where(m => !m.PerformOnNewInstall).Select(m => (m.Id, m.Name)));
|
||||
host.ConfigurationManager.SaveConfiguration(MigrationsListStore.StoreKey, migrationOptions);
|
||||
return;
|
||||
}
|
||||
|
||||
// If startup wizard is not finished, this is a fresh install.
|
||||
var onlyOldInstalls = migrations.Where(m => !m.PerformOnNewInstall).ToArray();
|
||||
logger.LogInformation("Marking following migrations as applied because this is a fresh install: {@OnlyOldInstalls}", onlyOldInstalls.Select(m => m.Name));
|
||||
migrationOptions.Applied.AddRange(onlyOldInstalls.Select(m => (m.Id, m.Name)));
|
||||
}
|
||||
|
||||
private static void PerformMigrations(IMigrationRoutine[] migrations, MigrationOptions migrationOptions, Action<MigrationOptions> saveConfiguration, ILogger logger)
|
||||
{
|
||||
var appliedMigrationIds = migrationOptions.Applied.Select(m => m.Id).ToHashSet();
|
||||
|
||||
for (var i = 0; i < migrations.Length; i++)
|
||||
@@ -78,7 +129,7 @@ namespace Jellyfin.Server.Migrations
|
||||
// Mark the migration as completed
|
||||
logger.LogInformation("Migration '{Name}' applied successfully", migrationRoutine.Name);
|
||||
migrationOptions.Applied.Add((migrationRoutine.Id, migrationRoutine.Name));
|
||||
host.ConfigurationManager.SaveConfiguration(MigrationsListStore.StoreKey, migrationOptions);
|
||||
saveConfiguration(migrationOptions);
|
||||
logger.LogDebug("Migration '{Name}' marked as applied in configuration.", migrationRoutine.Name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,138 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Xml;
|
||||
using System.Xml.Serialization;
|
||||
using Emby.Server.Implementations;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Jellyfin.Server.Migrations.PreStartupRoutines;
|
||||
|
||||
/// <inheritdoc />
|
||||
public class CreateNetworkConfiguration : IMigrationRoutine
|
||||
{
|
||||
private readonly ServerApplicationPaths _applicationPaths;
|
||||
private readonly ILogger<CreateNetworkConfiguration> _logger;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="CreateNetworkConfiguration"/> class.
|
||||
/// </summary>
|
||||
/// <param name="applicationPaths">An instance of <see cref="ServerApplicationPaths"/>.</param>
|
||||
/// <param name="loggerFactory">An instance of the <see cref="ILoggerFactory"/> interface.</param>
|
||||
public CreateNetworkConfiguration(ServerApplicationPaths applicationPaths, ILoggerFactory loggerFactory)
|
||||
{
|
||||
_applicationPaths = applicationPaths;
|
||||
_logger = loggerFactory.CreateLogger<CreateNetworkConfiguration>();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Guid Id => Guid.Parse("9B354818-94D5-4B68-AC49-E35CB85F9D84");
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Name => nameof(CreateNetworkConfiguration);
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool PerformOnNewInstall => false;
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Perform()
|
||||
{
|
||||
string path = Path.Combine(_applicationPaths.ConfigurationDirectoryPath, "network.xml");
|
||||
if (File.Exists(path))
|
||||
{
|
||||
_logger.LogDebug("Network configuration file already exists, skipping");
|
||||
return;
|
||||
}
|
||||
|
||||
var serverConfigSerializer = new XmlSerializer(typeof(OldNetworkConfiguration), new XmlRootAttribute("ServerConfiguration"));
|
||||
using var xmlReader = XmlReader.Create(_applicationPaths.SystemConfigurationFilePath);
|
||||
var networkSettings = serverConfigSerializer.Deserialize(xmlReader);
|
||||
|
||||
var networkConfigSerializer = new XmlSerializer(typeof(OldNetworkConfiguration), new XmlRootAttribute("NetworkConfiguration"));
|
||||
var xmlWriterSettings = new XmlWriterSettings { Indent = true };
|
||||
using var xmlWriter = XmlWriter.Create(path, xmlWriterSettings);
|
||||
networkConfigSerializer.Serialize(xmlWriter, networkSettings);
|
||||
}
|
||||
|
||||
#pragma warning disable
|
||||
public sealed class OldNetworkConfiguration
|
||||
{
|
||||
public const int DefaultHttpPort = 8096;
|
||||
|
||||
public const int DefaultHttpsPort = 8920;
|
||||
|
||||
private string _baseUrl = string.Empty;
|
||||
|
||||
public bool RequireHttps { get; set; }
|
||||
|
||||
public string CertificatePath { get; set; } = string.Empty;
|
||||
|
||||
public string CertificatePassword { get; set; } = string.Empty;
|
||||
|
||||
public string BaseUrl
|
||||
{
|
||||
get => _baseUrl;
|
||||
set
|
||||
{
|
||||
// Normalize the start of the string
|
||||
if (string.IsNullOrWhiteSpace(value))
|
||||
{
|
||||
// If baseUrl is empty, set an empty prefix string
|
||||
_baseUrl = string.Empty;
|
||||
return;
|
||||
}
|
||||
|
||||
if (value[0] != '/')
|
||||
{
|
||||
// If baseUrl was not configured with a leading slash, append one for consistency
|
||||
value = "/" + value;
|
||||
}
|
||||
|
||||
// Normalize the end of the string
|
||||
if (value[^1] == '/')
|
||||
{
|
||||
// If baseUrl was configured with a trailing slash, remove it for consistency
|
||||
value = value.Remove(value.Length - 1);
|
||||
}
|
||||
|
||||
_baseUrl = value;
|
||||
}
|
||||
}
|
||||
|
||||
public int PublicHttpsPort { get; set; } = DefaultHttpsPort;
|
||||
|
||||
public int HttpServerPortNumber { get; set; } = DefaultHttpPort;
|
||||
|
||||
public int HttpsPortNumber { get; set; } = DefaultHttpsPort;
|
||||
|
||||
public bool EnableHttps { get; set; }
|
||||
|
||||
public int PublicPort { get; set; } = DefaultHttpPort;
|
||||
|
||||
public bool EnableIPV6 { get; set; }
|
||||
|
||||
public bool EnableIPV4 { get; set; } = true;
|
||||
|
||||
public bool IgnoreVirtualInterfaces { get; set; } = true;
|
||||
|
||||
public string VirtualInterfaceNames { get; set; } = "vEthernet*";
|
||||
|
||||
public bool TrustAllIP6Interfaces { get; set; }
|
||||
|
||||
public string[] PublishedServerUriBySubnet { get; set; } = Array.Empty<string>();
|
||||
|
||||
public string[] RemoteIPFilter { get; set; } = Array.Empty<string>();
|
||||
|
||||
public bool IsRemoteIPFilterBlacklist { get; set; }
|
||||
|
||||
public bool EnableUPnP { get; set; }
|
||||
|
||||
public bool EnableRemoteAccess { get; set; } = true;
|
||||
|
||||
public string[] LocalNetworkSubnets { get; set; } = Array.Empty<string>();
|
||||
|
||||
public string[] LocalNetworkAddresses { get; set; } = Array.Empty<string>();
|
||||
|
||||
public string[] KnownProxies { get; set; } = Array.Empty<string>();
|
||||
}
|
||||
#pragma warning restore
|
||||
}
|
||||
@@ -9,7 +9,7 @@ using Jellyfin.Data.Enums;
|
||||
using Jellyfin.Server.Implementations;
|
||||
using MediaBrowser.Controller;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Dto;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using SQLitePCL.pretty;
|
||||
|
||||
@@ -114,13 +114,14 @@ namespace Jellyfin.Server.Migrations.Routines
|
||||
}
|
||||
|
||||
var chromecastVersion = dto.CustomPrefs.TryGetValue("chromecastVersion", out var version)
|
||||
&& !string.IsNullOrEmpty(version)
|
||||
? chromecastDict[version]
|
||||
: ChromecastVersion.Stable;
|
||||
dto.CustomPrefs.Remove("chromecastVersion");
|
||||
|
||||
var displayPreferences = new DisplayPreferences(dtoUserId, itemId, client)
|
||||
{
|
||||
IndexBy = Enum.TryParse<IndexingKind>(dto.IndexBy, true, out var indexBy) ? indexBy : (IndexingKind?)null,
|
||||
IndexBy = Enum.TryParse<IndexingKind>(dto.IndexBy, true, out var indexBy) ? indexBy : null,
|
||||
ShowBackdrop = dto.ShowBackdrop,
|
||||
ShowSidebar = dto.ShowSidebar,
|
||||
ScrollDirection = dto.ScrollDirection,
|
||||
|
||||
@@ -10,7 +10,6 @@ using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using CommandLine;
|
||||
using Emby.Server.Implementations;
|
||||
using Emby.Server.Implementations.IO;
|
||||
using Jellyfin.Server.Implementations;
|
||||
using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Common.Net;
|
||||
@@ -157,34 +156,37 @@ namespace Jellyfin.Server
|
||||
|
||||
ApplicationHost.LogEnvironmentInfo(_logger, appPaths);
|
||||
|
||||
// If hosting the web client, validate the client content path
|
||||
if (startupConfig.HostWebClient())
|
||||
{
|
||||
string? webContentPath = appPaths.WebPath;
|
||||
if (!Directory.Exists(webContentPath) || !Directory.EnumerateFiles(webContentPath).Any())
|
||||
{
|
||||
_logger.LogError(
|
||||
"The server is expected to host the web client, but the provided content directory is either " +
|
||||
"invalid or empty: {WebContentPath}. If you do not want to host the web client with the " +
|
||||
"server, you may set the '--nowebclient' command line flag, or set" +
|
||||
"'{ConfigKey}=false' in your config settings.",
|
||||
webContentPath,
|
||||
ConfigurationExtensions.HostWebClientKey);
|
||||
Environment.ExitCode = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
PerformStaticInitialization();
|
||||
var serviceCollection = new ServiceCollection();
|
||||
Migrations.MigrationRunner.RunPreStartup(appPaths, _loggerFactory);
|
||||
|
||||
var appHost = new CoreAppHost(
|
||||
appPaths,
|
||||
_loggerFactory,
|
||||
options,
|
||||
startupConfig,
|
||||
new ManagedFileSystem(_loggerFactory.CreateLogger<ManagedFileSystem>(), appPaths),
|
||||
serviceCollection);
|
||||
startupConfig);
|
||||
|
||||
try
|
||||
{
|
||||
// If hosting the web client, validate the client content path
|
||||
if (startupConfig.HostWebClient())
|
||||
{
|
||||
string? webContentPath = appHost.ConfigurationManager.ApplicationPaths.WebPath;
|
||||
if (!Directory.Exists(webContentPath) || Directory.GetFiles(webContentPath).Length == 0)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
"The server is expected to host the web client, but the provided content directory is either " +
|
||||
$"invalid or empty: {webContentPath}. If you do not want to host the web client with the " +
|
||||
"server, you may set the '--nowebclient' command line flag, or set" +
|
||||
$"'{ConfigurationExtensions.HostWebClientKey}=false' in your config settings.");
|
||||
}
|
||||
}
|
||||
|
||||
appHost.Init();
|
||||
var serviceCollection = new ServiceCollection();
|
||||
appHost.Init(serviceCollection);
|
||||
|
||||
var webHost = new WebHostBuilder().ConfigureWebHostBuilder(appHost, serviceCollection, options, startupConfig, appPaths).Build();
|
||||
|
||||
@@ -594,7 +596,7 @@ namespace Jellyfin.Server
|
||||
try
|
||||
{
|
||||
// Serilog.Log is used by SerilogLoggerFactory when no logger is specified
|
||||
Serilog.Log.Logger = new LoggerConfiguration()
|
||||
Log.Logger = new LoggerConfiguration()
|
||||
.ReadFrom.Configuration(configuration)
|
||||
.Enrich.FromLogContext()
|
||||
.Enrich.WithThreadId()
|
||||
@@ -602,7 +604,7 @@ namespace Jellyfin.Server
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Serilog.Log.Logger = new LoggerConfiguration()
|
||||
Log.Logger = new LoggerConfiguration()
|
||||
.WriteTo.Console(outputTemplate: "[{Timestamp:HH:mm:ss}] [{Level:u3}] [{ThreadId}] {SourceContext}: {Message:lj}{NewLine}{Exception}")
|
||||
.WriteTo.Async(x => x.File(
|
||||
Path.Combine(appPaths.LogDirectoryPath, "log_.log"),
|
||||
@@ -613,7 +615,7 @@ namespace Jellyfin.Server
|
||||
.Enrich.WithThreadId()
|
||||
.CreateLogger();
|
||||
|
||||
Serilog.Log.Logger.Fatal(ex, "Failed to create/read logger configuration");
|
||||
Log.Logger.Fatal(ex, "Failed to create/read logger configuration");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -648,7 +650,7 @@ namespace Jellyfin.Server
|
||||
|
||||
private static string NormalizeCommandLineArgument(string arg)
|
||||
{
|
||||
if (!arg.Contains(" ", StringComparison.OrdinalIgnoreCase))
|
||||
if (!arg.Contains(' ', StringComparison.Ordinal))
|
||||
{
|
||||
return arg;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user