using System; using System.Linq; using Emby.Server.Implementations.MediaEncoding; using MediaBrowser.Controller.MediaEncoding; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using StackExchange.Redis; namespace Jellyfin.Server.Extensions; /// /// Extensions for registering the transcode session store. /// public static class TranscodeStoreServiceCollectionExtensions { /// /// Registers the transcode session store, Redis-backed when a connection string is configured and /// no-op otherwise, and reports the selected store at . /// /// The service collection. /// The configuration to read Jellyfin:TranscodeStore from. /// The logger to report the selected store on. /// The updated service collection. public static IServiceCollection AddTranscodeSessionStore( this IServiceCollection serviceCollection, IConfiguration configuration, ILogger logger) { ArgumentNullException.ThrowIfNull(configuration); ArgumentNullException.ThrowIfNull(logger); serviceCollection.Configure(configuration.GetSection(TranscodeStoreOptions.ConfigurationSection)); var redisConnectionString = configuration[TranscodeStoreOptions.RedisConnectionStringKey]; if (string.IsNullOrEmpty(redisConnectionString)) { logger.LogInformation( "Transcode session store: {Store}. Cross-pod transcode takeover is off; set {Key} to enable it.", nameof(NullTranscodeSessionStore), TranscodeStoreOptions.RedisConnectionStringKey); return serviceCollection.AddSingleton(); } logger.LogInformation( "Transcode session store: {Store} on {Endpoints}.", nameof(RedisTranscodeSessionStore), DescribeEndpoints(redisConnectionString)); serviceCollection.AddSingleton(sp => { try { return ConnectionMultiplexer.Connect(redisConnectionString); } catch (Exception ex) { sp.GetRequiredService>() .LogError(ex, "Failed to connect to Redis. Check the {Key} configuration.", TranscodeStoreOptions.RedisConnectionStringKey); throw; } }); serviceCollection.AddSingleton(); serviceCollection.AddHostedService(); return serviceCollection; } /// /// Renders the endpoints of a connection string for logging. The connection string itself is never /// logged because it can carry a password. /// private static string DescribeEndpoints(string redisConnectionString) { try { return string.Join( ',', ConfigurationOptions.Parse(redisConnectionString).EndPoints.Select(endpoint => endpoint.ToString())); } catch (ArgumentException) { return "(unparsable connection string)"; } } }