瀏覽代碼

Add full migration for IsFolder flag

JPVenson 3 天之前
父節點
當前提交
a1eb04dc0b

+ 3 - 0
Jellyfin.Server/Migrations/Routines/MigrateLibraryDb.cs

@@ -90,6 +90,9 @@ internal class MigrateLibraryDb : IDatabaseMigrationRoutine
             operation.JellyfinDbContext.AncestorIds.ExecuteDelete();
         }
 
+        // notify the other migration to just silently abort because the fix has been applied here already.
+        ReseedFolderFlag.RerunGuardFlag = true;
+
         var legacyBaseItemWithUserKeys = new Dictionary<string, BaseItemEntity>();
         connection.Open();
 

+ 73 - 0
Jellyfin.Server/Migrations/Routines/ReseedFolderFlag.cs

@@ -0,0 +1,73 @@
+#pragma warning disable RS0030 // Do not use banned APIs
+using System.IO;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using Emby.Server.Implementations.Data;
+using Jellyfin.Database.Implementations;
+using Jellyfin.Server.ServerSetupApp;
+using MediaBrowser.Controller;
+using Microsoft.Data.Sqlite;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.Extensions.Logging;
+
+namespace Jellyfin.Server.Migrations.Routines;
+
+[JellyfinMigration("2025-07-30T21:50:00", nameof(ReseedFolderFlag))]
+[JellyfinMigrationBackup(JellyfinDb = true)]
+internal class ReseedFolderFlag : IAsyncMigrationRoutine
+{
+    private const string DbFilename = "library.db.old";
+
+    private readonly IStartupLogger _logger;
+    private readonly IServerApplicationPaths _paths;
+    private readonly IDbContextFactory<JellyfinDbContext> _provider;
+
+    public ReseedFolderFlag(
+            IStartupLogger<MigrateLibraryDb> startupLogger,
+            IDbContextFactory<JellyfinDbContext> provider,
+            IServerApplicationPaths paths)
+    {
+        _logger = startupLogger;
+        _provider = provider;
+        _paths = paths;
+    }
+
+    internal static bool RerunGuardFlag { get; set; } = false;
+
+    public async Task PerformAsync(CancellationToken cancellationToken)
+    {
+        if (RerunGuardFlag)
+        {
+            _logger.LogInformation("Migration is skipped because it does not apply.");
+            return;
+        }
+
+        _logger.LogInformation("Migrating the IsFolder flag from library.db.old may take a while, do not stop Jellyfin.");
+
+        var dataPath = _paths.DataPath;
+        var libraryDbPath = Path.Combine(dataPath, DbFilename);
+        if (!File.Exists(libraryDbPath))
+        {
+            _logger.LogError("Cannot migrate IsFolder flag from {LibraryDb} as it does not exist. This migration expects the MigrateLibraryDb to run first.", libraryDbPath);
+            return;
+        }
+
+        var dbContext = await _provider.CreateDbContextAsync(cancellationToken).ConfigureAwait(false);
+        await using (dbContext.ConfigureAwait(false))
+        {
+            using var connection = new SqliteConnection($"Filename={libraryDbPath};Mode=ReadOnly");
+            var queryResult = connection.Query(
+"""
+    SELECT key FROM TypedBaseItems
+
+    WHERE IsFolder = true
+""");
+            foreach (var entity in queryResult)
+            {
+                var id = entity.GetGuid(0);
+                await dbContext.BaseItems.Where(e => e.Id == id).ExecuteUpdateAsync(e => e.SetProperty(f => f.IsFolder, true), cancellationToken).ConfigureAwait(false);
+            }
+        }
+    }
+}