aboutsummaryrefslogtreecommitdiff
path: root/Emby.Server.Implementations/ScheduledTasks/Tasks
diff options
context:
space:
mode:
Diffstat (limited to 'Emby.Server.Implementations/ScheduledTasks/Tasks')
-rw-r--r--Emby.Server.Implementations/ScheduledTasks/Tasks/AudioNormalizationTask.cs119
-rw-r--r--Emby.Server.Implementations/ScheduledTasks/Tasks/CleanupUserDataTask.cs77
-rw-r--r--Emby.Server.Implementations/ScheduledTasks/Tasks/RefreshMediaLibraryTask.cs4
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);
}
}