diff --git a/Directory.Packages.props b/Directory.Packages.props index bd2a1d1811..06fb1ce14a 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -73,8 +73,6 @@ - - diff --git a/Jellyfin.Server/Extensions/SqliteExtensions.cs b/Jellyfin.Server/Extensions/SqliteExtensions.cs deleted file mode 100644 index 0e6a1bb13f..0000000000 --- a/Jellyfin.Server/Extensions/SqliteExtensions.cs +++ /dev/null @@ -1,449 +0,0 @@ -#nullable disable -#pragma warning disable CS1591 - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Globalization; -using SQLitePCL.pretty; - -namespace Jellyfin.Server.Extensions -{ - public static class SqliteExtensions - { - private const string DatetimeFormatUtc = "yyyy-MM-dd HH:mm:ss.FFFFFFFK"; - private const string DatetimeFormatLocal = "yyyy-MM-dd HH:mm:ss.FFFFFFF"; - - /// - /// An array of ISO-8601 DateTime formats that we support parsing. - /// - private static readonly string[] _datetimeFormats = new string[] - { - "THHmmssK", - "THHmmK", - "HH:mm:ss.FFFFFFFK", - "HH:mm:ssK", - "HH:mmK", - DatetimeFormatUtc, - "yyyy-MM-dd HH:mm:ssK", - "yyyy-MM-dd HH:mmK", - "yyyy-MM-ddTHH:mm:ss.FFFFFFFK", - "yyyy-MM-ddTHH:mmK", - "yyyy-MM-ddTHH:mm:ssK", - "yyyyMMddHHmmssK", - "yyyyMMddHHmmK", - "yyyyMMddTHHmmssFFFFFFFK", - "THHmmss", - "THHmm", - "HH:mm:ss.FFFFFFF", - "HH:mm:ss", - "HH:mm", - DatetimeFormatLocal, - "yyyy-MM-dd HH:mm:ss", - "yyyy-MM-dd HH:mm", - "yyyy-MM-ddTHH:mm:ss.FFFFFFF", - "yyyy-MM-ddTHH:mm", - "yyyy-MM-ddTHH:mm:ss", - "yyyyMMddHHmmss", - "yyyyMMddHHmm", - "yyyyMMddTHHmmssFFFFFFF", - "yyyy-MM-dd", - "yyyyMMdd", - "yy-MM-dd" - }; - - public static void RunQueries(this SQLiteDatabaseConnection connection, string[] queries) - { - ArgumentNullException.ThrowIfNull(queries); - - connection.RunInTransaction(conn => - { - conn.ExecuteAll(string.Join(';', queries)); - }); - } - - public static Guid ReadGuidFromBlob(this ResultSetValue result) - { - return new Guid(result.ToBlob()); - } - - public static string ToDateTimeParamValue(this DateTime dateValue) - { - var kind = DateTimeKind.Utc; - - return (dateValue.Kind == DateTimeKind.Unspecified) - ? DateTime.SpecifyKind(dateValue, kind).ToString( - GetDateTimeKindFormat(kind), - CultureInfo.InvariantCulture) - : dateValue.ToString( - GetDateTimeKindFormat(dateValue.Kind), - CultureInfo.InvariantCulture); - } - - private static string GetDateTimeKindFormat(DateTimeKind kind) - => (kind == DateTimeKind.Utc) ? DatetimeFormatUtc : DatetimeFormatLocal; - - public static DateTime ReadDateTime(this ResultSetValue result) - { - var dateText = result.ToString(); - - return DateTime.ParseExact( - dateText, - _datetimeFormats, - DateTimeFormatInfo.InvariantInfo, - DateTimeStyles.AdjustToUniversal); - } - - public static bool TryReadDateTime(this IReadOnlyList reader, int index, out DateTime result) - { - var item = reader[index]; - if (item.IsDbNull()) - { - result = default; - return false; - } - - var dateText = item.ToString(); - - if (DateTime.TryParseExact(dateText, _datetimeFormats, DateTimeFormatInfo.InvariantInfo, DateTimeStyles.AdjustToUniversal, out var dateTimeResult)) - { - result = dateTimeResult; - return true; - } - - result = default; - return false; - } - - public static bool TryGetGuid(this IReadOnlyList reader, int index, out Guid result) - { - var item = reader[index]; - if (item.IsDbNull()) - { - result = default; - return false; - } - - result = item.ReadGuidFromBlob(); - return true; - } - - public static bool IsDbNull(this ResultSetValue result) - { - return result.SQLiteType == SQLiteType.Null; - } - - public static string GetString(this IReadOnlyList result, int index) - { - return result[index].ToString(); - } - - public static bool TryGetString(this IReadOnlyList reader, int index, out string result) - { - result = null; - var item = reader[index]; - if (item.IsDbNull()) - { - return false; - } - - result = item.ToString(); - return true; - } - - public static bool GetBoolean(this IReadOnlyList result, int index) - { - return result[index].ToBool(); - } - - public static bool TryGetBoolean(this IReadOnlyList reader, int index, out bool result) - { - var item = reader[index]; - if (item.IsDbNull()) - { - result = default; - return false; - } - - result = item.ToBool(); - return true; - } - - public static bool TryGetInt32(this IReadOnlyList reader, int index, out int result) - { - var item = reader[index]; - if (item.IsDbNull()) - { - result = default; - return false; - } - - result = item.ToInt(); - return true; - } - - public static long GetInt64(this IReadOnlyList result, int index) - { - return result[index].ToInt64(); - } - - public static bool TryGetInt64(this IReadOnlyList reader, int index, out long result) - { - var item = reader[index]; - if (item.IsDbNull()) - { - result = default; - return false; - } - - result = item.ToInt64(); - return true; - } - - public static bool TryGetSingle(this IReadOnlyList reader, int index, out float result) - { - var item = reader[index]; - if (item.IsDbNull()) - { - result = default; - return false; - } - - result = item.ToFloat(); - return true; - } - - public static bool TryGetDouble(this IReadOnlyList reader, int index, out double result) - { - var item = reader[index]; - if (item.IsDbNull()) - { - result = default; - return false; - } - - result = item.ToDouble(); - return true; - } - - public static Guid GetGuid(this IReadOnlyList result, int index) - { - return result[index].ReadGuidFromBlob(); - } - - [Conditional("DEBUG")] - private static void CheckName(string name) - { - throw new ArgumentException("Invalid param name: " + name, nameof(name)); - } - - public static void TryBind(this IStatement statement, string name, double value) - { - if (statement.BindParameters.TryGetValue(name, out IBindParameter bindParam)) - { - bindParam.Bind(value); - } - else - { - CheckName(name); - } - } - - public static void TryBind(this IStatement statement, string name, string value) - { - if (statement.BindParameters.TryGetValue(name, out IBindParameter bindParam)) - { - if (value is null) - { - bindParam.BindNull(); - } - else - { - bindParam.Bind(value); - } - } - else - { - CheckName(name); - } - } - - public static void TryBind(this IStatement statement, string name, bool value) - { - if (statement.BindParameters.TryGetValue(name, out IBindParameter bindParam)) - { - bindParam.Bind(value); - } - else - { - CheckName(name); - } - } - - public static void TryBind(this IStatement statement, string name, float value) - { - if (statement.BindParameters.TryGetValue(name, out IBindParameter bindParam)) - { - bindParam.Bind(value); - } - else - { - CheckName(name); - } - } - - public static void TryBind(this IStatement statement, string name, int value) - { - if (statement.BindParameters.TryGetValue(name, out IBindParameter bindParam)) - { - bindParam.Bind(value); - } - else - { - CheckName(name); - } - } - - public static void TryBind(this IStatement statement, string name, Guid value) - { - if (statement.BindParameters.TryGetValue(name, out IBindParameter bindParam)) - { - Span byteValue = stackalloc byte[16]; - value.TryWriteBytes(byteValue); - bindParam.Bind(byteValue); - } - else - { - CheckName(name); - } - } - - public static void TryBind(this IStatement statement, string name, DateTime value) - { - if (statement.BindParameters.TryGetValue(name, out IBindParameter bindParam)) - { - bindParam.Bind(value.ToDateTimeParamValue()); - } - else - { - CheckName(name); - } - } - - public static void TryBind(this IStatement statement, string name, long value) - { - if (statement.BindParameters.TryGetValue(name, out IBindParameter bindParam)) - { - bindParam.Bind(value); - } - else - { - CheckName(name); - } - } - - public static void TryBind(this IStatement statement, string name, ReadOnlySpan value) - { - if (statement.BindParameters.TryGetValue(name, out IBindParameter bindParam)) - { - bindParam.Bind(value); - } - else - { - CheckName(name); - } - } - - public static void TryBindNull(this IStatement statement, string name) - { - if (statement.BindParameters.TryGetValue(name, out IBindParameter bindParam)) - { - bindParam.BindNull(); - } - else - { - CheckName(name); - } - } - - public static void TryBind(this IStatement statement, string name, DateTime? value) - { - if (value.HasValue) - { - TryBind(statement, name, value.Value); - } - else - { - TryBindNull(statement, name); - } - } - - public static void TryBind(this IStatement statement, string name, Guid? value) - { - if (value.HasValue) - { - TryBind(statement, name, value.Value); - } - else - { - TryBindNull(statement, name); - } - } - - public static void TryBind(this IStatement statement, string name, double? value) - { - if (value.HasValue) - { - TryBind(statement, name, value.Value); - } - else - { - TryBindNull(statement, name); - } - } - - public static void TryBind(this IStatement statement, string name, int? value) - { - if (value.HasValue) - { - TryBind(statement, name, value.Value); - } - else - { - TryBindNull(statement, name); - } - } - - public static void TryBind(this IStatement statement, string name, float? value) - { - if (value.HasValue) - { - TryBind(statement, name, value.Value); - } - else - { - TryBindNull(statement, name); - } - } - - public static void TryBind(this IStatement statement, string name, bool? value) - { - if (value.HasValue) - { - TryBind(statement, name, value.Value); - } - else - { - TryBindNull(statement, name); - } - } - - public static IEnumerable> ExecuteQuery(this IStatement statement) - { - while (statement.MoveNext()) - { - yield return statement.Current; - } - } - } -} diff --git a/Jellyfin.Server/Jellyfin.Server.csproj b/Jellyfin.Server/Jellyfin.Server.csproj index a881e7cb4e..60d9849a32 100644 --- a/Jellyfin.Server/Jellyfin.Server.csproj +++ b/Jellyfin.Server/Jellyfin.Server.csproj @@ -47,8 +47,6 @@ - - diff --git a/Jellyfin.Server/Migrations/Routines/MigrateActivityLogDb.cs b/Jellyfin.Server/Migrations/Routines/MigrateActivityLogDb.cs index 5f44ba2caf..c7c9c12501 100644 --- a/Jellyfin.Server/Migrations/Routines/MigrateActivityLogDb.cs +++ b/Jellyfin.Server/Migrations/Routines/MigrateActivityLogDb.cs @@ -3,12 +3,11 @@ using System.Collections.Generic; using System.IO; using Emby.Server.Implementations.Data; using Jellyfin.Data.Entities; -using Jellyfin.Server.Extensions; using Jellyfin.Server.Implementations; using MediaBrowser.Controller; +using Microsoft.Data.Sqlite; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; -using SQLitePCL.pretty; namespace Jellyfin.Server.Migrations.Routines { @@ -62,17 +61,12 @@ namespace Jellyfin.Server.Migrations.Routines }; var dataPath = _paths.DataPath; - using (var connection = SQLite3.Open( - Path.Combine(dataPath, DbFilename), - ConnectionFlags.ReadOnly, - null)) + using (var connection = new SqliteConnection($"Filename={Path.Combine(dataPath, DbFilename)}")) { - using var userDbConnection = SQLite3.Open(Path.Combine(dataPath, "users.db"), ConnectionFlags.ReadOnly, null); + using var userDbConnection = new SqliteConnection($"Filename={Path.Combine(dataPath, "users.db")}"); _logger.LogWarning("Migrating the activity database may take a while, do not stop Jellyfin."); using var dbContext = _provider.CreateDbContext(); - var queryResult = connection.Query("SELECT * FROM ActivityLog ORDER BY Id"); - // Make sure that the database is empty in case of failed migration due to power outages, etc. dbContext.ActivityLogs.RemoveRange(dbContext.ActivityLogs); dbContext.SaveChanges(); @@ -82,51 +76,52 @@ namespace Jellyfin.Server.Migrations.Routines var newEntries = new List(); + var queryResult = connection.Query("SELECT * FROM ActivityLog ORDER BY Id"); + foreach (var entry in queryResult) { - if (!logLevelDictionary.TryGetValue(entry[8].ToString(), out var severity)) + if (!logLevelDictionary.TryGetValue(entry.GetString(8), out var severity)) { severity = LogLevel.Trace; } var guid = Guid.Empty; - if (entry[6].SQLiteType != SQLiteType.Null && !Guid.TryParse(entry[6].ToString(), out guid)) + if (!entry.IsDBNull(6) && !entry.TryGetGuid(6, out guid)) { + var id = entry.GetString(6); // This is not a valid Guid, see if it is an internal ID from an old Emby schema - _logger.LogWarning("Invalid Guid in UserId column: {Guid}", entry[6].ToString()); + _logger.LogWarning("Invalid Guid in UserId column: {Guid}", id); using var statement = userDbConnection.PrepareStatement("SELECT guid FROM LocalUsersv2 WHERE Id=@Id"); - statement.TryBind("@Id", entry[6].ToString()); + statement.TryBind("@Id", id); - foreach (var row in statement.Query()) + using var reader = statement.ExecuteReader(); + if (reader.HasRows && reader.Read() && reader.TryGetGuid(0, out guid)) { - if (row.Count > 0 && Guid.TryParse(row[0].ToString(), out guid)) - { - // Successfully parsed a Guid from the user table. - break; - } + // Successfully parsed a Guid from the user table. + break; } } - var newEntry = new ActivityLog(entry[1].ToString(), entry[4].ToString(), guid) + var newEntry = new ActivityLog(entry.GetString(1), entry.GetString(4), guid) { - DateCreated = entry[7].ReadDateTime(), + DateCreated = entry.GetDateTime(7), LogSeverity = severity }; - if (entry[2].SQLiteType != SQLiteType.Null) + if (entry.TryGetString(2, out var result)) { - newEntry.Overview = entry[2].ToString(); + newEntry.Overview = result; } - if (entry[3].SQLiteType != SQLiteType.Null) + if (entry.TryGetString(3, out result)) { - newEntry.ShortOverview = entry[3].ToString(); + newEntry.ShortOverview = result; } - if (entry[5].SQLiteType != SQLiteType.Null) + if (entry.TryGetString(5, out result)) { - newEntry.ItemId = entry[5].ToString(); + newEntry.ItemId = result; } newEntries.Add(newEntry); diff --git a/Jellyfin.Server/Migrations/Routines/MigrateAuthenticationDb.cs b/Jellyfin.Server/Migrations/Routines/MigrateAuthenticationDb.cs index a1b87fbe0a..63cbe49503 100644 --- a/Jellyfin.Server/Migrations/Routines/MigrateAuthenticationDb.cs +++ b/Jellyfin.Server/Migrations/Routines/MigrateAuthenticationDb.cs @@ -3,13 +3,12 @@ using System.Collections.Generic; using System.IO; using Emby.Server.Implementations.Data; using Jellyfin.Data.Entities.Security; -using Jellyfin.Server.Extensions; using Jellyfin.Server.Implementations; using MediaBrowser.Controller; using MediaBrowser.Controller.Library; +using Microsoft.Data.Sqlite; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; -using SQLitePCL.pretty; namespace Jellyfin.Server.Migrations.Routines { @@ -57,10 +56,7 @@ namespace Jellyfin.Server.Migrations.Routines public void Perform() { var dataPath = _appPaths.DataPath; - using (var connection = SQLite3.Open( - Path.Combine(dataPath, DbFilename), - ConnectionFlags.ReadOnly, - null)) + using (var connection = new SqliteConnection($"Filename={Path.Combine(dataPath, DbFilename)}")) { using var dbContext = _dbProvider.CreateDbContext(); @@ -68,23 +64,23 @@ namespace Jellyfin.Server.Migrations.Routines foreach (var row in authenticatedDevices) { - var dateCreatedStr = row[9].ToString(); + var dateCreatedStr = row.GetString(9); _ = DateTime.TryParse(dateCreatedStr, out var dateCreated); - var dateLastActivityStr = row[10].ToString(); + var dateLastActivityStr = row.GetString(10); _ = DateTime.TryParse(dateLastActivityStr, out var dateLastActivity); - if (row[6].IsDbNull()) + if (row.IsDBNull(6)) { - dbContext.ApiKeys.Add(new ApiKey(row[3].ToString()) + dbContext.ApiKeys.Add(new ApiKey(row.GetString(3)) { - AccessToken = row[1].ToString(), + AccessToken = row.GetString(1), DateCreated = dateCreated, DateLastActivity = dateLastActivity }); } else { - var userId = new Guid(row[6].ToString()); + var userId = row.GetGuid(6); var user = _userManager.GetUserById(userId); if (user is null) { @@ -93,14 +89,14 @@ namespace Jellyfin.Server.Migrations.Routines } dbContext.Devices.Add(new Device( - new Guid(row[6].ToString()), - row[3].ToString(), - row[4].ToString(), - row[5].ToString(), - row[2].ToString()) + userId, + row.GetString(3), + row.GetString(4), + row.GetString(5), + row.GetString(2)) { - AccessToken = row[1].ToString(), - IsActive = row[8].ToBool(), + AccessToken = row.GetString(1), + IsActive = row.GetBoolean(8), DateCreated = dateCreated, DateLastActivity = dateLastActivity }); @@ -111,12 +107,12 @@ namespace Jellyfin.Server.Migrations.Routines var deviceIds = new HashSet(); foreach (var row in deviceOptions) { - if (row[2].IsDbNull()) + if (row.IsDBNull(2)) { continue; } - var deviceId = row[2].ToString(); + var deviceId = row.GetString(2); if (deviceIds.Contains(deviceId)) { continue; @@ -126,7 +122,7 @@ namespace Jellyfin.Server.Migrations.Routines dbContext.DeviceOptions.Add(new DeviceOptions(deviceId) { - CustomName = row[1].IsDbNull() ? null : row[1].ToString() + CustomName = row.IsDBNull(1) ? null : row.GetString(1) }); } diff --git a/Jellyfin.Server/Migrations/Routines/MigrateDisplayPreferencesDb.cs b/Jellyfin.Server/Migrations/Routines/MigrateDisplayPreferencesDb.cs index 8fe2b087d9..a036fe9bb5 100644 --- a/Jellyfin.Server/Migrations/Routines/MigrateDisplayPreferencesDb.cs +++ b/Jellyfin.Server/Migrations/Routines/MigrateDisplayPreferencesDb.cs @@ -4,15 +4,16 @@ using System.IO; using System.Linq; using System.Text.Json; using System.Text.Json.Serialization; +using Emby.Server.Implementations.Data; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; using Jellyfin.Server.Implementations; using MediaBrowser.Controller; using MediaBrowser.Controller.Library; using MediaBrowser.Model.Dto; +using Microsoft.Data.Sqlite; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; -using SQLitePCL.pretty; namespace Jellyfin.Server.Migrations.Routines { @@ -83,22 +84,22 @@ namespace Jellyfin.Server.Migrations.Routines var displayPrefs = new HashSet(StringComparer.OrdinalIgnoreCase); var customDisplayPrefs = new HashSet(StringComparer.OrdinalIgnoreCase); var dbFilePath = Path.Combine(_paths.DataPath, DbFilename); - using (var connection = SQLite3.Open(dbFilePath, ConnectionFlags.ReadOnly, null)) + using (var connection = new SqliteConnection($"Filename={dbFilePath}")) { using var dbContext = _provider.CreateDbContext(); var results = connection.Query("SELECT * FROM userdisplaypreferences"); foreach (var result in results) { - var dto = JsonSerializer.Deserialize(result[3].ToBlob(), _jsonOptions); + var dto = JsonSerializer.Deserialize(result.GetStream(3), _jsonOptions); if (dto is null) { continue; } - var itemId = new Guid(result[1].ToBlob()); - var dtoUserId = new Guid(result[1].ToBlob()); - var client = result[2].ToString(); + var itemId = result.GetGuid(1); + var dtoUserId = itemId; + var client = result.GetString(2); var displayPreferencesKey = $"{dtoUserId}|{itemId}|{client}"; if (displayPrefs.Contains(displayPreferencesKey)) { diff --git a/Jellyfin.Server/Migrations/Routines/MigrateRatingLevels.cs b/Jellyfin.Server/Migrations/Routines/MigrateRatingLevels.cs index 9f9960a642..06eda329cb 100644 --- a/Jellyfin.Server/Migrations/Routines/MigrateRatingLevels.cs +++ b/Jellyfin.Server/Migrations/Routines/MigrateRatingLevels.cs @@ -1,14 +1,12 @@ using System; using System.Globalization; using System.IO; - using Emby.Server.Implementations.Data; -using Jellyfin.Server.Extensions; using MediaBrowser.Controller; using MediaBrowser.Controller.Persistence; using MediaBrowser.Model.Globalization; +using Microsoft.Data.Sqlite; using Microsoft.Extensions.Logging; -using SQLitePCL.pretty; namespace Jellyfin.Server.Migrations.Routines { @@ -21,17 +19,14 @@ namespace Jellyfin.Server.Migrations.Routines private readonly ILogger _logger; private readonly IServerApplicationPaths _applicationPaths; private readonly ILocalizationManager _localizationManager; - private readonly IItemRepository _repository; public MigrateRatingLevels( IServerApplicationPaths applicationPaths, ILoggerFactory loggerFactory, - ILocalizationManager localizationManager, - IItemRepository repository) + ILocalizationManager localizationManager) { _applicationPaths = applicationPaths; _localizationManager = localizationManager; - _repository = repository; _logger = loggerFactory.CreateLogger(); } @@ -71,15 +66,13 @@ namespace Jellyfin.Server.Migrations.Routines // Migrate parental rating strings to new levels _logger.LogInformation("Recalculating parental rating levels based on rating string."); - using (var connection = SQLite3.Open( - dbPath, - ConnectionFlags.ReadWrite, - null)) + using (var connection = new SqliteConnection($"Filename={dbPath}")) + using (var transaction = connection.BeginTransaction()) { var queryResult = connection.Query("SELECT DISTINCT OfficialRating FROM TypedBaseItems"); foreach (var entry in queryResult) { - var ratingString = entry[0].ToString(); + var ratingString = entry.GetString(0); if (string.IsNullOrEmpty(ratingString)) { connection.Execute("UPDATE TypedBaseItems SET InheritedParentalRatingValue = NULL WHERE OfficialRating IS NULL OR OfficialRating='';"); @@ -95,9 +88,11 @@ namespace Jellyfin.Server.Migrations.Routines using var statement = connection.PrepareStatement("UPDATE TypedBaseItems SET InheritedParentalRatingValue = @Value WHERE OfficialRating = @Rating;"); statement.TryBind("@Value", ratingValue); statement.TryBind("@Rating", ratingString); - statement.ExecuteQuery(); + statement.ExecuteNonQuery(); } } + + transaction.Commit(); } } } diff --git a/Jellyfin.Server/Migrations/Routines/MigrateUserDb.cs b/Jellyfin.Server/Migrations/Routines/MigrateUserDb.cs index a1de104ade..9cf888d62b 100644 --- a/Jellyfin.Server/Migrations/Routines/MigrateUserDb.cs +++ b/Jellyfin.Server/Migrations/Routines/MigrateUserDb.cs @@ -4,7 +4,6 @@ using Emby.Server.Implementations.Data; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; using Jellyfin.Extensions.Json; -using Jellyfin.Server.Extensions; using Jellyfin.Server.Implementations; using Jellyfin.Server.Implementations.Users; using MediaBrowser.Controller; @@ -12,9 +11,9 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Serialization; using MediaBrowser.Model.Users; +using Microsoft.Data.Sqlite; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; -using SQLitePCL.pretty; using JsonSerializer = System.Text.Json.JsonSerializer; namespace Jellyfin.Server.Migrations.Routines @@ -65,7 +64,7 @@ namespace Jellyfin.Server.Migrations.Routines var dataPath = _paths.DataPath; _logger.LogInformation("Migrating the user database may take a while, do not stop Jellyfin."); - using (var connection = SQLite3.Open(Path.Combine(dataPath, DbFilename), ConnectionFlags.ReadOnly, null)) + using (var connection = new SqliteConnection($"Filename={Path.Combine(dataPath, DbFilename)}")) { var dbContext = _provider.CreateDbContext(); @@ -76,7 +75,7 @@ namespace Jellyfin.Server.Migrations.Routines foreach (var entry in queryResult) { - UserMockup? mockup = JsonSerializer.Deserialize(entry[2].ToBlob(), JsonDefaults.Options); + UserMockup? mockup = JsonSerializer.Deserialize(entry.GetStream(2), JsonDefaults.Options); if (mockup is null) { continue; @@ -109,8 +108,8 @@ namespace Jellyfin.Server.Migrations.Routines var user = new User(mockup.Name, policy.AuthenticationProviderId!, policy.PasswordResetProviderId!) { - Id = entry[1].ReadGuidFromBlob(), - InternalId = entry[0].ToInt64(), + Id = entry.GetGuid(1), + InternalId = entry.GetInt64(0), MaxParentalAgeRating = policy.MaxParentalRating, EnableUserPreferenceAccess = policy.EnableUserPreferenceAccess, RemoteClientBitrateLimit = policy.RemoteClientBitrateLimit, diff --git a/Jellyfin.Server/Migrations/Routines/RemoveDuplicateExtras.cs b/Jellyfin.Server/Migrations/Routines/RemoveDuplicateExtras.cs index 6c26e47e15..98017e3ef4 100644 --- a/Jellyfin.Server/Migrations/Routines/RemoveDuplicateExtras.cs +++ b/Jellyfin.Server/Migrations/Routines/RemoveDuplicateExtras.cs @@ -1,10 +1,11 @@ using System; using System.Globalization; using System.IO; - +using System.Linq; +using Emby.Server.Implementations.Data; using MediaBrowser.Controller; +using Microsoft.Data.Sqlite; using Microsoft.Extensions.Logging; -using SQLitePCL.pretty; namespace Jellyfin.Server.Migrations.Routines { @@ -37,14 +38,12 @@ namespace Jellyfin.Server.Migrations.Routines { var dataPath = _paths.DataPath; var dbPath = Path.Combine(dataPath, DbFilename); - using (var connection = SQLite3.Open( - dbPath, - ConnectionFlags.ReadWrite, - null)) + using (var connection = new SqliteConnection($"Filename={dbPath}")) { // Query the database for the ids of duplicate extras var queryResult = connection.Query("SELECT t1.Path FROM TypedBaseItems AS t1, TypedBaseItems AS t2 WHERE t1.Path=t2.Path AND t1.Type!=t2.Type AND t1.Type='MediaBrowser.Controller.Entities.Video'"); - var bads = string.Join(", ", queryResult.SelectScalarString()); + // TODO does this LINQ execute before the reader is disposed? + var bads = string.Join(", ", queryResult.Select(x => x.GetString(0)).ToList()); // Do nothing if no duplicate extras were detected if (bads.Length == 0)