Sfoglia il codice sorgente

Tweak Trickplay migration for speed (#12643)

Cody Robibero 8 mesi fa
parent
commit
3c639c2e80

+ 5 - 3
Jellyfin.Server.Implementations/Trickplay/TrickplayManager.cs

@@ -455,16 +455,18 @@ public class TrickplayManager : ITrickplayManager
     }
 
     /// <inheritdoc />
-    public async Task<IReadOnlyList<Guid>> GetTrickplayItemsAsync()
+    public async Task<IReadOnlyList<TrickplayInfo>> GetTrickplayItemsAsync(int limit, int offset)
     {
-        List<Guid> trickplayItems;
+        IReadOnlyList<TrickplayInfo> trickplayItems;
 
         var dbContext = await _dbProvider.CreateDbContextAsync().ConfigureAwait(false);
         await using (dbContext.ConfigureAwait(false))
         {
             trickplayItems = await dbContext.TrickplayInfos
                 .AsNoTracking()
-                .Select(i => i.ItemId)
+                .OrderBy(i => i.ItemId)
+                .Skip(offset)
+                .Take(limit)
                 .ToListAsync()
                 .ConfigureAwait(false);
         }

+ 44 - 13
Jellyfin.Server/Migrations/Routines/MoveTrickplayFiles.cs

@@ -1,10 +1,15 @@
 using System;
+using System.Diagnostics;
 using System.Globalization;
 using System.IO;
+using System.Linq;
+using Jellyfin.Data.Enums;
+using MediaBrowser.Common;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Trickplay;
 using MediaBrowser.Model.IO;
+using Microsoft.Extensions.Logging;
 
 namespace Jellyfin.Server.Migrations.Routines;
 
@@ -16,6 +21,7 @@ public class MoveTrickplayFiles : IMigrationRoutine
     private readonly ITrickplayManager _trickplayManager;
     private readonly IFileSystem _fileSystem;
     private readonly ILibraryManager _libraryManager;
+    private readonly ILogger<MoveTrickplayFiles> _logger;
 
     /// <summary>
     /// Initializes a new instance of the <see cref="MoveTrickplayFiles"/> class.
@@ -23,11 +29,13 @@ public class MoveTrickplayFiles : IMigrationRoutine
     /// <param name="trickplayManager">Instance of the <see cref="ITrickplayManager"/> interface.</param>
     /// <param name="fileSystem">Instance of the <see cref="IFileSystem"/> interface.</param>
     /// <param name="libraryManager">Instance of the <see cref="ILibraryManager"/> interface.</param>
-    public MoveTrickplayFiles(ITrickplayManager trickplayManager, IFileSystem fileSystem, ILibraryManager libraryManager)
+    /// <param name="logger">The logger.</param>
+    public MoveTrickplayFiles(ITrickplayManager trickplayManager, IFileSystem fileSystem, ILibraryManager libraryManager, ILogger<MoveTrickplayFiles> logger)
     {
         _trickplayManager = trickplayManager;
         _fileSystem = fileSystem;
         _libraryManager = libraryManager;
+        _logger = logger;
     }
 
     /// <inheritdoc />
@@ -42,26 +50,49 @@ public class MoveTrickplayFiles : IMigrationRoutine
     /// <inheritdoc />
     public void Perform()
     {
-        var trickplayItems = _trickplayManager.GetTrickplayItemsAsync().GetAwaiter().GetResult();
-        foreach (var itemId in trickplayItems)
+        const int Limit = 100;
+        int itemCount = 0, offset = 0, previousCount;
+
+        var sw = Stopwatch.StartNew();
+        var trickplayQuery = new InternalItemsQuery
         {
-            var resolutions = _trickplayManager.GetTrickplayResolutions(itemId).GetAwaiter().GetResult();
-            var item = _libraryManager.GetItemById(itemId);
-            if (item is null)
-            {
-                continue;
-            }
+            MediaTypes = [MediaType.Video],
+            SourceTypes = [SourceType.Library],
+            IsVirtualItem = false,
+            IsFolder = false
+        };
 
-            foreach (var resolution in resolutions)
+        do
+        {
+            var trickplayInfos = _trickplayManager.GetTrickplayItemsAsync(Limit, offset).GetAwaiter().GetResult();
+            previousCount = trickplayInfos.Count;
+            offset += Limit;
+
+            trickplayQuery.ItemIds = trickplayInfos.Select(i => i.ItemId).Distinct().ToArray();
+            var items = _libraryManager.GetItemList(trickplayQuery);
+            foreach (var trickplayInfo in trickplayInfos)
             {
-                var oldPath = GetOldTrickplayDirectory(item, resolution.Key);
-                var newPath = _trickplayManager.GetTrickplayDirectory(item, resolution.Value.TileWidth, resolution.Value.TileHeight, resolution.Value.Width, false);
+                var item = items.OfType<Video>().FirstOrDefault(i => i.Id.Equals(trickplayInfo.ItemId));
+                if (item is null)
+                {
+                    continue;
+                }
+
+                if (++itemCount % 1_000 == 0)
+                {
+                    _logger.LogInformation("Moved {Count} items in {Time}", itemCount, sw.Elapsed);
+                }
+
+                var oldPath = GetOldTrickplayDirectory(item, trickplayInfo.Width);
+                var newPath = _trickplayManager.GetTrickplayDirectory(item, trickplayInfo.TileWidth, trickplayInfo.TileHeight, trickplayInfo.Width, false);
                 if (_fileSystem.DirectoryExists(oldPath))
                 {
                     _fileSystem.MoveDirectory(oldPath, newPath);
                 }
             }
-        }
+        } while (previousCount == Limit);
+
+        _logger.LogInformation("Moved {Count} items in {Time}", itemCount, sw.Elapsed);
     }
 
     private string GetOldTrickplayDirectory(BaseItem item, int? width = null)

