mirror of
				https://github.com/jellyfin/jellyfin.git
				synced 2025-11-03 19:17:24 -05:00 
			
		
		
		
	
		
			
				
	
	
		
			233 lines
		
	
	
		
			9.7 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			233 lines
		
	
	
		
			9.7 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
using System;
 | 
						|
using System.Net;
 | 
						|
using System.Net.Http;
 | 
						|
using System.Net.Http.Headers;
 | 
						|
using System.Net.Mime;
 | 
						|
using System.Text;
 | 
						|
using Emby.Server.Implementations.EntryPoints;
 | 
						|
using Jellyfin.Api.Middleware;
 | 
						|
using Jellyfin.LiveTv.Extensions;
 | 
						|
using Jellyfin.LiveTv.Recordings;
 | 
						|
using Jellyfin.MediaEncoding.Hls.Extensions;
 | 
						|
using Jellyfin.Networking;
 | 
						|
using Jellyfin.Networking.HappyEyeballs;
 | 
						|
using Jellyfin.Server.Extensions;
 | 
						|
using Jellyfin.Server.HealthChecks;
 | 
						|
using Jellyfin.Server.Implementations;
 | 
						|
using Jellyfin.Server.Implementations.Extensions;
 | 
						|
using Jellyfin.Server.Infrastructure;
 | 
						|
using MediaBrowser.Common.Net;
 | 
						|
using MediaBrowser.Controller.Configuration;
 | 
						|
using MediaBrowser.Controller.Extensions;
 | 
						|
using MediaBrowser.XbmcMetadata;
 | 
						|
using Microsoft.AspNetCore.Builder;
 | 
						|
using Microsoft.AspNetCore.Hosting;
 | 
						|
using Microsoft.AspNetCore.Mvc;
 | 
						|
using Microsoft.AspNetCore.Mvc.Infrastructure;
 | 
						|
using Microsoft.AspNetCore.StaticFiles;
 | 
						|
using Microsoft.Extensions.Configuration;
 | 
						|
using Microsoft.Extensions.DependencyInjection;
 | 
						|
using Microsoft.Extensions.FileProviders;
 | 
						|
using Microsoft.Extensions.Hosting;
 | 
						|
using Prometheus;
 | 
						|
 | 
						|
