diff options
Diffstat (limited to 'Emby.Server.Implementations/ScheduledTasks/Tasks')
3 files changed, 147 insertions, 53 deletions
diff --git a/Emby.Server.Implementations/ScheduledTasks/Tasks/AudioNormalizationTask.cs b/Emby.Server.Implementations/ScheduledTasks/Tasks/AudioNormalizationTask.cs index ef005bfaa..e912e9f01 100644 --- a/Emby.Server.Implementations/ScheduledTasks/Tasks/AudioNormalizationTask.cs +++ b/Emby.Server.Implementations/ScheduledTasks/Tasks/AudioNormalizationTask.cs @@ -76,81 +76,98 @@ public partial class AudioNormalizationTask : IScheduledTask /// <inheritdoc /> public async Task ExecuteAsync(IProgress<double> progress, CancellationToken cancellationToken) { - foreach (var library in _libraryManager.RootFolder.Children) + var numComplete = 0; + var libraries = _libraryManager.RootFolder.Children.Where(library => _libraryManager.GetLibraryOptions(library).EnableLUFSScan).ToArray(); + double percent = 0; + + foreach (var library in libraries) { - var libraryOptions = _libraryManager.GetLibraryOptions(library); - if (!libraryOptions.EnableLUFSScan) - { - continue; - } + var albums = _libraryManager.GetItemList(new InternalItemsQuery { IncludeItemTypes = [BaseItemKind.MusicAlbum], Parent = library, Recursive = true }); - // Album gain - var albums = _libraryManager.GetItemList(new InternalItemsQuery - { - IncludeItemTypes = [BaseItemKind.MusicAlbum], - Parent = library, - Recursive = true - }); + double nextPercent = numComplete + 1; + nextPercent /= libraries.Length; + nextPercent -= percent; + // Split the progress for this single library into two halves: album gain and track gain. + // The first half will be for album gain, the second half for track gain. + nextPercent /= 2; + var albumComplete = 0; foreach (var a in albums) { - if (a.NormalizationGain.HasValue || a.LUFS.HasValue) + if (!a.NormalizationGain.HasValue && !a.LUFS.HasValue) { - continue; + // Album gain + var albumTracks = ((MusicAlbum)a).Tracks.Where(x => x.IsFileProtocol).ToList(); + + // Skip albums that don't have multiple tracks, album gain is useless here + if (albumTracks.Count > 1) + { + _logger.LogInformation("Calculating LUFS for album: {Album} with id: {Id}", a.Name, a.Id); + var tempDir = _applicationPaths.TempDirectory; + Directory.CreateDirectory(tempDir); + var tempFile = Path.Join(tempDir, a.Id + ".concat"); + var inputLines = albumTracks.Select(x => string.Format(CultureInfo.InvariantCulture, "file '{0}'", x.Path.Replace("'", @"'\''", StringComparison.Ordinal))); + await File.WriteAllLinesAsync(tempFile, inputLines, cancellationToken).ConfigureAwait(false); + try + { + a.LUFS = await CalculateLUFSAsync( + string.Format(CultureInfo.InvariantCulture, "-f concat -safe 0 -i \"{0}\"", tempFile), + OperatingSystem.IsWindows(), // Wait for process to exit on Windows before we try deleting the concat file + cancellationToken).ConfigureAwait(false); + } + finally + { + File.Delete(tempFile); + } + } } - // Skip albums that don't have multiple tracks, album gain is useless here - var albumTracks = ((MusicAlbum)a).Tracks.Where(x => x.IsFileProtocol).ToList(); - if (albumTracks.Count <= 1) - { - continue; - } + // Update sub-progress for album gain + albumComplete++; + double albumPercent = albumComplete; + albumPercent /= albums.Count; - _logger.LogInformation("Calculating LUFS for album: {Album} with id: {Id}", a.Name, a.Id); - var tempDir = _applicationPaths.TempDirectory; - Directory.CreateDirectory(tempDir); - var tempFile = Path.Join(tempDir, a.Id + ".concat"); - var inputLines = albumTracks.Select(x => string.Format(CultureInfo.InvariantCulture, "file '{0}'", x.Path.Replace("'", @"'\''", StringComparison.Ordinal))); - await File.WriteAllLinesAsync(tempFile, inputLines, cancellationToken).ConfigureAwait(false); - try - { - a.LUFS = await CalculateLUFSAsync( - string.Format(CultureInfo.InvariantCulture, "-f concat -safe 0 -i \"{0}\"", tempFile), - OperatingSystem.IsWindows(), // Wait for process to exit on Windows before we try deleting the concat file - cancellationToken).ConfigureAwait(false); - } - finally - { - File.Delete(tempFile); - } + progress.Report(100 * (percent + (albumPercent * nextPercent))); } + // Update progress to start at the track gain percent calculation + percent += nextPercent; + _itemRepository.SaveItems(albums, cancellationToken); // Track gain - var tracks = _libraryManager.GetItemList(new InternalItemsQuery - { - MediaTypes = [MediaType.Audio], - IncludeItemTypes = [BaseItemKind.Audio], - Parent = library, - Recursive = true - }); + var tracks = _libraryManager.GetItemList(new InternalItemsQuery { MediaTypes = [MediaType.Audio], IncludeItemTypes = [BaseItemKind.Audio], Parent = library, Recursive = true }); + var tracksComplete = 0; foreach (var t in tracks) { - if (t.NormalizationGain.HasValue || t.LUFS.HasValue || !t.IsFileProtocol) + if (!t.NormalizationGain.HasValue && !t.LUFS.HasValue && t.IsFileProtocol) { - continue; + t.LUFS = await CalculateLUFSAsync( + string.Format(CultureInfo.InvariantCulture, "-i \"{0}\"", t.Path.Replace("\"", "\\\"", StringComparison.Ordinal)), + false, + cancellationToken).ConfigureAwait(false); } - t.LUFS = await CalculateLUFSAsync( - string.Format(CultureInfo.InvariantCulture, "-i \"{0}\"", t.Path.Replace("\"", "\\\"", StringComparison.Ordinal)), - false, - cancellationToken).ConfigureAwait(false); + // Update sub-progress for track gain + tracksComplete++; + double trackPercent = tracksComplete; + trackPercent /= tracks.Count; + + progress.Report(100 * (percent + (trackPercent * nextPercent))); } _itemRepository.SaveItems(tracks, cancellationToken); + + // Update progress + numComplete++; + percent = numComplete; + percent /= libraries.Length; + + progress.Report(100 * percent); } + + progress.Report(100.0); } /// <inheritdoc /> diff --git a/Emby.Server.Implementations/ScheduledTasks/Tasks/CleanupUserDataTask.cs b/Emby.Server.Implementations/ScheduledTasks/Tasks/CleanupUserDataTask.cs new file mode 100644 index 000000000..4156050eb --- /dev/null +++ b/Emby.Server.Implementations/ScheduledTasks/Tasks/CleanupUserDataTask.cs @@ -0,0 +1,77 @@ +#pragma warning disable RS0030 // Do not use banned APIs + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Jellyfin.Database.Implementations; +using Jellyfin.Server.Implementations.Item; +using MediaBrowser.Model.Globalization; +using MediaBrowser.Model.Tasks; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Logging; + +namespace Emby.Server.Implementations.ScheduledTasks.Tasks; + +/// <summary> +/// Task to clean up any detached userdata from the database. +/// </summary> +public class CleanupUserDataTask : IScheduledTask +{ + private readonly ILocalizationManager _localization; + private readonly IDbContextFactory<JellyfinDbContext> _dbProvider; + private readonly ILogger<CleanupUserDataTask> _logger; + + /// <summary> + /// Initializes a new instance of the <see cref="CleanupUserDataTask"/> class. + /// </summary> + /// <param name="localization">The localisation Provider.</param> + /// <param name="dbProvider">The DB context factory.</param> + /// <param name="logger">A logger.</param> + public CleanupUserDataTask(ILocalizationManager localization, IDbContextFactory<JellyfinDbContext> dbProvider, ILogger<CleanupUserDataTask> logger) + { + _localization = localization; + _dbProvider = dbProvider; + _logger = logger; + } + + /// <inheritdoc /> + public string Name => _localization.GetLocalizedString("CleanupUserDataTask"); + + /// <inheritdoc /> + public string Description => _localization.GetLocalizedString("CleanupUserDataTaskDescription"); + + /// <inheritdoc /> + public string Category => _localization.GetLocalizedString("TasksMaintenanceCategory"); + + /// <inheritdoc /> + public string Key => nameof(CleanupUserDataTask); + + /// <inheritdoc/> + public async Task ExecuteAsync(IProgress<double> progress, CancellationToken cancellationToken) + { + const int LimitDays = 90; + var userDataDate = DateTime.UtcNow.AddDays(LimitDays * -1); + var dbContext = await _dbProvider.CreateDbContextAsync(cancellationToken).ConfigureAwait(false); + await using (dbContext.ConfigureAwait(false)) + { + var detachedUserData = dbContext.UserData.Where(e => e.ItemId == BaseItemRepository.PlaceholderId); + _logger.LogInformation("There are {NoDetached} detached UserData entries.", detachedUserData.Count()); + + detachedUserData = detachedUserData.Where(e => e.RetentionDate < userDataDate); + + _logger.LogInformation("{NoDetached} are older then {Limit} days.", detachedUserData.Count(), LimitDays); + + await detachedUserData.ExecuteDeleteAsync(cancellationToken).ConfigureAwait(false); + } + + progress.Report(100); + } + + /// <inheritdoc/> + public IEnumerable<TaskTriggerInfo> GetDefaultTriggers() + { + yield break; + } +} diff --git a/Emby.Server.Implementations/ScheduledTasks/Tasks/RefreshMediaLibraryTask.cs b/Emby.Server.Implementations/ScheduledTasks/Tasks/RefreshMediaLibraryTask.cs index c96843199..1865189d0 100644 --- a/Emby.Server.Implementations/ScheduledTasks/Tasks/RefreshMediaLibraryTask.cs +++ b/Emby.Server.Implementations/ScheduledTasks/Tasks/RefreshMediaLibraryTask.cs @@ -54,12 +54,12 @@ public class RefreshMediaLibraryTask : IScheduledTask } /// <inheritdoc /> - public Task ExecuteAsync(IProgress<double> progress, CancellationToken cancellationToken) + public async Task ExecuteAsync(IProgress<double> progress, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); progress.Report(0); - return ((LibraryManager)_libraryManager).ValidateMediaLibraryInternal(progress, cancellationToken); + await ((LibraryManager)_libraryManager).ValidateMediaLibraryInternal(progress, cancellationToken).ConfigureAwait(false); } } |
