|
@@ -4,6 +4,7 @@ using System;
|
|
|
using System.Collections.Concurrent;
|
|
|
using System.Collections.Generic;
|
|
|
using System.Diagnostics;
|
|
|
+using System.Globalization;
|
|
|
using System.IO;
|
|
|
using System.Linq;
|
|
|
using System.Net;
|
|
@@ -37,10 +38,11 @@ using Emby.Server.Implementations.LiveTv;
|
|
|
using Emby.Server.Implementations.Localization;
|
|
|
using Emby.Server.Implementations.Net;
|
|
|
using Emby.Server.Implementations.Playlists;
|
|
|
+using Emby.Server.Implementations.Plugins;
|
|
|
+using Emby.Server.Implementations.QuickConnect;
|
|
|
using Emby.Server.Implementations.ScheduledTasks;
|
|
|
using Emby.Server.Implementations.Security;
|
|
|
using Emby.Server.Implementations.Serialization;
|
|
|
-using Emby.Server.Implementations.Services;
|
|
|
using Emby.Server.Implementations.Session;
|
|
|
using Emby.Server.Implementations.SyncPlay;
|
|
|
using Emby.Server.Implementations.TV;
|
|
@@ -49,11 +51,11 @@ using Jellyfin.Api.Helpers;
|
|
|
using MediaBrowser.Common;
|
|
|
using MediaBrowser.Common.Configuration;
|
|
|
using MediaBrowser.Common.Events;
|
|
|
+using MediaBrowser.Common.Json;
|
|
|
using MediaBrowser.Common.Net;
|
|
|
using MediaBrowser.Common.Plugins;
|
|
|
using MediaBrowser.Common.Updates;
|
|
|
using MediaBrowser.Controller;
|
|
|
-using MediaBrowser.Controller.Authentication;
|
|
|
using MediaBrowser.Controller.Channels;
|
|
|
using MediaBrowser.Controller.Chapters;
|
|
|
using MediaBrowser.Controller.Collections;
|
|
@@ -72,6 +74,7 @@ using MediaBrowser.Controller.Persistence;
|
|
|
using MediaBrowser.Controller.Playlists;
|
|
|
using MediaBrowser.Controller.Plugins;
|
|
|
using MediaBrowser.Controller.Providers;
|
|
|
+using MediaBrowser.Controller.QuickConnect;
|
|
|
using MediaBrowser.Controller.Resolvers;
|
|
|
using MediaBrowser.Controller.Security;
|
|
|
using MediaBrowser.Controller.Session;
|
|
@@ -89,19 +92,20 @@ using MediaBrowser.Model.IO;
|
|
|
using MediaBrowser.Model.MediaInfo;
|
|
|
using MediaBrowser.Model.Net;
|
|
|
using MediaBrowser.Model.Serialization;
|
|
|
-using MediaBrowser.Model.Services;
|
|
|
using MediaBrowser.Model.System;
|
|
|
using MediaBrowser.Model.Tasks;
|
|
|
using MediaBrowser.Providers.Chapters;
|
|
|
using MediaBrowser.Providers.Manager;
|
|
|
using MediaBrowser.Providers.Plugins.TheTvdb;
|
|
|
+using MediaBrowser.Providers.Plugins.Tmdb;
|
|
|
using MediaBrowser.Providers.Subtitles;
|
|
|
using MediaBrowser.XbmcMetadata.Providers;
|
|
|
-using Microsoft.AspNetCore.Http;
|
|
|
+using Microsoft.AspNetCore.Mvc;
|
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
|
using Microsoft.Extensions.Logging;
|
|
|
using Prometheus.DotNetRuntime;
|
|
|
using OperatingSystem = MediaBrowser.Common.System.OperatingSystem;
|
|
|
+using WebSocketManager = Emby.Server.Implementations.HttpServer.WebSocketManager;
|
|
|
|
|
|
namespace Emby.Server.Implementations
|
|
|
{
|
|
@@ -118,18 +122,22 @@ namespace Emby.Server.Implementations
|
|
|
private readonly IFileSystem _fileSystemManager;
|
|
|
private readonly INetworkManager _networkManager;
|
|
|
private readonly IXmlSerializer _xmlSerializer;
|
|
|
+ private readonly IJsonSerializer _jsonSerializer;
|
|
|
private readonly IStartupOptions _startupOptions;
|
|
|
|
|
|
private IMediaEncoder _mediaEncoder;
|
|
|
private ISessionManager _sessionManager;
|
|
|
- private IHttpServer _httpServer;
|
|
|
- private IHttpClient _httpClient;
|
|
|
+ private IHttpClientFactory _httpClientFactory;
|
|
|
+
|
|
|
+ private string[] _urlPrefixes;
|
|
|
|
|
|
/// <summary>
|
|
|
/// Gets a value indicating whether this instance can self restart.
|
|
|
/// </summary>
|
|
|
public bool CanSelfRestart => _startupOptions.RestartPath != null;
|
|
|
|
|
|
+ public bool CoreStartupHasCompleted { get; private set; }
|
|
|
+
|
|
|
public virtual bool CanLaunchWebBrowser
|
|
|
{
|
|
|
get
|
|
@@ -173,6 +181,8 @@ namespace Emby.Server.Implementations
|
|
|
/// </summary>
|
|
|
protected ILogger<ApplicationHost> Logger { get; }
|
|
|
|
|
|
+ protected IServiceCollection ServiceCollection { get; }
|
|
|
+
|
|
|
private IPlugin[] _plugins;
|
|
|
|
|
|
/// <summary>
|
|
@@ -231,16 +241,26 @@ namespace Emby.Server.Implementations
|
|
|
public IServerConfigurationManager ServerConfigurationManager => (IServerConfigurationManager)ConfigurationManager;
|
|
|
|
|
|
/// <summary>
|
|
|
- /// Initializes a new instance of the <see cref="ApplicationHost" /> class.
|
|
|
+ /// Initializes a new instance of the <see cref="ApplicationHost"/> class.
|
|
|
/// </summary>
|
|
|
+ /// <param name="applicationPaths">Instance of the <see cref="IServerApplicationPaths"/> interface.</param>
|
|
|
+ /// <param name="loggerFactory">Instance of the <see cref="ILoggerFactory"/> interface.</param>
|
|
|
+ /// <param name="options">Instance of the <see cref="IStartupOptions"/> interface.</param>
|
|
|
+ /// <param name="fileSystem">Instance of the <see cref="IFileSystem"/> interface.</param>
|
|
|
+ /// <param name="networkManager">Instance of the <see cref="INetworkManager"/> interface.</param>
|
|
|
+ /// <param name="serviceCollection">Instance of the <see cref="IServiceCollection"/> interface.</param>
|
|
|
public ApplicationHost(
|
|
|
IServerApplicationPaths applicationPaths,
|
|
|
ILoggerFactory loggerFactory,
|
|
|
IStartupOptions options,
|
|
|
IFileSystem fileSystem,
|
|
|
- INetworkManager networkManager)
|
|
|
+ INetworkManager networkManager,
|
|
|
+ IServiceCollection serviceCollection)
|
|
|
{
|
|
|
_xmlSerializer = new MyXmlSerializer();
|
|
|
+ _jsonSerializer = new JsonSerializer();
|
|
|
+
|
|
|
+ ServiceCollection = serviceCollection;
|
|
|
|
|
|
_networkManager = networkManager;
|
|
|
networkManager.LocalSubnetsFn = GetConfiguredLocalSubnets;
|
|
@@ -271,6 +291,10 @@ namespace Emby.Server.Implementations
|
|
|
Password = ServerConfigurationManager.Configuration.CertificatePassword
|
|
|
};
|
|
|
Certificate = GetCertificate(CertificateInfo);
|
|
|
+
|
|
|
+ ApplicationVersion = typeof(ApplicationHost).Assembly.GetName().Version;
|
|
|
+ ApplicationVersionString = ApplicationVersion.ToString(3);
|
|
|
+ ApplicationUserAgent = Name.Replace(' ', '-') + "/" + ApplicationVersionString;
|
|
|
}
|
|
|
|
|
|
public string ExpandVirtualPath(string path)
|
|
@@ -300,22 +324,22 @@ namespace Emby.Server.Implementations
|
|
|
}
|
|
|
|
|
|
/// <inheritdoc />
|
|
|
- public Version ApplicationVersion { get; } = typeof(ApplicationHost).Assembly.GetName().Version;
|
|
|
+ public Version ApplicationVersion { get; }
|
|
|
|
|
|
/// <inheritdoc />
|
|
|
- public string ApplicationVersionString { get; } = typeof(ApplicationHost).Assembly.GetName().Version.ToString(3);
|
|
|
+ public string ApplicationVersionString { get; }
|
|
|
|
|
|
/// <summary>
|
|
|
/// Gets the current application user agent.
|
|
|
/// </summary>
|
|
|
/// <value>The application user agent.</value>
|
|
|
- public string ApplicationUserAgent => Name.Replace(' ', '-') + "/" + ApplicationVersionString;
|
|
|
+ public string ApplicationUserAgent { get; }
|
|
|
|
|
|
/// <summary>
|
|
|
/// Gets the email address for use within a comment section of a user agent field.
|
|
|
/// Presently used to provide contact information to MusicBrainz service.
|
|
|
/// </summary>
|
|
|
- public string ApplicationUserAgentAddress { get; } = "team@jellyfin.org";
|
|
|
+ public string ApplicationUserAgentAddress => "team@jellyfin.org";
|
|
|
|
|
|
/// <summary>
|
|
|
/// Gets the current application name.
|
|
@@ -379,7 +403,7 @@ namespace Emby.Server.Implementations
|
|
|
/// <summary>
|
|
|
/// Resolves this instance.
|
|
|
/// </summary>
|
|
|
- /// <typeparam name="T">The type</typeparam>
|
|
|
+ /// <typeparam name="T">The type.</typeparam>
|
|
|
/// <returns>``0.</returns>
|
|
|
public T Resolve<T>() => ServiceProvider.GetService<T>();
|
|
|
|
|
@@ -440,8 +464,7 @@ namespace Emby.Server.Implementations
|
|
|
Logger.LogInformation("Executed all pre-startup entry points in {Elapsed:g}", stopWatch.Elapsed);
|
|
|
|
|
|
Logger.LogInformation("Core startup complete");
|
|
|
- _httpServer.GlobalResponse = null;
|
|
|
-
|
|
|
+ CoreStartupHasCompleted = true;
|
|
|
stopWatch.Restart();
|
|
|
await Task.WhenAll(StartEntryPoints(entryPoints, false)).ConfigureAwait(false);
|
|
|
Logger.LogInformation("Executed all post-startup entry points in {Elapsed:g}", stopWatch.Elapsed);
|
|
@@ -464,7 +487,7 @@ namespace Emby.Server.Implementations
|
|
|
}
|
|
|
|
|
|
/// <inheritdoc/>
|
|
|
- public void Init(IServiceCollection serviceCollection)
|
|
|
+ public void Init()
|
|
|
{
|
|
|
HttpPort = ServerConfigurationManager.Configuration.HttpServerPortNumber;
|
|
|
HttpsPort = ServerConfigurationManager.Configuration.HttpsPortNumber;
|
|
@@ -493,145 +516,142 @@ namespace Emby.Server.Implementations
|
|
|
|
|
|
DiscoverTypes();
|
|
|
|
|
|
- RegisterServices(serviceCollection);
|
|
|
+ RegisterServices();
|
|
|
}
|
|
|
|
|
|
- public Task ExecuteHttpHandlerAsync(HttpContext context, Func<Task> next)
|
|
|
- => _httpServer.RequestHandler(context);
|
|
|
-
|
|
|
/// <summary>
|
|
|
/// Registers services/resources with the service collection that will be available via DI.
|
|
|
/// </summary>
|
|
|
- protected virtual void RegisterServices(IServiceCollection serviceCollection)
|
|
|
+ protected virtual void RegisterServices()
|
|
|
{
|
|
|
- serviceCollection.AddSingleton(_startupOptions);
|
|
|
-
|
|
|
- serviceCollection.AddMemoryCache();
|
|
|
-
|
|
|
- serviceCollection.AddSingleton(ConfigurationManager);
|
|
|
- serviceCollection.AddSingleton<IApplicationHost>(this);
|
|
|
+ ServiceCollection.AddSingleton(_startupOptions);
|
|
|
|
|
|
- serviceCollection.AddSingleton<IApplicationPaths>(ApplicationPaths);
|
|
|
+ ServiceCollection.AddMemoryCache();
|
|
|
|
|
|
- serviceCollection.AddSingleton<IJsonSerializer, JsonSerializer>();
|
|
|
+ ServiceCollection.AddSingleton(ConfigurationManager);
|
|
|
+ ServiceCollection.AddSingleton<IApplicationHost>(this);
|
|
|
|
|
|
- serviceCollection.AddSingleton(_fileSystemManager);
|
|
|
- serviceCollection.AddSingleton<TvdbClientManager>();
|
|
|
+ ServiceCollection.AddSingleton<IApplicationPaths>(ApplicationPaths);
|
|
|
|
|
|
- serviceCollection.AddSingleton<IHttpClient, HttpClientManager.HttpClientManager>();
|
|
|
+ ServiceCollection.AddSingleton<IJsonSerializer, JsonSerializer>();
|
|
|
|
|
|
- serviceCollection.AddSingleton(_networkManager);
|
|
|
+ ServiceCollection.AddSingleton(_fileSystemManager);
|
|
|
+ ServiceCollection.AddSingleton<TvdbClientManager>();
|
|
|
+ ServiceCollection.AddSingleton<TmdbClientManager>();
|
|
|
|
|
|
- serviceCollection.AddSingleton<IIsoManager, IsoManager>();
|
|
|
+ ServiceCollection.AddSingleton(_networkManager);
|
|
|
|
|
|
- serviceCollection.AddSingleton<ITaskManager, TaskManager>();
|
|
|
+ ServiceCollection.AddSingleton<IIsoManager, IsoManager>();
|
|
|
|
|
|
- serviceCollection.AddSingleton(_xmlSerializer);
|
|
|
+ ServiceCollection.AddSingleton<ITaskManager, TaskManager>();
|
|
|
|
|
|
- serviceCollection.AddSingleton<IStreamHelper, StreamHelper>();
|
|
|
+ ServiceCollection.AddSingleton(_xmlSerializer);
|
|
|
|
|
|
- serviceCollection.AddSingleton<ICryptoProvider, CryptographyProvider>();
|
|
|
+ ServiceCollection.AddSingleton<IStreamHelper, StreamHelper>();
|
|
|
|
|
|
- serviceCollection.AddSingleton<ISocketFactory, SocketFactory>();
|
|
|
+ ServiceCollection.AddSingleton<ICryptoProvider, CryptographyProvider>();
|
|
|
|
|
|
- serviceCollection.AddSingleton<IInstallationManager, InstallationManager>();
|
|
|
+ ServiceCollection.AddSingleton<ISocketFactory, SocketFactory>();
|
|
|
|
|
|
- serviceCollection.AddSingleton<IZipClient, ZipClient>();
|
|
|
+ ServiceCollection.AddSingleton<IInstallationManager, InstallationManager>();
|
|
|
|
|
|
- serviceCollection.AddSingleton<IHttpResultFactory, HttpResultFactory>();
|
|
|
+ ServiceCollection.AddSingleton<IZipClient, ZipClient>();
|
|
|
|
|
|
- serviceCollection.AddSingleton<IServerApplicationHost>(this);
|
|
|
- serviceCollection.AddSingleton<IServerApplicationPaths>(ApplicationPaths);
|
|
|
+ ServiceCollection.AddSingleton<IServerApplicationHost>(this);
|
|
|
+ ServiceCollection.AddSingleton<IServerApplicationPaths>(ApplicationPaths);
|
|
|
|
|
|
- serviceCollection.AddSingleton(ServerConfigurationManager);
|
|
|
+ ServiceCollection.AddSingleton(ServerConfigurationManager);
|
|
|
|
|
|
- serviceCollection.AddSingleton<ILocalizationManager, LocalizationManager>();
|
|
|
+ ServiceCollection.AddSingleton<ILocalizationManager, LocalizationManager>();
|
|
|
|
|
|
- serviceCollection.AddSingleton<IBlurayExaminer, BdInfoExaminer>();
|
|
|
+ ServiceCollection.AddSingleton<IBlurayExaminer, BdInfoExaminer>();
|
|
|
|
|
|
- serviceCollection.AddSingleton<IUserDataRepository, SqliteUserDataRepository>();
|
|
|
- serviceCollection.AddSingleton<IUserDataManager, UserDataManager>();
|
|
|
+ ServiceCollection.AddSingleton<IUserDataRepository, SqliteUserDataRepository>();
|
|
|
+ ServiceCollection.AddSingleton<IUserDataManager, UserDataManager>();
|
|
|
|
|
|
- serviceCollection.AddSingleton<IItemRepository, SqliteItemRepository>();
|
|
|
+ ServiceCollection.AddSingleton<IItemRepository, SqliteItemRepository>();
|
|
|
|
|
|
- serviceCollection.AddSingleton<IAuthenticationRepository, AuthenticationRepository>();
|
|
|
+ ServiceCollection.AddSingleton<IAuthenticationRepository, AuthenticationRepository>();
|
|
|
|
|
|
// TODO: Refactor to eliminate the circular dependency here so that Lazy<T> isn't required
|
|
|
- serviceCollection.AddTransient(provider => new Lazy<IDtoService>(provider.GetRequiredService<IDtoService>));
|
|
|
+ ServiceCollection.AddTransient(provider => new Lazy<IDtoService>(provider.GetRequiredService<IDtoService>));
|
|
|
|
|
|
// TODO: Refactor to eliminate the circular dependency here so that Lazy<T> isn't required
|
|
|
- serviceCollection.AddTransient(provider => new Lazy<EncodingHelper>(provider.GetRequiredService<EncodingHelper>));
|
|
|
- serviceCollection.AddSingleton<IMediaEncoder, MediaBrowser.MediaEncoding.Encoder.MediaEncoder>();
|
|
|
+ ServiceCollection.AddTransient(provider => new Lazy<EncodingHelper>(provider.GetRequiredService<EncodingHelper>));
|
|
|
+ ServiceCollection.AddSingleton<IMediaEncoder, MediaBrowser.MediaEncoding.Encoder.MediaEncoder>();
|
|
|
|
|
|
// TODO: Refactor to eliminate the circular dependencies here so that Lazy<T> isn't required
|
|
|
- serviceCollection.AddTransient(provider => new Lazy<ILibraryMonitor>(provider.GetRequiredService<ILibraryMonitor>));
|
|
|
- serviceCollection.AddTransient(provider => new Lazy<IProviderManager>(provider.GetRequiredService<IProviderManager>));
|
|
|
- serviceCollection.AddTransient(provider => new Lazy<IUserViewManager>(provider.GetRequiredService<IUserViewManager>));
|
|
|
- serviceCollection.AddSingleton<ILibraryManager, LibraryManager>();
|
|
|
+ ServiceCollection.AddTransient(provider => new Lazy<ILibraryMonitor>(provider.GetRequiredService<ILibraryMonitor>));
|
|
|
+ ServiceCollection.AddTransient(provider => new Lazy<IProviderManager>(provider.GetRequiredService<IProviderManager>));
|
|
|
+ ServiceCollection.AddTransient(provider => new Lazy<IUserViewManager>(provider.GetRequiredService<IUserViewManager>));
|
|
|
+ ServiceCollection.AddSingleton<ILibraryManager, LibraryManager>();
|
|
|
|
|
|
- serviceCollection.AddSingleton<IMusicManager, MusicManager>();
|
|
|
+ ServiceCollection.AddSingleton<IMusicManager, MusicManager>();
|
|
|
|
|
|
- serviceCollection.AddSingleton<ILibraryMonitor, LibraryMonitor>();
|
|
|
+ ServiceCollection.AddSingleton<ILibraryMonitor, LibraryMonitor>();
|
|
|
|
|
|
- serviceCollection.AddSingleton<ISearchEngine, SearchEngine>();
|
|
|
+ ServiceCollection.AddSingleton<ISearchEngine, SearchEngine>();
|
|
|
|
|
|
- serviceCollection.AddSingleton<ServiceController>();
|
|
|
- serviceCollection.AddSingleton<IHttpServer, HttpListenerHost>();
|
|
|
+ ServiceCollection.AddSingleton<IWebSocketManager, WebSocketManager>();
|
|
|
|
|
|
- serviceCollection.AddSingleton<IImageProcessor, ImageProcessor>();
|
|
|
+ ServiceCollection.AddSingleton<IImageProcessor, ImageProcessor>();
|
|
|
|
|
|
- serviceCollection.AddSingleton<ITVSeriesManager, TVSeriesManager>();
|
|
|
+ ServiceCollection.AddSingleton<ITVSeriesManager, TVSeriesManager>();
|
|
|
|
|
|
- serviceCollection.AddSingleton<IDeviceManager, DeviceManager>();
|
|
|
+ ServiceCollection.AddSingleton<IDeviceManager, DeviceManager>();
|
|
|
|
|
|
- serviceCollection.AddSingleton<IMediaSourceManager, MediaSourceManager>();
|
|
|
+ ServiceCollection.AddSingleton<IMediaSourceManager, MediaSourceManager>();
|
|
|
|
|
|
- serviceCollection.AddSingleton<ISubtitleManager, SubtitleManager>();
|
|
|
+ ServiceCollection.AddSingleton<ISubtitleManager, SubtitleManager>();
|
|
|
|
|
|
- serviceCollection.AddSingleton<IProviderManager, ProviderManager>();
|
|
|
+ ServiceCollection.AddSingleton<IProviderManager, ProviderManager>();
|
|
|
|
|
|
// TODO: Refactor to eliminate the circular dependency here so that Lazy<T> isn't required
|
|
|
- serviceCollection.AddTransient(provider => new Lazy<ILiveTvManager>(provider.GetRequiredService<ILiveTvManager>));
|
|
|
- serviceCollection.AddSingleton<IDtoService, DtoService>();
|
|
|
+ ServiceCollection.AddTransient(provider => new Lazy<ILiveTvManager>(provider.GetRequiredService<ILiveTvManager>));
|
|
|
+ ServiceCollection.AddSingleton<IDtoService, DtoService>();
|
|
|
|
|
|
- serviceCollection.AddSingleton<IChannelManager, ChannelManager>();
|
|
|
+ ServiceCollection.AddSingleton<IChannelManager, ChannelManager>();
|
|
|
|
|
|
- serviceCollection.AddSingleton<ISessionManager, SessionManager>();
|
|
|
+ ServiceCollection.AddSingleton<ISessionManager, SessionManager>();
|
|
|
|
|
|
- serviceCollection.AddSingleton<IDlnaManager, DlnaManager>();
|
|
|
+ ServiceCollection.AddSingleton<IDlnaManager, DlnaManager>();
|
|
|
|
|
|
- serviceCollection.AddSingleton<ICollectionManager, CollectionManager>();
|
|
|
+ ServiceCollection.AddSingleton<ICollectionManager, CollectionManager>();
|
|
|
|
|
|
- serviceCollection.AddSingleton<IPlaylistManager, PlaylistManager>();
|
|
|
+ ServiceCollection.AddSingleton<IPlaylistManager, PlaylistManager>();
|
|
|
|
|
|
- serviceCollection.AddSingleton<ISyncPlayManager, SyncPlayManager>();
|
|
|
+ ServiceCollection.AddSingleton<ISyncPlayManager, SyncPlayManager>();
|
|
|
|
|
|
- serviceCollection.AddSingleton<LiveTvDtoService>();
|
|
|
- serviceCollection.AddSingleton<ILiveTvManager, LiveTvManager>();
|
|
|
+ ServiceCollection.AddSingleton<LiveTvDtoService>();
|
|
|
+ ServiceCollection.AddSingleton<ILiveTvManager, LiveTvManager>();
|
|
|
|
|
|
- serviceCollection.AddSingleton<IUserViewManager, UserViewManager>();
|
|
|
+ ServiceCollection.AddSingleton<IUserViewManager, UserViewManager>();
|
|
|
|
|
|
- serviceCollection.AddSingleton<INotificationManager, NotificationManager>();
|
|
|
+ ServiceCollection.AddSingleton<INotificationManager, NotificationManager>();
|
|
|
|
|
|
- serviceCollection.AddSingleton<IDeviceDiscovery, DeviceDiscovery>();
|
|
|
+ ServiceCollection.AddSingleton<IDeviceDiscovery, DeviceDiscovery>();
|
|
|
|
|
|
- serviceCollection.AddSingleton<IChapterManager, ChapterManager>();
|
|
|
+ ServiceCollection.AddSingleton<IChapterManager, ChapterManager>();
|
|
|
|
|
|
- serviceCollection.AddSingleton<IEncodingManager, MediaEncoder.EncodingManager>();
|
|
|
+ ServiceCollection.AddSingleton<IEncodingManager, MediaEncoder.EncodingManager>();
|
|
|
|
|
|
- serviceCollection.AddSingleton<IAuthorizationContext, AuthorizationContext>();
|
|
|
- serviceCollection.AddSingleton<ISessionContext, SessionContext>();
|
|
|
+ ServiceCollection.AddSingleton<IAuthorizationContext, AuthorizationContext>();
|
|
|
+ ServiceCollection.AddSingleton<ISessionContext, SessionContext>();
|
|
|
|
|
|
- serviceCollection.AddSingleton<IAuthService, AuthService>();
|
|
|
+ ServiceCollection.AddSingleton<IAuthService, AuthService>();
|
|
|
+ ServiceCollection.AddSingleton<IQuickConnect, QuickConnectManager>();
|
|
|
|
|
|
- serviceCollection.AddSingleton<ISubtitleEncoder, MediaBrowser.MediaEncoding.Subtitles.SubtitleEncoder>();
|
|
|
+ ServiceCollection.AddSingleton<ISubtitleEncoder, MediaBrowser.MediaEncoding.Subtitles.SubtitleEncoder>();
|
|
|
|
|
|
- serviceCollection.AddSingleton<IResourceFileManager, ResourceFileManager>();
|
|
|
- serviceCollection.AddSingleton<EncodingHelper>();
|
|
|
+ ServiceCollection.AddSingleton<IResourceFileManager, ResourceFileManager>();
|
|
|
+ ServiceCollection.AddSingleton<EncodingHelper>();
|
|
|
|
|
|
- serviceCollection.AddSingleton<IAttachmentExtractor, MediaBrowser.MediaEncoding.Attachments.AttachmentExtractor>();
|
|
|
+ ServiceCollection.AddSingleton<IAttachmentExtractor, MediaBrowser.MediaEncoding.Attachments.AttachmentExtractor>();
|
|
|
|
|
|
- serviceCollection.AddSingleton<TranscodingJobHelper>();
|
|
|
+ ServiceCollection.AddSingleton<TranscodingJobHelper>();
|
|
|
+ ServiceCollection.AddScoped<MediaInfoHelper>();
|
|
|
+ ServiceCollection.AddScoped<AudioHelper>();
|
|
|
+ ServiceCollection.AddScoped<DynamicHlsHelper>();
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
@@ -645,8 +665,7 @@ namespace Emby.Server.Implementations
|
|
|
|
|
|
_mediaEncoder = Resolve<IMediaEncoder>();
|
|
|
_sessionManager = Resolve<ISessionManager>();
|
|
|
- _httpServer = Resolve<IHttpServer>();
|
|
|
- _httpClient = Resolve<IHttpClient>();
|
|
|
+ _httpClientFactory = Resolve<IHttpClientFactory>();
|
|
|
|
|
|
((AuthenticationRepository)Resolve<IAuthenticationRepository>()).Initialize();
|
|
|
|
|
@@ -747,7 +766,6 @@ namespace Emby.Server.Implementations
|
|
|
CollectionFolder.XmlSerializer = _xmlSerializer;
|
|
|
CollectionFolder.JsonSerializer = Resolve<IJsonSerializer>();
|
|
|
CollectionFolder.ApplicationHost = this;
|
|
|
- AuthenticatedAttribute.AuthService = Resolve<IAuthService>();
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
@@ -767,7 +785,7 @@ namespace Emby.Server.Implementations
|
|
|
.Where(i => i != null)
|
|
|
.ToArray();
|
|
|
|
|
|
- _httpServer.Init(GetExportTypes<IService>(), GetExports<IWebSocketListener>(), GetUrlPrefixes());
|
|
|
+ _urlPrefixes = GetUrlPrefixes().ToArray();
|
|
|
|
|
|
Resolve<ILibraryManager>().AddParts(
|
|
|
GetExports<IResolverIgnoreRule>(),
|
|
@@ -800,37 +818,7 @@ namespace Emby.Server.Implementations
|
|
|
{
|
|
|
try
|
|
|
{
|
|
|
- if (plugin is IPluginAssembly assemblyPlugin)
|
|
|
- {
|
|
|
- var assembly = plugin.GetType().Assembly;
|
|
|
- var assemblyName = assembly.GetName();
|
|
|
- var assemblyFilePath = assembly.Location;
|
|
|
-
|
|
|
- var dataFolderPath = Path.Combine(ApplicationPaths.PluginsPath, Path.GetFileNameWithoutExtension(assemblyFilePath));
|
|
|
-
|
|
|
- assemblyPlugin.SetAttributes(assemblyFilePath, dataFolderPath, assemblyName.Version);
|
|
|
-
|
|
|
- try
|
|
|
- {
|
|
|
- var idAttributes = assembly.GetCustomAttributes(typeof(GuidAttribute), true);
|
|
|
- if (idAttributes.Length > 0)
|
|
|
- {
|
|
|
- var attribute = (GuidAttribute)idAttributes[0];
|
|
|
- var assemblyId = new Guid(attribute.Value);
|
|
|
-
|
|
|
- assemblyPlugin.SetId(assemblyId);
|
|
|
- }
|
|
|
- }
|
|
|
- catch (Exception ex)
|
|
|
- {
|
|
|
- Logger.LogError(ex, "Error getting plugin Id from {PluginName}.", plugin.GetType().FullName);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (plugin is IHasPluginConfiguration hasPluginConfiguration)
|
|
|
- {
|
|
|
- hasPluginConfiguration.SetStartupInfo(s => Directory.CreateDirectory(s));
|
|
|
- }
|
|
|
+ plugin.RegisterServices(ServiceCollection);
|
|
|
}
|
|
|
catch (Exception ex)
|
|
|
{
|
|
@@ -931,7 +919,7 @@ namespace Emby.Server.Implementations
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- if (!_httpServer.UrlPrefixes.SequenceEqual(GetUrlPrefixes(), StringComparer.OrdinalIgnoreCase))
|
|
|
+ if (!_urlPrefixes.SequenceEqual(GetUrlPrefixes(), StringComparer.OrdinalIgnoreCase))
|
|
|
{
|
|
|
requiresRestart = true;
|
|
|
}
|
|
@@ -1005,6 +993,119 @@ namespace Emby.Server.Implementations
|
|
|
|
|
|
protected abstract void RestartInternal();
|
|
|
|
|
|
+ /// <summary>
|
|
|
+ /// Comparison function used in <see cref="GetPlugins" />.
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="a">Item to compare.</param>
|
|
|
+ /// <param name="b">Item to compare with.</param>
|
|
|
+ /// <returns>Boolean result of the operation.</returns>
|
|
|
+ private static int VersionCompare(
|
|
|
+ (Version PluginVersion, string Name, string Path) a,
|
|
|
+ (Version PluginVersion, string Name, string Path) b)
|
|
|
+ {
|
|
|
+ int compare = string.Compare(a.Name, b.Name, true, CultureInfo.InvariantCulture);
|
|
|
+
|
|
|
+ if (compare == 0)
|
|
|
+ {
|
|
|
+ return a.PluginVersion.CompareTo(b.PluginVersion);
|
|
|
+ }
|
|
|
+
|
|
|
+ return compare;
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// Returns a list of plugins to install.
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="path">Path to check.</param>
|
|
|
+ /// <param name="cleanup">True if an attempt should be made to delete old plugs.</param>
|
|
|
+ /// <returns>Enumerable list of dlls to load.</returns>
|
|
|
+ private IEnumerable<string> GetPlugins(string path, bool cleanup = true)
|
|
|
+ {
|
|
|
+ var dllList = new List<string>();
|
|
|
+ var versions = new List<(Version PluginVersion, string Name, string Path)>();
|
|
|
+ var directories = Directory.EnumerateDirectories(path, "*.*", SearchOption.TopDirectoryOnly);
|
|
|
+ string metafile;
|
|
|
+
|
|
|
+ foreach (var dir in directories)
|
|
|
+ {
|
|
|
+ try
|
|
|
+ {
|
|
|
+ metafile = Path.Combine(dir, "meta.json");
|
|
|
+ if (File.Exists(metafile))
|
|
|
+ {
|
|
|
+ var manifest = _jsonSerializer.DeserializeFromFile<PluginManifest>(metafile);
|
|
|
+
|
|
|
+ if (!Version.TryParse(manifest.TargetAbi, out var targetAbi))
|
|
|
+ {
|
|
|
+ targetAbi = new Version(0, 0, 0, 1);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!Version.TryParse(manifest.Version, out var version))
|
|
|
+ {
|
|
|
+ version = new Version(0, 0, 0, 1);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (ApplicationVersion >= targetAbi)
|
|
|
+ {
|
|
|
+ // Only load Plugins if the plugin is built for this version or below.
|
|
|
+ versions.Add((version, manifest.Name, dir));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ // No metafile, so lets see if the folder is versioned.
|
|
|
+ metafile = dir.Split(new[] { Path.DirectorySeparatorChar }, StringSplitOptions.RemoveEmptyEntries)[^1];
|
|
|
+
|
|
|
+ int versionIndex = dir.LastIndexOf('_');
|
|
|
+ if (versionIndex != -1 && Version.TryParse(dir.Substring(versionIndex + 1), out Version ver))
|
|
|
+ {
|
|
|
+ // Versioned folder.
|
|
|
+ versions.Add((ver, metafile, dir));
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ // Un-versioned folder - Add it under the path name and version 0.0.0.1.
|
|
|
+ versions.Add((new Version(0, 0, 0, 1), metafile, dir));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ catch
|
|
|
+ {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ string lastName = string.Empty;
|
|
|
+ versions.Sort(VersionCompare);
|
|
|
+ // Traverse backwards through the list.
|
|
|
+ // The first item will be the latest version.
|
|
|
+ for (int x = versions.Count - 1; x >= 0; x--)
|
|
|
+ {
|
|
|
+ if (!string.Equals(lastName, versions[x].Name, StringComparison.OrdinalIgnoreCase))
|
|
|
+ {
|
|
|
+ dllList.AddRange(Directory.EnumerateFiles(versions[x].Path, "*.dll", SearchOption.AllDirectories));
|
|
|
+ lastName = versions[x].Name;
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!string.IsNullOrEmpty(lastName) && cleanup)
|
|
|
+ {
|
|
|
+ // Attempt a cleanup of old folders.
|
|
|
+ try
|
|
|
+ {
|
|
|
+ Logger.LogDebug("Deleting {Path}", versions[x].Path);
|
|
|
+ Directory.Delete(versions[x].Path, true);
|
|
|
+ }
|
|
|
+ catch (Exception e)
|
|
|
+ {
|
|
|
+ Logger.LogWarning(e, "Unable to delete {Path}", versions[x].Path);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return dllList;
|
|
|
+ }
|
|
|
+
|
|
|
/// <summary>
|
|
|
/// Gets the composable part assemblies.
|
|
|
/// </summary>
|
|
@@ -1013,7 +1114,7 @@ namespace Emby.Server.Implementations
|
|
|
{
|
|
|
if (Directory.Exists(ApplicationPaths.PluginsPath))
|
|
|
{
|
|
|
- foreach (var file in Directory.EnumerateFiles(ApplicationPaths.PluginsPath, "*.dll", SearchOption.AllDirectories))
|
|
|
+ foreach (var file in GetPlugins(ApplicationPaths.PluginsPath))
|
|
|
{
|
|
|
Assembly plugAss;
|
|
|
try
|
|
@@ -1127,7 +1228,8 @@ namespace Emby.Server.Implementations
|
|
|
Id = SystemId,
|
|
|
OperatingSystem = OperatingSystem.Id.ToString(),
|
|
|
ServerName = FriendlyName,
|
|
|
- LocalAddress = localAddress
|
|
|
+ LocalAddress = localAddress,
|
|
|
+ StartupWizardCompleted = ConfigurationManager.CommonConfiguration.IsStartupWizardCompleted
|
|
|
};
|
|
|
}
|
|
|
|
|
@@ -1289,25 +1391,17 @@ namespace Emby.Server.Implementations
|
|
|
|
|
|
try
|
|
|
{
|
|
|
- using (var response = await _httpClient.SendAsync(
|
|
|
- new HttpRequestOptions
|
|
|
- {
|
|
|
- Url = apiUrl,
|
|
|
- LogErrorResponseBody = false,
|
|
|
- BufferContent = false,
|
|
|
- CancellationToken = cancellationToken
|
|
|
- }, HttpMethod.Post).ConfigureAwait(false))
|
|
|
- {
|
|
|
- using (var reader = new StreamReader(response.Content))
|
|
|
- {
|
|
|
- var result = await reader.ReadToEndAsync().ConfigureAwait(false);
|
|
|
- var valid = string.Equals(Name, result, StringComparison.OrdinalIgnoreCase);
|
|
|
+ using var request = new HttpRequestMessage(HttpMethod.Post, apiUrl);
|
|
|
+ using var response = await _httpClientFactory.CreateClient(NamedClient.Default)
|
|
|
+ .SendAsync(request, HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false);
|
|
|
|
|
|
- _validAddressResults.AddOrUpdate(apiUrl, valid, (k, v) => valid);
|
|
|
- Logger.LogDebug("Ping test result to {0}. Success: {1}", apiUrl, valid);
|
|
|
- return valid;
|
|
|
- }
|
|
|
- }
|
|
|
+ await using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false);
|
|
|
+ var result = await System.Text.Json.JsonSerializer.DeserializeAsync<string>(stream, JsonDefaults.GetOptions(), cancellationToken).ConfigureAwait(false);
|
|
|
+ var valid = string.Equals(Name, result, StringComparison.OrdinalIgnoreCase);
|
|
|
+
|
|
|
+ _validAddressResults.AddOrUpdate(apiUrl, valid, (k, v) => valid);
|
|
|
+ Logger.LogDebug("Ping test result to {0}. Success: {1}", apiUrl, valid);
|
|
|
+ return valid;
|
|
|
}
|
|
|
catch (OperationCanceledException)
|
|
|
{
|
|
@@ -1385,6 +1479,20 @@ namespace Emby.Server.Implementations
|
|
|
_plugins = list.ToArray();
|
|
|
}
|
|
|
|
|
|
+ public IEnumerable<Assembly> GetApiPluginAssemblies()
|
|
|
+ {
|
|
|
+ var assemblies = _allConcreteTypes
|
|
|
+ .Where(i => typeof(ControllerBase).IsAssignableFrom(i))
|
|
|
+ .Select(i => i.Assembly)
|
|
|
+ .Distinct();
|
|
|
+
|
|
|
+ foreach (var assembly in assemblies)
|
|
|
+ {
|
|
|
+ Logger.LogDebug("Found API endpoints in plugin {Name}", assembly.FullName);
|
|
|
+ yield return assembly;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
public virtual void LaunchUrl(string url)
|
|
|
{
|
|
|
if (!CanLaunchWebBrowser)
|
|
@@ -1415,10 +1523,6 @@ namespace Emby.Server.Implementations
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- public virtual void EnableLoopback(string appName)
|
|
|
- {
|
|
|
- }
|
|
|
-
|
|
|
private bool _disposed = false;
|
|
|
|
|
|
/// <summary>
|