diff options
| author | Cody Robibero <cody@robibe.ro> | 2024-04-30 13:15:51 -0600 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-04-30 13:15:51 -0600 |
| commit | 48bb16472f7ed62ee74c98a51dea3bf3ee135de2 (patch) | |
| tree | 0dff8fb5e9c010aca0fb12ab4887e8b18823b832 | |
| parent | 74f3e54807ab306897f592c57478cd28b96280d2 (diff) | |
| parent | 9ffb07d67fd7d2c08cafff9081f38faac51b7e43 (diff) | |
Merge pull request #11457 from Bond-009/audionormalization
11 files changed, 232 insertions, 69 deletions
diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs index 59e4ff1a9..0a8a36ebc 100644 --- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs @@ -49,8 +49,8 @@ namespace Emby.Server.Implementations.Data private const string SaveItemCommandText = @"replace into TypedBaseItems - (guid,type,data,Path,StartDate,EndDate,ChannelId,IsMovie,IsSeries,EpisodeTitle,IsRepeat,CommunityRating,CustomRating,IndexNumber,IsLocked,Name,OfficialRating,MediaType,Overview,ParentIndexNumber,PremiereDate,ProductionYear,ParentId,Genres,InheritedParentalRatingValue,SortName,ForcedSortName,RunTimeTicks,Size,DateCreated,DateModified,PreferredMetadataLanguage,PreferredMetadataCountryCode,Width,Height,DateLastRefreshed,DateLastSaved,IsInMixedFolder,LockedFields,Studios,Audio,ExternalServiceId,Tags,IsFolder,UnratedType,TopParentId,TrailerTypes,CriticRating,CleanName,PresentationUniqueKey,OriginalTitle,PrimaryVersionId,DateLastMediaAdded,Album,LUFS,IsVirtualItem,SeriesName,UserDataKey,SeasonName,SeasonId,SeriesId,ExternalSeriesId,Tagline,ProviderIds,Images,ProductionLocations,ExtraIds,TotalBitrate,ExtraType,Artists,AlbumArtists,ExternalId,SeriesPresentationUniqueKey,ShowId,OwnerId) - values (@guid,@type,@data,@Path,@StartDate,@EndDate,@ChannelId,@IsMovie,@IsSeries,@EpisodeTitle,@IsRepeat,@CommunityRating,@CustomRating,@IndexNumber,@IsLocked,@Name,@OfficialRating,@MediaType,@Overview,@ParentIndexNumber,@PremiereDate,@ProductionYear,@ParentId,@Genres,@InheritedParentalRatingValue,@SortName,@ForcedSortName,@RunTimeTicks,@Size,@DateCreated,@DateModified,@PreferredMetadataLanguage,@PreferredMetadataCountryCode,@Width,@Height,@DateLastRefreshed,@DateLastSaved,@IsInMixedFolder,@LockedFields,@Studios,@Audio,@ExternalServiceId,@Tags,@IsFolder,@UnratedType,@TopParentId,@TrailerTypes,@CriticRating,@CleanName,@PresentationUniqueKey,@OriginalTitle,@PrimaryVersionId,@DateLastMediaAdded,@Album,@LUFS,@IsVirtualItem,@SeriesName,@UserDataKey,@SeasonName,@SeasonId,@SeriesId,@ExternalSeriesId,@Tagline,@ProviderIds,@Images,@ProductionLocations,@ExtraIds,@TotalBitrate,@ExtraType,@Artists,@AlbumArtists,@ExternalId,@SeriesPresentationUniqueKey,@ShowId,@OwnerId)"; + (guid,type,data,Path,StartDate,EndDate,ChannelId,IsMovie,IsSeries,EpisodeTitle,IsRepeat,CommunityRating,CustomRating,IndexNumber,IsLocked,Name,OfficialRating,MediaType,Overview,ParentIndexNumber,PremiereDate,ProductionYear,ParentId,Genres,InheritedParentalRatingValue,SortName,ForcedSortName,RunTimeTicks,Size,DateCreated,DateModified,PreferredMetadataLanguage,PreferredMetadataCountryCode,Width,Height,DateLastRefreshed,DateLastSaved,IsInMixedFolder,LockedFields,Studios,Audio,ExternalServiceId,Tags,IsFolder,UnratedType,TopParentId,TrailerTypes,CriticRating,CleanName,PresentationUniqueKey,OriginalTitle,PrimaryVersionId,DateLastMediaAdded,Album,LUFS,NormalizationGain,IsVirtualItem,SeriesName,UserDataKey,SeasonName,SeasonId,SeriesId,ExternalSeriesId,Tagline,ProviderIds,Images,ProductionLocations,ExtraIds,TotalBitrate,ExtraType,Artists,AlbumArtists,ExternalId,SeriesPresentationUniqueKey,ShowId,OwnerId) + values (@guid,@type,@data,@Path,@StartDate,@EndDate,@ChannelId,@IsMovie,@IsSeries,@EpisodeTitle,@IsRepeat,@CommunityRating,@CustomRating,@IndexNumber,@IsLocked,@Name,@OfficialRating,@MediaType,@Overview,@ParentIndexNumber,@PremiereDate,@ProductionYear,@ParentId,@Genres,@InheritedParentalRatingValue,@SortName,@ForcedSortName,@RunTimeTicks,@Size,@DateCreated,@DateModified,@PreferredMetadataLanguage,@PreferredMetadataCountryCode,@Width,@Height,@DateLastRefreshed,@DateLastSaved,@IsInMixedFolder,@LockedFields,@Studios,@Audio,@ExternalServiceId,@Tags,@IsFolder,@UnratedType,@TopParentId,@TrailerTypes,@CriticRating,@CleanName,@PresentationUniqueKey,@OriginalTitle,@PrimaryVersionId,@DateLastMediaAdded,@Album,@LUFS,@NormalizationGain,@IsVirtualItem,@SeriesName,@UserDataKey,@SeasonName,@SeasonId,@SeriesId,@ExternalSeriesId,@Tagline,@ProviderIds,@Images,@ProductionLocations,@ExtraIds,@TotalBitrate,@ExtraType,@Artists,@AlbumArtists,@ExternalId,@SeriesPresentationUniqueKey,@ShowId,@OwnerId)"; private readonly IServerConfigurationManager _config; private readonly IServerApplicationHost _appHost; @@ -111,6 +111,7 @@ namespace Emby.Server.Implementations.Data "DateLastMediaAdded", "Album", "LUFS", + "NormalizationGain", "CriticRating", "IsVirtualItem", "SeriesName", @@ -478,6 +479,7 @@ namespace Emby.Server.Implementations.Data AddColumn(connection, "TypedBaseItems", "DateLastMediaAdded", "DATETIME", existingColumnNames); AddColumn(connection, "TypedBaseItems", "Album", "Text", existingColumnNames); AddColumn(connection, "TypedBaseItems", "LUFS", "Float", existingColumnNames); + AddColumn(connection, "TypedBaseItems", "NormalizationGain", "Float", existingColumnNames); AddColumn(connection, "TypedBaseItems", "IsVirtualItem", "BIT", existingColumnNames); AddColumn(connection, "TypedBaseItems", "SeriesName", "Text", existingColumnNames); AddColumn(connection, "TypedBaseItems", "UserDataKey", "Text", existingColumnNames); @@ -886,6 +888,7 @@ namespace Emby.Server.Implementations.Data saveItemStatement.TryBind("@Album", item.Album); saveItemStatement.TryBind("@LUFS", item.LUFS); + saveItemStatement.TryBind("@NormalizationGain", item.NormalizationGain); saveItemStatement.TryBind("@IsVirtualItem", item.IsVirtualItem); if (item is IHasSeries hasSeriesName) @@ -1672,6 +1675,11 @@ namespace Emby.Server.Implementations.Data item.LUFS = lUFS; } + if (reader.TryGetSingle(index++, out var normalizationGain)) + { + item.NormalizationGain = normalizationGain; + } + if (reader.TryGetSingle(index++, out var criticRating)) { item.CriticRating = criticRating; diff --git a/Emby.Server.Implementations/Dto/DtoService.cs b/Emby.Server.Implementations/Dto/DtoService.cs index 98eacb52b..19902b26a 100644 --- a/Emby.Server.Implementations/Dto/DtoService.cs +++ b/Emby.Server.Implementations/Dto/DtoService.cs @@ -898,7 +898,15 @@ namespace Emby.Server.Implementations.Dto dto.IsPlaceHolder = supportsPlaceHolders.IsPlaceHolder; } - dto.LUFS = item.LUFS; + if (item.LUFS.HasValue) + { + // -18 LUFS reference, same as ReplayGain 2.0, compatible with ReplayGain 1.0 + dto.NormalizationGain = -18f - item.LUFS; + } + else if (item.NormalizationGain.HasValue) + { + dto.NormalizationGain = item.NormalizationGain; + } // Add audio info if (item is Audio audio) diff --git a/Emby.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs b/Emby.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs index 0bfb7fbe6..9405f2102 100644 --- a/Emby.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs @@ -13,7 +13,6 @@ using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Providers; using MediaBrowser.Controller.Resolvers; -using MediaBrowser.Model.Entities; using MediaBrowser.Model.IO; using Microsoft.Extensions.Logging; diff --git a/Emby.Server.Implementations/Localization/Core/en-US.json b/Emby.Server.Implementations/Localization/Core/en-US.json index 4ba31bee0..c229f3538 100644 --- a/Emby.Server.Implementations/Localization/Core/en-US.json +++ b/Emby.Server.Implementations/Localization/Core/en-US.json @@ -106,6 +106,8 @@ "TaskCleanCacheDescription": "Deletes cache files no longer needed by the system.", "TaskRefreshChapterImages": "Extract Chapter Images", "TaskRefreshChapterImagesDescription": "Creates thumbnails for videos that have chapters.", + "TaskAudioNormalization": "Audio Normalization", + "TaskAudioNormalizationDescription": "Scans files for audio normalization data.", "TaskRefreshLibrary": "Scan Media Library", "TaskRefreshLibraryDescription": "Scans your media library for new files and refreshes metadata.", "TaskCleanLogs": "Clean Log Directory", diff --git a/Emby.Server.Implementations/ScheduledTasks/Tasks/AudioNormalizationTask.cs b/Emby.Server.Implementations/ScheduledTasks/Tasks/AudioNormalizationTask.cs new file mode 100644 index 000000000..04d6ed0f2 --- /dev/null +++ b/Emby.Server.Implementations/ScheduledTasks/Tasks/AudioNormalizationTask.cs @@ -0,0 +1,195 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Text.RegularExpressions; +using System.Threading; +using System.Threading.Tasks; +using Jellyfin.Data.Enums; +using MediaBrowser.Common.Configuration; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities.Audio; +using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.MediaEncoding; +using MediaBrowser.Controller.Persistence; +using MediaBrowser.Model.Globalization; +using MediaBrowser.Model.Tasks; +using Microsoft.Extensions.Logging; + +namespace Emby.Server.Implementations.ScheduledTasks.Tasks; + +/// <summary> +/// The audio normalization task. +/// </summary> +public partial class AudioNormalizationTask : IScheduledTask +{ + private readonly IItemRepository _itemRepository; + private readonly ILibraryManager _libraryManager; + private readonly IMediaEncoder _mediaEncoder; + private readonly IConfigurationManager _configurationManager; + private readonly ILocalizationManager _localization; + private readonly ILogger<AudioNormalizationTask> _logger; + + /// <summary> + /// Initializes a new instance of the <see cref="AudioNormalizationTask"/> class. + /// </summary> + /// <param name="itemRepository">Instance of the <see cref="IItemRepository"/> interface.</param> + /// <param name="libraryManager">Instance of the <see cref="ILibraryManager"/> interface.</param> + /// <param name="mediaEncoder">Instance of the <see cref="IMediaEncoder"/> interface.</param> + /// <param name="configurationManager">Instance of the <see cref="IConfigurationManager"/> interface.</param> + /// <param name="localizationManager">Instance of the <see cref="ILocalizationManager"/> interface.</param> + /// <param name="logger">Instance of the <see cref="ILogger{AudioNormalizationTask}"/> interface.</param> + public AudioNormalizationTask( + IItemRepository itemRepository, + ILibraryManager libraryManager, + IMediaEncoder mediaEncoder, + IConfigurationManager configurationManager, + ILocalizationManager localizationManager, + ILogger<AudioNormalizationTask> logger) + { + _itemRepository = itemRepository; + _libraryManager = libraryManager; + _mediaEncoder = mediaEncoder; + _configurationManager = configurationManager; + _localization = localizationManager; + _logger = logger; + } + + /// <inheritdoc /> + public string Name => _localization.GetLocalizedString("TaskAudioNormalization"); + + /// <inheritdoc /> + public string Description => _localization.GetLocalizedString("TaskAudioNormalizationDescription"); + + /// <inheritdoc /> + public string Category => _localization.GetLocalizedString("TasksLibraryCategory"); + + /// <inheritdoc /> + public string Key => "AudioNormalization"; + + [GeneratedRegex(@"I:\s+(.*?)\s+LUFS")] + private static partial Regex LUFSRegex(); + + /// <inheritdoc /> + public async Task ExecuteAsync(IProgress<double> progress, CancellationToken cancellationToken) + { + foreach (var library in _libraryManager.RootFolder.Children) + { + var libraryOptions = _libraryManager.GetLibraryOptions(library); + if (!libraryOptions.EnableLUFSScan) + { + continue; + } + + // Album gain + var albums = _libraryManager.GetItemList(new InternalItemsQuery + { + IncludeItemTypes = [BaseItemKind.MusicAlbum], + Parent = library, + Recursive = true + }); + + foreach (var a in albums) + { + if (a.NormalizationGain.HasValue || a.LUFS.HasValue) + { + continue; + } + + // 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; + } + + var tempFile = Path.Join(_configurationManager.GetTranscodePath(), Guid.NewGuid() + ".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); + a.LUFS = await CalculateLUFSAsync( + string.Format(CultureInfo.InvariantCulture, "-f concat -safe 0 -i \"{0}\"", tempFile), + cancellationToken).ConfigureAwait(false); + File.Delete(tempFile); + } + + _itemRepository.SaveItems(albums, cancellationToken); + + // Track gain + var tracks = _libraryManager.GetItemList(new InternalItemsQuery + { + MediaTypes = [MediaType.Audio], + IncludeItemTypes = [BaseItemKind.Audio], + Parent = library, + Recursive = true + }); + + foreach (var t in tracks) + { + 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)), cancellationToken); + } + + _itemRepository.SaveItems(tracks, cancellationToken); + } + } + + /// <inheritdoc /> + public IEnumerable<TaskTriggerInfo> GetDefaultTriggers() + { + return + [ + new TaskTriggerInfo + { + Type = TaskTriggerInfo.TriggerInterval, + IntervalTicks = TimeSpan.FromHours(24).Ticks + } + ]; + } + + private async Task<float?> CalculateLUFSAsync(string inputArgs, CancellationToken cancellationToken) + { + var args = $"-hide_banner {inputArgs} -af ebur128=framelog=verbose -f null -"; + + using (var process = new Process() + { + StartInfo = new ProcessStartInfo + { + FileName = _mediaEncoder.EncoderPath, + Arguments = args, + RedirectStandardOutput = false, + RedirectStandardError = true + }, + }) + { + try + { + _logger.LogDebug("Starting ffmpeg with arguments: {Arguments}", args); + process.Start(); + } + catch (Exception ex) + { + _logger.LogError(ex, "Error starting ffmpeg with arguments: {Arguments}", args); + return null; + } + + using var reader = process.StandardError; + var output = await reader.ReadToEndAsync(cancellationToken).ConfigureAwait(false); + cancellationToken.ThrowIfCancellationRequested(); + MatchCollection split = LUFSRegex().Matches(output); + + if (split.Count != 0) + { + return float.Parse(split[0].Groups[1].ValueSpan, CultureInfo.InvariantCulture.NumberFormat); + } + + _logger.LogError("Failed to find LUFS value in output:\n{Output}", output); + return null; + } + } +} diff --git a/Emby.Server.Implementations/ScheduledTasks/Tasks/ChapterImagesTask.cs b/Emby.Server.Implementations/ScheduledTasks/Tasks/ChapterImagesTask.cs index d03d40863..36456504b 100644 --- a/Emby.Server.Implementations/ScheduledTasks/Tasks/ChapterImagesTask.cs +++ b/Emby.Server.Implementations/ScheduledTasks/Tasks/ChapterImagesTask.cs @@ -13,7 +13,6 @@ using MediaBrowser.Controller.Library; using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.Controller.Persistence; using MediaBrowser.Controller.Providers; -using MediaBrowser.Model.Entities; using MediaBrowser.Model.Globalization; using MediaBrowser.Model.IO; using MediaBrowser.Model.Tasks; diff --git a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs index 237345206..5b3349108 100644 --- a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs +++ b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs @@ -183,14 +183,13 @@ namespace MediaBrowser.Controller.Entities.Audio progress.Report(percent * 95); } - // get album LUFS - LUFS = items.OfType<Audio>().Max(item => item.LUFS); - var parentRefreshOptions = refreshOptions; if (childUpdateType > ItemUpdateType.None) { - parentRefreshOptions = new MetadataRefreshOptions(refreshOptions); - parentRefreshOptions.MetadataRefreshMode = MetadataRefreshMode.FullRefresh; + parentRefreshOptions = new MetadataRefreshOptions(refreshOptions) + { + MetadataRefreshMode = MetadataRefreshMode.FullRefresh + }; } // Refresh current item diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index 474b093d5..adbbbaa03 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -138,6 +138,13 @@ namespace MediaBrowser.Controller.Entities public float? LUFS { get; set; } /// <summary> + /// Gets or sets the gain required for audio normalization. + /// </summary> + /// <value>The gain required for audio normalization.</value> + [JsonIgnore] + public float? NormalizationGain { get; set; } + + /// <summary> /// Gets or sets the channel identifier. /// </summary> /// <value>The channel identifier.</value> diff --git a/MediaBrowser.Model/Dto/BaseItemDto.cs b/MediaBrowser.Model/Dto/BaseItemDto.cs index 6d5c84e1d..7e8949e1f 100644 --- a/MediaBrowser.Model/Dto/BaseItemDto.cs +++ b/MediaBrowser.Model/Dto/BaseItemDto.cs @@ -782,10 +782,10 @@ namespace MediaBrowser.Model.Dto public string TimerId { get; set; } /// <summary> - /// Gets or sets the LUFS value. + /// Gets or sets the gain required for audio normalization. /// </summary> - /// <value>The LUFS Value.</value> - public float? LUFS { get; set; } + /// <value>The gain required for audio normalization.</value> + public float? NormalizationGain { get; set; } /// <summary> /// Gets or sets the current program. diff --git a/MediaBrowser.Providers/MediaInfo/AudioFileProber.cs b/MediaBrowser.Providers/MediaInfo/AudioFileProber.cs index 17d2ab71d..9b2610ee7 100644 --- a/MediaBrowser.Providers/MediaInfo/AudioFileProber.cs +++ b/MediaBrowser.Providers/MediaInfo/AudioFileProber.cs @@ -1,9 +1,6 @@ using System; using System.Collections.Generic; -using System.Diagnostics; -using System.Globalization; using System.Linq; -using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; using Jellyfin.Data.Enums; @@ -18,7 +15,6 @@ using MediaBrowser.Model.Dlna; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; using MediaBrowser.Model.MediaInfo; -using Microsoft.Extensions.Logging; using TagLib; namespace MediaBrowser.Providers.MediaInfo @@ -26,12 +22,8 @@ namespace MediaBrowser.Providers.MediaInfo /// <summary> /// Probes audio files for metadata. /// </summary> - public partial class AudioFileProber + public class AudioFileProber { - // Default LUFS value for use with the web interface, at -18db gain will be 1(no db gain). - private const float DefaultLUFSValue = -18; - - private readonly ILogger<AudioFileProber> _logger; private readonly IMediaEncoder _mediaEncoder; private readonly IItemRepository _itemRepo; private readonly ILibraryManager _libraryManager; @@ -42,7 +34,6 @@ namespace MediaBrowser.Providers.MediaInfo /// <summary> /// Initializes a new instance of the <see cref="AudioFileProber"/> class. /// </summary> - /// <param name="logger">Instance of the <see cref="ILogger"/> interface.</param> /// <param name="mediaSourceManager">Instance of the <see cref="IMediaSourceManager"/> interface.</param> /// <param name="mediaEncoder">Instance of the <see cref="IMediaEncoder"/> interface.</param> /// <param name="itemRepo">Instance of the <see cref="IItemRepository"/> interface.</param> @@ -50,7 +41,6 @@ namespace MediaBrowser.Providers.MediaInfo /// <param name="lyricResolver">Instance of the <see cref="LyricResolver"/> interface.</param> /// <param name="lyricManager">Instance of the <see cref="ILyricManager"/> interface.</param> public AudioFileProber( - ILogger<AudioFileProber> logger, IMediaSourceManager mediaSourceManager, IMediaEncoder mediaEncoder, IItemRepository itemRepo, @@ -58,7 +48,6 @@ namespace MediaBrowser.Providers.MediaInfo LyricResolver lyricResolver, ILyricManager lyricManager) { - _logger = logger; _mediaEncoder = mediaEncoder; _itemRepo = itemRepo; _libraryManager = libraryManager; @@ -67,9 +56,6 @@ namespace MediaBrowser.Providers.MediaInfo _lyricManager = lyricManager; } - [GeneratedRegex(@"I:\s+(.*?)\s+LUFS")] - private static partial Regex LUFSRegex(); - /// <summary> /// Probes the specified item for metadata. /// </summary> @@ -112,45 +98,6 @@ namespace MediaBrowser.Providers.MediaInfo await FetchAsync(item, result, options, cancellationToken).ConfigureAwait(false); } - var libraryOptions = _libraryManager.GetLibraryOptions(item); - if (libraryOptions.EnableLUFSScan && item.LUFS is null) - { - using (var process = new Process() - { - StartInfo = new ProcessStartInfo - { - FileName = _mediaEncoder.EncoderPath, - Arguments = $"-hide_banner -i \"{path}\" -af ebur128=framelog=verbose -f null -", - RedirectStandardOutput = false, - RedirectStandardError = true - }, - }) - { - try - { - process.Start(); - } - catch (Exception ex) - { - _logger.LogError(ex, "Error starting ffmpeg"); - - throw; - } - - using var reader = process.StandardError; - var output = await reader.ReadToEndAsync(cancellationToken).ConfigureAwait(false); - cancellationToken.ThrowIfCancellationRequested(); - MatchCollection split = LUFSRegex().Matches(output); - - if (split.Count != 0) - { - item.LUFS = float.Parse(split[0].Groups[1].ValueSpan, CultureInfo.InvariantCulture.NumberFormat); - } - } - } - - _logger.LogDebug("LUFS for {ItemName} is {LUFS}.", item.Name, item.LUFS); - return ItemUpdateType.MetadataImport; } @@ -339,7 +286,7 @@ namespace MediaBrowser.Providers.MediaInfo if (!double.IsNaN(tags.ReplayGainTrackGain)) { - audio.LUFS = DefaultLUFSValue - (float)tags.ReplayGainTrackGain; + audio.NormalizationGain = (float)tags.ReplayGainTrackGain; } if (options.ReplaceAllMetadata || !audio.TryGetProviderId(MetadataProvider.MusicBrainzArtist, out _)) diff --git a/MediaBrowser.Providers/MediaInfo/ProbeProvider.cs b/MediaBrowser.Providers/MediaInfo/ProbeProvider.cs index 8bb8d5bb4..b330b419b 100644 --- a/MediaBrowser.Providers/MediaInfo/ProbeProvider.cs +++ b/MediaBrowser.Providers/MediaInfo/ProbeProvider.cs @@ -103,7 +103,6 @@ namespace MediaBrowser.Providers.MediaInfo _subtitleResolver); _audioProber = new AudioFileProber( - loggerFactory.CreateLogger<AudioFileProber>(), mediaSourceManager, mediaEncoder, itemRepo, |
