|
@@ -28,20 +28,20 @@ using Emby.Server.Implementations.Data;
|
|
|
using Emby.Server.Implementations.Devices;
|
|
|
using Emby.Server.Implementations.Diagnostics;
|
|
|
using Emby.Server.Implementations.Dto;
|
|
|
-using Emby.Server.Implementations.FFMpeg;
|
|
|
using Emby.Server.Implementations.HttpServer;
|
|
|
using Emby.Server.Implementations.HttpServer.Security;
|
|
|
using Emby.Server.Implementations.IO;
|
|
|
using Emby.Server.Implementations.Library;
|
|
|
using Emby.Server.Implementations.LiveTv;
|
|
|
using Emby.Server.Implementations.Localization;
|
|
|
+using Emby.Server.Implementations.Middleware;
|
|
|
using Emby.Server.Implementations.Net;
|
|
|
using Emby.Server.Implementations.Playlists;
|
|
|
-using Emby.Server.Implementations.Reflection;
|
|
|
using Emby.Server.Implementations.ScheduledTasks;
|
|
|
using Emby.Server.Implementations.Security;
|
|
|
using Emby.Server.Implementations.Serialization;
|
|
|
using Emby.Server.Implementations.Session;
|
|
|
+using Emby.Server.Implementations.SocketSharp;
|
|
|
using Emby.Server.Implementations.TV;
|
|
|
using Emby.Server.Implementations.Updates;
|
|
|
using MediaBrowser.Api;
|
|
@@ -91,7 +91,6 @@ using MediaBrowser.Model.Globalization;
|
|
|
using MediaBrowser.Model.IO;
|
|
|
using MediaBrowser.Model.MediaInfo;
|
|
|
using MediaBrowser.Model.Net;
|
|
|
-using MediaBrowser.Model.Reflection;
|
|
|
using MediaBrowser.Model.Serialization;
|
|
|
using MediaBrowser.Model.Services;
|
|
|
using MediaBrowser.Model.System;
|
|
@@ -103,11 +102,15 @@ using MediaBrowser.Providers.Subtitles;
|
|
|
using MediaBrowser.Providers.TV.TheTVDB;
|
|
|
using MediaBrowser.WebDashboard.Api;
|
|
|
using MediaBrowser.XbmcMetadata.Providers;
|
|
|
+using Microsoft.AspNetCore.Builder;
|
|
|
+using Microsoft.AspNetCore.Hosting;
|
|
|
+using Microsoft.AspNetCore.Http;
|
|
|
+using Microsoft.AspNetCore.Http.Extensions;
|
|
|
using Microsoft.Extensions.Configuration;
|
|
|
using Microsoft.Extensions.Logging;
|
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
|
+using Microsoft.Extensions.DependencyInjection.Extensions;
|
|
|
using ServiceStack;
|
|
|
-using X509Certificate = System.Security.Cryptography.X509Certificates.X509Certificate;
|
|
|
|
|
|
namespace Emby.Server.Implementations
|
|
|
{
|
|
@@ -533,7 +536,7 @@ namespace Emby.Server.Implementations
|
|
|
|
|
|
ConfigurationManager.ConfigurationUpdated += OnConfigurationUpdated;
|
|
|
|
|
|
- MediaEncoder.Init();
|
|
|
+ MediaEncoder.SetFFmpegPath();
|
|
|
|
|
|
//if (string.IsNullOrWhiteSpace(MediaEncoder.EncoderPath))
|
|
|
//{
|
|
@@ -610,6 +613,68 @@ namespace Emby.Server.Implementations
|
|
|
await RegisterResources(serviceCollection);
|
|
|
|
|
|
FindParts();
|
|
|
+
|
|
|
+ string contentRoot = ServerConfigurationManager.Configuration.DashboardSourcePath;
|
|
|
+ if (string.IsNullOrEmpty(contentRoot))
|
|
|
+ {
|
|
|
+ contentRoot = Path.Combine(ServerConfigurationManager.ApplicationPaths.ApplicationResourcesPath, "jellyfin-web", "src");
|
|
|
+ }
|
|
|
+
|
|
|
+ var host = new WebHostBuilder()
|
|
|
+ .UseKestrel(options =>
|
|
|
+ {
|
|
|
+ options.ListenAnyIP(HttpPort);
|
|
|
+
|
|
|
+ if (EnableHttps && Certificate != null)
|
|
|
+ {
|
|
|
+ options.ListenAnyIP(HttpsPort, listenOptions => { listenOptions.UseHttps(Certificate); });
|
|
|
+ }
|
|
|
+ })
|
|
|
+ .UseContentRoot(contentRoot)
|
|
|
+ .ConfigureServices(services =>
|
|
|
+ {
|
|
|
+ services.AddResponseCompression();
|
|
|
+ services.AddHttpContextAccessor();
|
|
|
+ })
|
|
|
+ .Configure(app =>
|
|
|
+ {
|
|
|
+ app.UseWebSockets();
|
|
|
+
|
|
|
+ app.UseResponseCompression();
|
|
|
+ // TODO app.UseMiddleware<WebSocketMiddleware>();
|
|
|
+ app.Use(ExecuteWebsocketHandlerAsync);
|
|
|
+ app.Use(ExecuteHttpHandlerAsync);
|
|
|
+ })
|
|
|
+ .Build();
|
|
|
+
|
|
|
+ await host.StartAsync();
|
|
|
+ }
|
|
|
+
|
|
|
+ private async Task ExecuteWebsocketHandlerAsync(HttpContext context, Func<Task> next)
|
|
|
+ {
|
|
|
+ if (!context.WebSockets.IsWebSocketRequest)
|
|
|
+ {
|
|
|
+ await next().ConfigureAwait(false);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ await HttpServer.ProcessWebSocketRequest(context).ConfigureAwait(false);
|
|
|
+ }
|
|
|
+
|
|
|
+ private async Task ExecuteHttpHandlerAsync(HttpContext context, Func<Task> next)
|
|
|
+ {
|
|
|
+ if (context.WebSockets.IsWebSocketRequest)
|
|
|
+ {
|
|
|
+ await next().ConfigureAwait(false);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ var request = context.Request;
|
|
|
+ var response = context.Response;
|
|
|
+ var localPath = context.Request.Path.ToString();
|
|
|
+
|
|
|
+ var req = new WebSocketSharpRequest(request, response, request.Path, Logger);
|
|
|
+ await HttpServer.RequestHandler(req, request.GetDisplayUrl(), request.Host.ToString(), localPath, CancellationToken.None).ConfigureAwait(false);
|
|
|
}
|
|
|
|
|
|
protected virtual IHttpClient CreateHttpClient()
|
|
@@ -631,6 +696,8 @@ namespace Emby.Server.Implementations
|
|
|
|
|
|
serviceCollection.AddSingleton<IApplicationPaths>(ApplicationPaths);
|
|
|
|
|
|
+ serviceCollection.AddSingleton<IConfiguration>(_configuration);
|
|
|
+
|
|
|
serviceCollection.AddSingleton(JsonSerializer);
|
|
|
|
|
|
serviceCollection.AddSingleton(LoggerFactory);
|
|
@@ -672,7 +739,7 @@ namespace Emby.Server.Implementations
|
|
|
ZipClient = new ZipClient();
|
|
|
serviceCollection.AddSingleton(ZipClient);
|
|
|
|
|
|
- HttpResultFactory = new HttpResultFactory(LoggerFactory, FileSystemManager, JsonSerializer, CreateBrotliCompressor());
|
|
|
+ HttpResultFactory = new HttpResultFactory(LoggerFactory, FileSystemManager, JsonSerializer, StreamHelper);
|
|
|
serviceCollection.AddSingleton(HttpResultFactory);
|
|
|
|
|
|
serviceCollection.AddSingleton<IServerApplicationHost>(this);
|
|
@@ -680,9 +747,6 @@ namespace Emby.Server.Implementations
|
|
|
|
|
|
serviceCollection.AddSingleton(ServerConfigurationManager);
|
|
|
|
|
|
- var assemblyInfo = new AssemblyInfo();
|
|
|
- serviceCollection.AddSingleton<IAssemblyInfo>(assemblyInfo);
|
|
|
-
|
|
|
LocalizationManager = new LocalizationManager(ServerConfigurationManager, FileSystemManager, JsonSerializer, LoggerFactory);
|
|
|
await LocalizationManager.LoadAll();
|
|
|
serviceCollection.AddSingleton<ILocalizationManager>(LocalizationManager);
|
|
@@ -699,7 +763,7 @@ namespace Emby.Server.Implementations
|
|
|
var displayPreferencesRepo = new SqliteDisplayPreferencesRepository(LoggerFactory, JsonSerializer, ApplicationPaths, FileSystemManager);
|
|
|
serviceCollection.AddSingleton<IDisplayPreferencesRepository>(displayPreferencesRepo);
|
|
|
|
|
|
- ItemRepository = new SqliteItemRepository(ServerConfigurationManager, this, JsonSerializer, LoggerFactory, assemblyInfo);
|
|
|
+ ItemRepository = new SqliteItemRepository(ServerConfigurationManager, this, JsonSerializer, LoggerFactory);
|
|
|
serviceCollection.AddSingleton<IItemRepository>(ItemRepository);
|
|
|
|
|
|
AuthenticationRepository = GetAuthenticationRepository();
|
|
@@ -729,7 +793,8 @@ namespace Emby.Server.Implementations
|
|
|
_configuration,
|
|
|
NetworkManager,
|
|
|
JsonSerializer,
|
|
|
- XmlSerializer);
|
|
|
+ XmlSerializer,
|
|
|
+ CreateHttpListener());
|
|
|
|
|
|
HttpServer.GlobalResponse = LocalizationManager.GetLocalizedString("StartupEmbyServerIsLoading");
|
|
|
serviceCollection.AddSingleton(HttpServer);
|
|
@@ -786,7 +851,18 @@ namespace Emby.Server.Implementations
|
|
|
ChapterManager = new ChapterManager(LibraryManager, LoggerFactory, ServerConfigurationManager, ItemRepository);
|
|
|
serviceCollection.AddSingleton(ChapterManager);
|
|
|
|
|
|
- RegisterMediaEncoder(serviceCollection);
|
|
|
+ MediaEncoder = new MediaBrowser.MediaEncoding.Encoder.MediaEncoder(
|
|
|
+ LoggerFactory,
|
|
|
+ JsonSerializer,
|
|
|
+ StartupOptions.FFmpegPath,
|
|
|
+ StartupOptions.FFprobePath,
|
|
|
+ ServerConfigurationManager,
|
|
|
+ FileSystemManager,
|
|
|
+ () => SubtitleEncoder,
|
|
|
+ () => MediaSourceManager,
|
|
|
+ ProcessFactory,
|
|
|
+ 5000);
|
|
|
+ serviceCollection.AddSingleton(MediaEncoder);
|
|
|
|
|
|
EncodingManager = new MediaEncoder.EncodingManager(FileSystemManager, LoggerFactory, MediaEncoder, ChapterManager, LibraryManager);
|
|
|
serviceCollection.AddSingleton(EncodingManager);
|
|
@@ -822,11 +898,6 @@ namespace Emby.Server.Implementations
|
|
|
_serviceProvider = serviceCollection.BuildServiceProvider();
|
|
|
}
|
|
|
|
|
|
- protected virtual IBrotliCompressor CreateBrotliCompressor()
|
|
|
- {
|
|
|
- return null;
|
|
|
- }
|
|
|
-
|
|
|
public virtual string PackageRuntime => "netcore";
|
|
|
|
|
|
public static void LogEnvironmentInfo(ILogger logger, IApplicationPaths appPaths, EnvironmentInfo.EnvironmentInfo environmentInfo)
|
|
@@ -859,11 +930,9 @@ namespace Emby.Server.Implementations
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- protected virtual bool SupportsDualModeSockets => true;
|
|
|
-
|
|
|
- private X509Certificate GetCertificate(CertificateInfo info)
|
|
|
+ private X509Certificate2 GetCertificate(CertificateInfo info)
|
|
|
{
|
|
|
- var certificateLocation = info == null ? null : info.Path;
|
|
|
+ var certificateLocation = info?.Path;
|
|
|
|
|
|
if (string.IsNullOrWhiteSpace(certificateLocation))
|
|
|
{
|
|
@@ -902,85 +971,6 @@ namespace Emby.Server.Implementations
|
|
|
return new ImageProcessor(LoggerFactory, ServerConfigurationManager.ApplicationPaths, FileSystemManager, ImageEncoder, () => LibraryManager, () => MediaEncoder);
|
|
|
}
|
|
|
|
|
|
- protected virtual FFMpegInstallInfo GetFfmpegInstallInfo()
|
|
|
- {
|
|
|
- var info = new FFMpegInstallInfo();
|
|
|
-
|
|
|
- // Windows builds: http://ffmpeg.zeranoe.com/builds/
|
|
|
- // Linux builds: http://johnvansickle.com/ffmpeg/
|
|
|
- // OS X builds: http://ffmpegmac.net/
|
|
|
- // OS X x64: http://www.evermeet.cx/ffmpeg/
|
|
|
-
|
|
|
- if (EnvironmentInfo.OperatingSystem == MediaBrowser.Model.System.OperatingSystem.Linux)
|
|
|
- {
|
|
|
- info.FFMpegFilename = "ffmpeg";
|
|
|
- info.FFProbeFilename = "ffprobe";
|
|
|
- info.ArchiveType = "7z";
|
|
|
- info.Version = "20170308";
|
|
|
- }
|
|
|
- else if (EnvironmentInfo.OperatingSystem == MediaBrowser.Model.System.OperatingSystem.Windows)
|
|
|
- {
|
|
|
- info.FFMpegFilename = "ffmpeg.exe";
|
|
|
- info.FFProbeFilename = "ffprobe.exe";
|
|
|
- info.Version = "20170308";
|
|
|
- info.ArchiveType = "7z";
|
|
|
- }
|
|
|
- else if (EnvironmentInfo.OperatingSystem == MediaBrowser.Model.System.OperatingSystem.OSX)
|
|
|
- {
|
|
|
- info.FFMpegFilename = "ffmpeg";
|
|
|
- info.FFProbeFilename = "ffprobe";
|
|
|
- info.ArchiveType = "7z";
|
|
|
- info.Version = "20170308";
|
|
|
- }
|
|
|
-
|
|
|
- return info;
|
|
|
- }
|
|
|
-
|
|
|
- protected virtual FFMpegInfo GetFFMpegInfo()
|
|
|
- {
|
|
|
- return new FFMpegLoader(ApplicationPaths, FileSystemManager, GetFfmpegInstallInfo())
|
|
|
- .GetFFMpegInfo(StartupOptions);
|
|
|
- }
|
|
|
-
|
|
|
- /// <summary>
|
|
|
- /// Registers the media encoder.
|
|
|
- /// </summary>
|
|
|
- /// <returns>Task.</returns>
|
|
|
- private void RegisterMediaEncoder(IServiceCollection serviceCollection)
|
|
|
- {
|
|
|
- string encoderPath = null;
|
|
|
- string probePath = null;
|
|
|
-
|
|
|
- var info = GetFFMpegInfo();
|
|
|
-
|
|
|
- encoderPath = info.EncoderPath;
|
|
|
- probePath = info.ProbePath;
|
|
|
- var hasExternalEncoder = string.Equals(info.Version, "external", StringComparison.OrdinalIgnoreCase);
|
|
|
-
|
|
|
- var mediaEncoder = new MediaBrowser.MediaEncoding.Encoder.MediaEncoder(
|
|
|
- LoggerFactory,
|
|
|
- JsonSerializer,
|
|
|
- encoderPath,
|
|
|
- probePath,
|
|
|
- hasExternalEncoder,
|
|
|
- ServerConfigurationManager,
|
|
|
- FileSystemManager,
|
|
|
- LiveTvManager,
|
|
|
- IsoManager,
|
|
|
- LibraryManager,
|
|
|
- ChannelManager,
|
|
|
- SessionManager,
|
|
|
- () => SubtitleEncoder,
|
|
|
- () => MediaSourceManager,
|
|
|
- HttpClient,
|
|
|
- ZipClient,
|
|
|
- ProcessFactory,
|
|
|
- 5000);
|
|
|
-
|
|
|
- MediaEncoder = mediaEncoder;
|
|
|
- serviceCollection.AddSingleton(MediaEncoder);
|
|
|
- }
|
|
|
-
|
|
|
/// <summary>
|
|
|
/// Gets the user repository.
|
|
|
/// </summary>
|
|
@@ -1017,7 +1007,7 @@ namespace Emby.Server.Implementations
|
|
|
/// </summary>
|
|
|
private void SetStaticProperties()
|
|
|
{
|
|
|
- ((SqliteItemRepository)ItemRepository).ImageProcessor = ImageProcessor;
|
|
|
+ ItemRepository.ImageProcessor = ImageProcessor;
|
|
|
|
|
|
// For now there's no real way to inject these properly
|
|
|
BaseItem.Logger = LoggerFactory.CreateLogger("BaseItem");
|
|
@@ -1059,9 +1049,7 @@ namespace Emby.Server.Implementations
|
|
|
.Where(i => i != null)
|
|
|
.ToArray();
|
|
|
|
|
|
- HttpServer.Init(GetExports<IService>(false), GetExports<IWebSocketListener>());
|
|
|
-
|
|
|
- StartServer();
|
|
|
+ HttpServer.Init(GetExports<IService>(false), GetExports<IWebSocketListener>(), GetUrlPrefixes());
|
|
|
|
|
|
LibraryManager.AddParts(GetExports<IResolverIgnoreRule>(),
|
|
|
GetExports<IItemResolver>(),
|
|
@@ -1145,15 +1133,12 @@ namespace Emby.Server.Implementations
|
|
|
|
|
|
AllConcreteTypes = GetComposablePartAssemblies()
|
|
|
.SelectMany(x => x.ExportedTypes)
|
|
|
- .Where(type =>
|
|
|
- {
|
|
|
- return type.IsClass && !type.IsAbstract && !type.IsInterface && !type.IsGenericType;
|
|
|
- })
|
|
|
+ .Where(type => type.IsClass && !type.IsAbstract && !type.IsInterface && !type.IsGenericType)
|
|
|
.ToArray();
|
|
|
}
|
|
|
|
|
|
private CertificateInfo CertificateInfo { get; set; }
|
|
|
- protected X509Certificate Certificate { get; private set; }
|
|
|
+ protected X509Certificate2 Certificate { get; private set; }
|
|
|
|
|
|
private IEnumerable<string> GetUrlPrefixes()
|
|
|
{
|
|
@@ -1175,45 +1160,7 @@ namespace Emby.Server.Implementations
|
|
|
});
|
|
|
}
|
|
|
|
|
|
- protected abstract IHttpListener CreateHttpListener();
|
|
|
-
|
|
|
- /// <summary>
|
|
|
- /// Starts the server.
|
|
|
- /// </summary>
|
|
|
- private void StartServer()
|
|
|
- {
|
|
|
- try
|
|
|
- {
|
|
|
- ((HttpListenerHost)HttpServer).StartServer(GetUrlPrefixes().ToArray(), CreateHttpListener());
|
|
|
- return;
|
|
|
- }
|
|
|
- catch (Exception ex)
|
|
|
- {
|
|
|
- var msg = string.Equals(ex.GetType().Name, "SocketException", StringComparison.OrdinalIgnoreCase)
|
|
|
- ? "The http server is unable to start due to a Socket error. This can occasionally happen when the operating system takes longer than usual to release the IP bindings from the previous session. This can take up to five minutes. Please try waiting or rebooting the system."
|
|
|
- : "Error starting Http Server";
|
|
|
-
|
|
|
- Logger.LogError(ex, msg);
|
|
|
-
|
|
|
- if (HttpPort == ServerConfiguration.DefaultHttpPort)
|
|
|
- {
|
|
|
- throw;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- HttpPort = ServerConfiguration.DefaultHttpPort;
|
|
|
-
|
|
|
- try
|
|
|
- {
|
|
|
- ((HttpListenerHost)HttpServer).StartServer(GetUrlPrefixes().ToArray(), CreateHttpListener());
|
|
|
- }
|
|
|
- catch (Exception ex)
|
|
|
- {
|
|
|
- Logger.LogError(ex, "Error starting http server");
|
|
|
-
|
|
|
- throw;
|
|
|
- }
|
|
|
- }
|
|
|
+ protected IHttpListener CreateHttpListener() => new WebSocketSharpListener(Logger);
|
|
|
|
|
|
private CertificateInfo GetCertificateInfo(bool generateCertificate)
|
|
|
{
|
|
@@ -1456,7 +1403,7 @@ namespace Emby.Server.Implementations
|
|
|
ServerName = FriendlyName,
|
|
|
LocalAddress = localAddress,
|
|
|
SupportsLibraryMonitor = true,
|
|
|
- EncoderLocationType = MediaEncoder.EncoderLocationType,
|
|
|
+ EncoderLocation = MediaEncoder.EncoderLocation,
|
|
|
SystemArchitecture = EnvironmentInfo.SystemArchitecture,
|
|
|
SystemUpdateLevel = SystemUpdateLevel,
|
|
|
PackageName = StartupOptions.PackageName
|
|
@@ -1650,7 +1597,7 @@ namespace Emby.Server.Implementations
|
|
|
LogErrorResponseBody = false,
|
|
|
LogErrors = logPing,
|
|
|
LogRequest = logPing,
|
|
|
- TimeoutMs = 30000,
|
|
|
+ TimeoutMs = 5000,
|
|
|
BufferContent = false,
|
|
|
|
|
|
CancellationToken = cancellationToken
|