namespace Jellyfin.Server
 | 
						|
{
 | 
						|
    /// <summary>
 | 
						|
    /// Startup configuration for the Kestrel webhost.
 | 
						|
    /// </summary>
 | 
						|
    public class Startup
 | 
						|
    {
 | 
						|
        private readonly CoreAppHost _serverApplicationHost;
 | 
						|
        private readonly IServerConfigurationManager _serverConfigurationManager;
 | 
						|
 | 
						|
        /// <summary>
 | 
						|
        /// Initializes a new instance of the <see cref="Startup" /> class.
 | 
						|
        /// </summary>
 | 
						|
        /// <param name="appHost">The server application host.</param>
 | 
						|
        public Startup(CoreAppHost appHost)
 | 
						|
        {
 | 
						|
            _serverApplicationHost = appHost;
 | 
						|
            _serverConfigurationManager = appHost.ConfigurationManager;
 | 
						|
        }
 | 
						|
 | 
						|
        /// <summary>
 | 
						|
        /// Configures the service collection for the webhost.
 | 
						|
        /// </summary>
 | 
						|
        /// <param name="services">The service collection.</param>
 | 
						|
        public void ConfigureServices(IServiceCollection services)
 | 
						|
        {
 | 
						|
            services.AddResponseCompression();
 | 
						|
            services.AddHttpContextAccessor();
 | 
						|
            services.AddHttpsRedirection(options =>
 | 
						|
            {
 | 
						|
                options.HttpsPort = _serverApplicationHost.HttpsPort;
 | 
						|
            });
 | 
						|
 | 
						|
            // TODO remove once this is fixed upstream https://github.com/dotnet/aspnetcore/issues/34371
 | 
						|
            services.AddSingleton<IActionResultExecutor<PhysicalFileResult>, SymlinkFollowingPhysicalFileResultExecutor>();
 | 
						|
            services.AddJellyfinApi(_serverApplicationHost.GetApiPluginAssemblies(), _serverConfigurationManager.GetNetworkConfiguration());
 | 
						|
            services.AddJellyfinDbContext();
 | 
						|
            services.AddJellyfinApiSwagger();
 | 
						|
 | 
						|
            // configure custom legacy authentication
 | 
						|
            services.AddCustomAuthentication();
 | 
						|
 | 
						|
            services.AddJellyfinApiAuthorization();
 | 
						|
 | 
						|
            var productHeader = new ProductInfoHeaderValue(
 | 
						|
                _serverApplicationHost.Name.Replace(' ', '-'),
 | 
						|
                _serverApplicationHost.ApplicationVersionString);
 | 
						|
            var acceptJsonHeader = new MediaTypeWithQualityHeaderValue(MediaTypeNames.Application.Json, 1.0);
 | 
						|
            var acceptXmlHeader = new MediaTypeWithQualityHeaderValue(MediaTypeNames.Application.Xml, 0.9);
 | 
						|
            var acceptAnyHeader = new MediaTypeWithQualityHeaderValue("*/*", 0.8);
 | 
						|
            Func<IServiceProvider, HttpMessageHandler> eyeballsHttpClientHandlerDelegate = (_) => new SocketsHttpHandler()
 | 
						|
            {
 | 
						|
                AutomaticDecompression = DecompressionMethods.All,
 | 
						|
                RequestHeaderEncodingSelector = (_, _) => Encoding.UTF8,
 | 
						|
                ConnectCallback = HttpClientExtension.OnConnect
 | 
						|
            };
 | 
						|
 | 
						|
            Func<IServiceProvider, HttpMessageHandler> defaultHttpClientHandlerDelegate = (_) => new SocketsHttpHandler()
 | 
						|
            {
 | 
						|
                AutomaticDecompression = DecompressionMethods.All,
 | 
						|
                RequestHeaderEncodingSelector = (_, _) => Encoding.UTF8
 | 
						|
            };
 | 
						|
 | 
						|
            services.AddHttpClient(NamedClient.Default, c =>
 | 
						|
                {
 | 
						|
                    c.DefaultRequestHeaders.UserAgent.Add(productHeader);
 | 
						|
                    c.DefaultRequestHeaders.Accept.Add(acceptJsonHeader);
 | 
						|
                    c.DefaultRequestHeaders.Accept.Add(acceptXmlHeader);
 | 
						|
                    c.DefaultRequestHeaders.Accept.Add(acceptAnyHeader);
 | 
						|
                })
 | 
						|
                .ConfigurePrimaryHttpMessageHandler(eyeballsHttpClientHandlerDelegate);
 | 
						|
 | 
						|
            services.AddHttpClient(NamedClient.MusicBrainz, c =>
 | 
						|
                {
 | 
						|
                    c.DefaultRequestHeaders.UserAgent.Add(productHeader);
 | 
						|
                    c.DefaultRequestHeaders.UserAgent.Add(new ProductInfoHeaderValue($"({_serverApplicationHost.ApplicationUserAgentAddress})"));
 | 
						|
                    c.DefaultRequestHeaders.Accept.Add(acceptXmlHeader);
 | 
						|
                    c.DefaultRequestHeaders.Accept.Add(acceptAnyHeader);
 | 
						|
                })
 | 
						|
                .ConfigurePrimaryHttpMessageHandler(eyeballsHttpClientHandlerDelegate);
 | 
						|
 | 
						|
            services.AddHttpClient(NamedClient.DirectIp, c =>
 | 
						|
                {
 | 
						|
                    c.DefaultRequestHeaders.UserAgent.Add(productHeader);
 | 
						|
                    c.DefaultRequestHeaders.Accept.Add(acceptJsonHeader);
 | 
						|
                    c.DefaultRequestHeaders.Accept.Add(acceptXmlHeader);
 | 
						|
                    c.DefaultRequestHeaders.Accept.Add(acceptAnyHeader);
 | 
						|
                })
 | 
						|
                .ConfigurePrimaryHttpMessageHandler(defaultHttpClientHandlerDelegate);
 | 
						|
 | 
						|
            services.AddHealthChecks()
 | 
						|
                .AddCheck<DbContextFactoryHealthCheck<JellyfinDbContext>>(nameof(JellyfinDbContext));
 | 
						|
 | 
						|
            services.AddHlsPlaylistGenerator();
 | 
						|
            services.AddLiveTvServices();
 | 
						|
 | 
						|
            services.AddHostedService<RecordingsHost>();
 | 
						|
            services.AddHostedService<AutoDiscoveryHost>();
 | 
						|
            services.AddHostedService<NfoUserDataSaver>();
 | 
						|
            services.AddHostedService<LibraryChangedNotifier>();
 | 
						|
            services.AddHostedService<UserDataChangeNotifier>();
 | 
						|
            services.AddHostedService<RecordingNotifier>();
 | 
						|
        }
 | 
						|
 | 
						|
        /// <summary>
 | 
						|
        /// Configures the app builder for the webhost.
 | 
						|
        /// </summary>
 | 
						|
        /// <param name="app">The application builder.</param>
 | 
						|
        /// <param name="env">The webhost environment.</param>
 | 
						|
        /// <param name="appConfig">The application config.</param>
 | 
						|
        public void Configure(
 | 
						|
            IApplicationBuilder app,
 | 
						|
            IWebHostEnvironment env,
 | 
						|
            IConfiguration appConfig)
 | 
						|
        {
 | 
						|
            app.UseBaseUrlRedirection();
 | 
						|
 | 
						|
            // Wrap rest of configuration so everything only listens on BaseUrl.
 | 
						|
            var config = _serverConfigurationManager.GetNetworkConfiguration();
 | 
						|
            app.Map(config.BaseUrl, mainApp =>
 | 
						|
            {
 | 
						|
                if (env.IsDevelopment())
 | 
						|
                {
 | 
						|
                    mainApp.UseDeveloperExceptionPage();
 | 
						|
                }
 | 
						|
 | 
						|
                mainApp.UseForwardedHeaders();
 | 
						|
                mainApp.UseMiddleware<ExceptionMiddleware>();
 | 
						|
 | 
						|
                mainApp.UseMiddleware<ResponseTimeMiddleware>();
 | 
						|
 | 
						|
                mainApp.UseWebSockets();
 | 
						|
 | 
						|
                mainApp.UseResponseCompression();
 | 
						|
 | 
						|
                mainApp.UseCors();
 | 
						|
 | 
						|
                if (config.RequireHttps && _serverApplicationHost.ListenWithHttps)
 | 
						|
                {
 | 
						|
                    mainApp.UseHttpsRedirection();
 | 
						|
                }
 | 
						|
 | 
						|
                // This must be injected before any path related middleware.
 | 
						|
                mainApp.UsePathTrim();
 | 
						|
 | 
						|
                if (appConfig.HostWebClient())
 | 
						|
                {
 | 
						|
                    var extensionProvider = new FileExtensionContentTypeProvider();
 | 
						|
 | 
						|
                    // subtitles octopus requires .data, .mem files.
 | 
						|
                    extensionProvider.Mappings.Add(".data", MediaTypeNames.Application.Octet);
 | 
						|
                    extensionProvider.Mappings.Add(".mem", MediaTypeNames.Application.Octet);
 | 
						|
                    mainApp.UseDefaultFiles(new DefaultFilesOptions
 | 
						|
                    {
 | 
						|
                        FileProvider = new PhysicalFileProvider(_serverConfigurationManager.ApplicationPaths.WebPath),
 | 
						|
                        RequestPath = "/web"
 | 
						|
                    });
 | 
						|
                    mainApp.UseStaticFiles(new StaticFileOptions
 | 
						|
                    {
 | 
						|
                        FileProvider = new PhysicalFileProvider(_serverConfigurationManager.ApplicationPaths.WebPath),
 | 
						|
                        RequestPath = "/web",
 | 
						|
                        ContentTypeProvider = extensionProvider
 | 
						|
                    });
 | 
						|
 | 
						|
                    mainApp.UseRobotsRedirection();
 | 
						|
                }
 | 
						|
 | 
						|
                mainApp.UseStaticFiles();
 | 
						|
                mainApp.UseAuthentication();
 | 
						|
                mainApp.UseJellyfinApiSwagger(_serverConfigurationManager);
 | 
						|
                mainApp.UseQueryStringDecoding();
 | 
						|
                mainApp.UseRouting();
 | 
						|
                mainApp.UseAuthorization();
 | 
						|
 | 
						|
                mainApp.UseLanFiltering();
 | 
						|
                mainApp.UseIPBasedAccessValidation();
 | 
						|
                mainApp.UseWebSocketHandler();
 | 
						|
                mainApp.UseServerStartupMessage();
 | 
						|
 | 
						|
                if (_serverConfigurationManager.Configuration.EnableMetrics)
 | 
						|
                {
 | 
						|
                    // Must be registered after any middleware that could change HTTP response codes or the data will be bad
 | 
						|
                    mainApp.UseHttpMetrics();
 | 
						|
                }
 | 
						|
 | 
						|
                mainApp.UseEndpoints(endpoints =>
 | 
						|
                {
 | 
						|
                    endpoints.MapControllers();
 | 
						|
                    if (_serverConfigurationManager.Configuration.EnableMetrics)
 | 
						|
                    {
 | 
						|
                        endpoints.MapMetrics();
 | 
						|
                    }
 | 
						|
 | 
						|
                    endpoints.MapHealthChecks("/health");
 | 
						|
                });
 | 
						|
            });
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 |