using System; using System.IO; using System.Threading; using System.Threading.Tasks; using Jellyfin.Server.Implementations; using MediaBrowser.Common.Configuration; using Microsoft.Data.Sqlite; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; namespace Jellyfin.Database.Providers.Sqlite; /// /// Configures jellyfin to use an SQLite database. /// [JellyfinDatabaseProviderKey("Jellyfin-SQLite")] public sealed class SqliteDatabaseProvider : IJellyfinDatabaseProvider { private readonly IApplicationPaths _applicationPaths; private readonly ILogger _logger; /// /// Initializes a new instance of the class. /// /// Service to construct the fallback when the old data path configuration is used. /// A logger. public SqliteDatabaseProvider(IApplicationPaths applicationPaths, ILogger logger) { _applicationPaths = applicationPaths; _logger = logger; } /// public IDbContextFactory? DbContextFactory { get; set; } /// public void Initialise(DbContextOptionsBuilder options) { options.UseSqlite( $"Filename={Path.Combine(_applicationPaths.DataPath, "jellyfin.db")};Pooling=false", sqLiteOptions => sqLiteOptions.MigrationsAssembly(GetType().Assembly)); } /// public async Task RunScheduledOptimisation(CancellationToken cancellationToken) { var context = await DbContextFactory!.CreateDbContextAsync(cancellationToken).ConfigureAwait(false); await using (context.ConfigureAwait(false)) { if (context.Database.IsSqlite()) { await context.Database.ExecuteSqlRawAsync("PRAGMA optimize", cancellationToken).ConfigureAwait(false); await context.Database.ExecuteSqlRawAsync("VACUUM", cancellationToken).ConfigureAwait(false); _logger.LogInformation("jellyfin.db optimized successfully!"); } else { _logger.LogInformation("This database doesn't support optimization"); } } } /// public void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.SetDefaultDateTimeKind(DateTimeKind.Utc); } /// public async Task RunShutdownTask(CancellationToken cancellationToken) { // Run before disposing the application var context = await DbContextFactory!.CreateDbContextAsync(cancellationToken).ConfigureAwait(false); await using (context.ConfigureAwait(false)) { await context.Database.ExecuteSqlRawAsync("PRAGMA optimize", cancellationToken).ConfigureAwait(false); } SqliteConnection.ClearAllPools(); } /// public void ConfigureConventions(ModelConfigurationBuilder configurationBuilder) { configurationBuilder.Conventions.Add(_ => new DoNotUseReturningClauseConvention()); } }