diff options
| author | Cody Robibero <cody@robibe.ro> | 2024-09-23 09:09:23 -0600 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-09-23 09:09:23 -0600 |
| commit | 3c639c2e80f2a17eea3f5f1a70c1b287bc99aba4 (patch) | |
| tree | 0d15c42ffee4c02603be75c8dc44863b8e72da02 | |
| parent | 0539fdc5e3a164b694d12d8d3f8437e2cc5b6457 (diff) | |
Tweak Trickplay migration for speed (#12643)
4 files changed, 82 insertions, 38 deletions
diff --git a/Jellyfin.Server.Implementations/Trickplay/TrickplayManager.cs b/Jellyfin.Server.Implementations/Trickplay/TrickplayManager.cs index 861037c1f..73e31279f 100644 --- a/Jellyfin.Server.Implementations/Trickplay/TrickplayManager.cs +++ b/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); } diff --git a/Jellyfin.Server/Migrations/Routines/MoveTrickplayFiles.cs b/Jellyfin.Server/Migrations/Routines/MoveTrickplayFiles.cs index 301541b6c..c1a9e8894 100644 --- a/Jellyfin.Server/Migrations/Routines/MoveTrickplayFiles.cs +++ b/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) diff --git a/MediaBrowser.Controller/Trickplay/ITrickplayManager.cs b/MediaBrowser.Controller/Trickplay/ITrickplayManager.cs index bda794aa6..800317800 100644 --- a/MediaBrowser.Controller/Trickplay/ITrickplayManager.cs +++ b/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. diff --git a/MediaBrowser.Providers/Trickplay/TrickplayMoveImagesTask.cs b/MediaBrowser.Providers/Trickplay/TrickplayMoveImagesTask.cs index c581fd26c..c0b8a8c75 100644 --- a/MediaBrowser.Providers/Trickplay/TrickplayMoveImagesTask.cs +++ b/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); } |