+ 3 - 1
MediaBrowser.Controller/Trickplay/ITrickplayManager.cs

@@ -46,8 +46,10 @@ public interface ITrickplayManager
     /// <summary>
     /// Gets the item ids of all items with trickplay info.
     /// </summary>
+    /// <param name="limit">The limit of items to return.</param>
+    /// <param name="offset">The offset to start the query at.</param>
     /// <returns>The list of item ids that have trickplay info.</returns>
-    public Task<IReadOnlyList<Guid>> GetTrickplayItemsAsync();
+    Task<IReadOnlyList<TrickplayInfo>> GetTrickplayItemsAsync(int limit, int offset);
 
     /// <summary>
     /// Saves trickplay info.

+ 30 - 21
MediaBrowser.Providers/Trickplay/TrickplayMoveImagesTask.cs

@@ -18,8 +18,6 @@ namespace MediaBrowser.Providers.Trickplay;
 /// </summary>
 public class TrickplayMoveImagesTask : IScheduledTask
 {
-    private const int QueryPageLimit = 100;
-
     private readonly ILogger<TrickplayMoveImagesTask> _logger;
     private readonly ILibraryManager _libraryManager;
     private readonly ILocalizationManager _localization;
@@ -62,32 +60,46 @@ public class TrickplayMoveImagesTask : IScheduledTask
     /// <inheritdoc />
     public async Task ExecuteAsync(IProgress<double> progress, CancellationToken cancellationToken)
     {
-        var trickplayItems = await _trickplayManager.GetTrickplayItemsAsync().ConfigureAwait(false);
-        var query = new InternalItemsQuery
+        const int Limit = 100;
+        int itemCount = 0, offset = 0, previousCount;
+
+        // This count may not be accurate, but just get something to show progress on the dashboard.
+        var totalVideoCount = _libraryManager.GetCount(new InternalItemsQuery
         {
             MediaTypes = [MediaType.Video],
             SourceTypes = [SourceType.Library],
             IsVirtualItem = false,
             IsFolder = false,
-            Recursive = true,
-            Limit = QueryPageLimit
-        };
-
-        var numberOfVideos = _libraryManager.GetCount(query);
+            Recursive = true
+        });
 
-        var startIndex = 0;
-        var numComplete = 0;
+        var trickplayQuery = new InternalItemsQuery
+        {
+            MediaTypes = [MediaType.Video],
+            SourceTypes = [SourceType.Library],
+            IsVirtualItem = false,
+            IsFolder = false
+        };
 
-        while (startIndex < numberOfVideos)
+        do
         {
-            query.StartIndex = startIndex;
-            var videos = _libraryManager.GetItemList(query).OfType<Video>().ToList();
-            videos.RemoveAll(i => !trickplayItems.Contains(i.Id));
+            var trickplayInfos = await _trickplayManager.GetTrickplayItemsAsync(Limit, offset).ConfigureAwait(false);
+            previousCount = trickplayInfos.Count;
+            offset += Limit;
 
-            foreach (var video in videos)
+            trickplayQuery.ItemIds = trickplayInfos.Select(i => i.ItemId).Distinct().ToArray();
+            var items = _libraryManager.GetItemList(trickplayQuery);
+            foreach (var trickplayInfo in trickplayInfos)
             {
                 cancellationToken.ThrowIfCancellationRequested();
 
+                var video = items.OfType<Video>().FirstOrDefault(i => i.Id.Equals(trickplayInfo.ItemId));
+                if (video is null)
+                {
+                    continue;
+                }
+
+                itemCount++;
                 try
                 {
                     var libraryOptions = _libraryManager.GetLibraryOptions(video);
@@ -97,13 +109,10 @@ public class TrickplayMoveImagesTask : IScheduledTask
                 {
                     _logger.LogError(ex, "Error moving trickplay files for {ItemName}", video.Name);
                 }
-
-                numComplete++;
-                progress.Report(100d * numComplete / numberOfVideos);
             }
 
-            startIndex += QueryPageLimit;
-        }
+            progress.Report(100d * itemCount / totalVideoCount);
+        } while (previousCount == Limit);
 
         progress.Report(100);
     }