diff --git a/frontend/src/MovieFile/Editor/MediaInfo.tsx b/frontend/src/MovieFile/Editor/MediaInfo.tsx index d0a8951750..f5e3db21f6 100644 --- a/frontend/src/MovieFile/Editor/MediaInfo.tsx +++ b/frontend/src/MovieFile/Editor/MediaInfo.tsx @@ -2,6 +2,7 @@ import React from 'react'; import DescriptionList from 'Components/DescriptionList/DescriptionList'; import DescriptionListItem from 'Components/DescriptionList/DescriptionListItem'; import MediaInfoProps from 'typings/MediaInfo'; +import formatBitrate from 'Utilities/Number/formatBitrate'; import getEntries from 'Utilities/Object/getEntries'; function MediaInfo(props: MediaInfoProps) { @@ -16,9 +17,19 @@ function MediaInfo(props: MediaInfoProps) { return null; } - return ( - - ); + if (key === 'audioBitrate' || key === 'videoBitrate') { + return ( + {formatBitrate(value)} + } + /> + ); + } + + return ; })} ); diff --git a/frontend/src/Utilities/Number/formatBitrate.ts b/frontend/src/Utilities/Number/formatBitrate.ts new file mode 100644 index 0000000000..5d7d25ae4a --- /dev/null +++ b/frontend/src/Utilities/Number/formatBitrate.ts @@ -0,0 +1,19 @@ +import { filesize } from 'filesize'; + +function formatBitrate(input: string | number) { + const size = Number(input); + + if (isNaN(size)) { + return ''; + } + + const { value, symbol } = filesize(size, { + base: 10, + round: 1, + output: 'object', + }); + + return `${value} ${symbol}/s`; +} + +export default formatBitrate; diff --git a/src/NzbDrone.Core/MediaFiles/MediaInfo/VideoFileInfoReader.cs b/src/NzbDrone.Core/MediaFiles/MediaInfo/VideoFileInfoReader.cs index 868d7749a6..cbfb17e888 100644 --- a/src/NzbDrone.Core/MediaFiles/MediaInfo/VideoFileInfoReader.cs +++ b/src/NzbDrone.Core/MediaFiles/MediaInfo/VideoFileInfoReader.cs @@ -21,8 +21,8 @@ public class VideoFileInfoReader : IVideoFileInfoReader private readonly Logger _logger; private readonly List _pixelFormats; - public const int MINIMUM_MEDIA_INFO_SCHEMA_REVISION = 8; - public const int CURRENT_MEDIA_INFO_SCHEMA_REVISION = 13; + public const int MINIMUM_MEDIA_INFO_SCHEMA_REVISION = 14; + public const int CURRENT_MEDIA_INFO_SCHEMA_REVISION = 14; private static readonly string[] ValidHdrColourPrimaries = { "bt2020" }; private static readonly string[] HlgTransferFunctions = { "arib-std-b67" }; @@ -80,7 +80,7 @@ public MediaInfoModel GetMediaInfo(string filename) mediaInfoModel.VideoFormat = primaryVideoStream?.CodecName; mediaInfoModel.VideoCodecID = primaryVideoStream?.CodecTagString; mediaInfoModel.VideoProfile = primaryVideoStream?.Profile; - mediaInfoModel.VideoBitrate = primaryVideoStream?.BitRate ?? 0; + mediaInfoModel.VideoBitrate = GetBitrate(primaryVideoStream); mediaInfoModel.VideoMultiViewCount = primaryVideoStream?.Tags?.ContainsKey("stereo_mode") ?? false ? 2 : 1; mediaInfoModel.VideoBitDepth = GetPixelFormat(primaryVideoStream?.PixelFormat)?.Components.Min(x => x.BitDepth) ?? 8; mediaInfoModel.VideoColourPrimaries = primaryVideoStream?.ColorPrimaries; @@ -91,7 +91,7 @@ public MediaInfoModel GetMediaInfo(string filename) mediaInfoModel.AudioFormat = analysis.PrimaryAudioStream?.CodecName; mediaInfoModel.AudioCodecID = analysis.PrimaryAudioStream?.CodecTagString; mediaInfoModel.AudioProfile = analysis.PrimaryAudioStream?.Profile; - mediaInfoModel.AudioBitrate = analysis.PrimaryAudioStream?.BitRate ?? 0; + mediaInfoModel.AudioBitrate = GetBitrate(analysis.PrimaryAudioStream); mediaInfoModel.RunTime = GetBestRuntime(analysis.PrimaryAudioStream?.Duration, primaryVideoStream?.Duration, analysis.Format.Duration); mediaInfoModel.AudioStreamCount = analysis.AudioStreams.Count; mediaInfoModel.AudioChannels = analysis.PrimaryAudioStream?.Channels ?? 0; @@ -161,6 +161,21 @@ private static TimeSpan GetBestRuntime(TimeSpan? audio, TimeSpan? video, TimeSpa return video.Value; } + private static long GetBitrate(MediaStream mediaStream) + { + if (mediaStream?.BitRate is > 0) + { + return mediaStream.BitRate; + } + + if ((mediaStream?.Tags?.TryGetValue("BPS", out var bitratePerSecond) ?? false) && bitratePerSecond.IsNotNullOrWhiteSpace()) + { + return Convert.ToInt64(bitratePerSecond); + } + + return 0; + } + private VideoStream GetPrimaryVideoStream(IMediaAnalysis mediaAnalysis) { if (mediaAnalysis.VideoStreams.Count <= 1)