Add progress reporting to AudioNormalizationTask. (#14306)

This commit is contained in:
Shane Powell 2025-07-28 13:27:24 +12:00 committed by GitHub
parent e86315128d
commit ba54cda774
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -76,81 +76,98 @@ public partial class AudioNormalizationTask : IScheduledTask
/// <inheritdoc /> /// <inheritdoc />
public async Task ExecuteAsync(IProgress<double> progress, CancellationToken cancellationToken) 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();
var libraryOptions = _libraryManager.GetLibraryOptions(library); double percent = 0;
if (!libraryOptions.EnableLUFSScan)
{
continue;
}
// Album gain foreach (var library in libraries)
var albums = _libraryManager.GetItemList(new InternalItemsQuery {
{ var albums = _libraryManager.GetItemList(new InternalItemsQuery { IncludeItemTypes = [BaseItemKind.MusicAlbum], Parent = library, Recursive = true });
IncludeItemTypes = [BaseItemKind.MusicAlbum],
Parent = library, double nextPercent = numComplete + 1;
Recursive = true 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) 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 // Update sub-progress for album gain
var albumTracks = ((MusicAlbum)a).Tracks.Where(x => x.IsFileProtocol).ToList(); albumComplete++;
if (albumTracks.Count <= 1) double albumPercent = albumComplete;
{ albumPercent /= albums.Count;
continue;
}
_logger.LogInformation("Calculating LUFS for album: {Album} with id: {Id}", a.Name, a.Id); progress.Report(100 * (percent + (albumPercent * nextPercent)));
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);
}
} }
// Update progress to start at the track gain percent calculation
percent += nextPercent;
_itemRepository.SaveItems(albums, cancellationToken); _itemRepository.SaveItems(albums, cancellationToken);
// Track gain // Track gain
var tracks = _libraryManager.GetItemList(new InternalItemsQuery var tracks = _libraryManager.GetItemList(new InternalItemsQuery { MediaTypes = [MediaType.Audio], IncludeItemTypes = [BaseItemKind.Audio], Parent = library, Recursive = true });
{
MediaTypes = [MediaType.Audio],
IncludeItemTypes = [BaseItemKind.Audio],
Parent = library,
Recursive = true
});
var tracksComplete = 0;
foreach (var t in tracks) 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( // Update sub-progress for track gain
string.Format(CultureInfo.InvariantCulture, "-i \"{0}\"", t.Path.Replace("\"", "\\\"", StringComparison.Ordinal)), tracksComplete++;
false, double trackPercent = tracksComplete;
cancellationToken).ConfigureAwait(false); trackPercent /= tracks.Count;
progress.Report(100 * (percent + (trackPercent * nextPercent)));
} }
_itemRepository.SaveItems(tracks, cancellationToken); _itemRepository.SaveItems(tracks, cancellationToken);
// Update progress
numComplete++;
percent = numComplete;
percent /= libraries.Length;
progress.Report(100 * percent);
} }
progress.Report(100.0);
} }
/// <inheritdoc /> /// <inheritdoc />