diff --git a/src/NzbDrone.Core/MediaFiles/MediaInfo/MediaInfoModel.cs b/src/NzbDrone.Core/MediaFiles/MediaInfo/MediaInfoModel.cs index 964c62d4d..f4242ed13 100644 --- a/src/NzbDrone.Core/MediaFiles/MediaInfo/MediaInfoModel.cs +++ b/src/NzbDrone.Core/MediaFiles/MediaInfo/MediaInfoModel.cs @@ -1,4 +1,8 @@ using System; +using System.Globalization; +using System.Linq; +using Newtonsoft.Json; +using NzbDrone.Common.Extensions; using NzbDrone.Core.Datastore; namespace NzbDrone.Core.MediaFiles.MediaInfo @@ -7,6 +11,7 @@ namespace NzbDrone.Core.MediaFiles.MediaInfo { public string VideoCodec { get; set; } public int VideoBitrate { get; set; } + public int VideoBitDepth { get; set; } public int Width { get; set; } public int Height { get; set; } public string AudioFormat { get; set; } @@ -14,10 +19,26 @@ namespace NzbDrone.Core.MediaFiles.MediaInfo public TimeSpan RunTime { get; set; } public int AudioStreamCount { get; set; } public int AudioChannels { get; set; } + public string AudioChannelPositions { get; set; } public string AudioProfile { get; set; } public decimal VideoFps { get; set; } public string AudioLanguages { get; set; } public string Subtitles { get; set; } public string ScanType { get; set; } + public int SchemaRevision { get; set; } + + [JsonIgnore] + public decimal FormattedAudioChannels + { + get + { + if (AudioChannelPositions.IsNullOrWhiteSpace()) + { + return 0; + } + + return AudioChannelPositions.Split('/').Sum(s => decimal.Parse(s, CultureInfo.InvariantCulture)); + } + } } } diff --git a/src/NzbDrone.Core/MediaFiles/MediaInfo/UpdateMediaInfoService.cs b/src/NzbDrone.Core/MediaFiles/MediaInfo/UpdateMediaInfoService.cs index dc6cadc8b..8918835c4 100644 --- a/src/NzbDrone.Core/MediaFiles/MediaInfo/UpdateMediaInfoService.cs +++ b/src/NzbDrone.Core/MediaFiles/MediaInfo/UpdateMediaInfoService.cs @@ -18,6 +18,8 @@ namespace NzbDrone.Core.MediaFiles.MediaInfo private readonly IConfigService _configService; private readonly Logger _logger; + private const int CURRENT_MEDIA_INFO_SCHEMA_REVISION = 2; + public UpdateMediaInfoService(IDiskProvider diskProvider, IMediaFileService mediaFileService, IVideoFileInfoReader videoFileInfoReader, @@ -47,6 +49,7 @@ namespace NzbDrone.Core.MediaFiles.MediaInfo if (mediaFile.MediaInfo != null) { + mediaFile.MediaInfo.SchemaRevision = CURRENT_MEDIA_INFO_SCHEMA_REVISION; _mediaFileService.Update(mediaFile); _logger.Debug("Updated MediaInfo for '{0}'", path); } @@ -61,11 +64,10 @@ namespace NzbDrone.Core.MediaFiles.MediaInfo return; } - var mediaFiles = _mediaFileService.GetFilesBySeries(message.Series.Id) - .Where(c => c.MediaInfo == null) - .ToList(); + var allMediaFiles = _mediaFileService.GetFilesBySeries(message.Series.Id); + var filteredMediaFiles = allMediaFiles.Where(c => c.MediaInfo == null || c.MediaInfo.SchemaRevision < CURRENT_MEDIA_INFO_SCHEMA_REVISION).ToList(); - UpdateMediaInfo(message.Series, mediaFiles); + UpdateMediaInfo(message.Series, filteredMediaFiles); } } } diff --git a/src/NzbDrone.Core/MediaFiles/MediaInfo/VideoFileInfoReader.cs b/src/NzbDrone.Core/MediaFiles/MediaInfo/VideoFileInfoReader.cs index 204c06ae5..bf46b58b2 100644 --- a/src/NzbDrone.Core/MediaFiles/MediaInfo/VideoFileInfoReader.cs +++ b/src/NzbDrone.Core/MediaFiles/MediaInfo/VideoFileInfoReader.cs @@ -88,6 +88,7 @@ namespace NzbDrone.Core.MediaFiles.MediaInfo int generalRuntime; int streamCount; int audioChannels; + int videoBitDepth; decimal videoFrameRate; string subtitles = mediaInfo.Get(StreamKind.General, 0, "Text_Language_List"); @@ -96,6 +97,7 @@ namespace NzbDrone.Core.MediaFiles.MediaInfo int.TryParse(mediaInfo.Get(StreamKind.Video, 0, "Height"), out height); int.TryParse(mediaInfo.Get(StreamKind.Video, 0, "BitRate"), out videoBitRate); decimal.TryParse(mediaInfo.Get(StreamKind.Video, 0, "FrameRate"), NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out videoFrameRate); + int.TryParse(mediaInfo.Get(StreamKind.Video, 0, "BitDepth"), out videoBitDepth); //Runtime int.TryParse(mediaInfo.Get(StreamKind.Video, 0, "PlayTime"), out videoRuntime); @@ -105,7 +107,9 @@ namespace NzbDrone.Core.MediaFiles.MediaInfo string aBitRate = mediaInfo.Get(StreamKind.Audio, 0, "BitRate"); int aBindex = aBitRate.IndexOf(" /", StringComparison.InvariantCultureIgnoreCase); if (aBindex > 0) + { aBitRate = aBitRate.Remove(aBindex); + } int.TryParse(aBitRate, out audioBitRate); int.TryParse(mediaInfo.Get(StreamKind.Audio, 0, "StreamCount"), out streamCount); @@ -113,21 +117,30 @@ namespace NzbDrone.Core.MediaFiles.MediaInfo string audioChannelsStr = mediaInfo.Get(StreamKind.Audio, 0, "Channel(s)"); int aCindex = audioChannelsStr.IndexOf(" /", StringComparison.InvariantCultureIgnoreCase); + if (aCindex > 0) + { audioChannelsStr = audioChannelsStr.Remove(aCindex); + } + + var audioChannelPositions = mediaInfo.Get(StreamKind.Audio, 0, "ChannelPositions/String2"); string audioLanguages = mediaInfo.Get(StreamKind.General, 0, "Audio_Language_List"); string audioProfile = mediaInfo.Get(StreamKind.Audio, 0, "Format_Profile"); int aPindex = audioProfile.IndexOf(" /", StringComparison.InvariantCultureIgnoreCase); + if (aPindex > 0) + { audioProfile = audioProfile.Remove(aPindex); + } int.TryParse(audioChannelsStr, out audioChannels); var mediaInfoModel = new MediaInfoModel { VideoCodec = mediaInfo.Get(StreamKind.Video, 0, "Codec/String"), VideoBitrate = videoBitRate, + VideoBitDepth = videoBitDepth, Height = height, Width = width, AudioFormat = mediaInfo.Get(StreamKind.Audio, 0, "Format"), @@ -135,6 +148,7 @@ namespace NzbDrone.Core.MediaFiles.MediaInfo RunTime = GetBestRuntime(audioRuntime, videoRuntime, generalRuntime), AudioStreamCount = streamCount, AudioChannels = audioChannels, + AudioChannelPositions = audioChannelPositions, AudioProfile = audioProfile.Trim(), VideoFps = videoFrameRate, AudioLanguages = audioLanguages, diff --git a/src/NzbDrone.Core/Organizer/FileNameBuilder.cs b/src/NzbDrone.Core/Organizer/FileNameBuilder.cs index 48ff833f0..4ff8f0368 100644 --- a/src/NzbDrone.Core/Organizer/FileNameBuilder.cs +++ b/src/NzbDrone.Core/Organizer/FileNameBuilder.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.IO; using System.Linq; using System.Text.RegularExpressions; @@ -444,60 +445,60 @@ namespace NzbDrone.Core.Organizer { if (episodeFile.MediaInfo == null) return; - string mediaInfoVideo; + string videoCodec; switch (episodeFile.MediaInfo.VideoCodec) { case "AVC": if (episodeFile.SceneName.IsNotNullOrWhiteSpace() && Path.GetFileNameWithoutExtension(episodeFile.SceneName).Contains("h264")) { - mediaInfoVideo = "h264"; + videoCodec = "h264"; } else { - mediaInfoVideo = "x264"; + videoCodec = "x264"; } break; case "V_MPEGH/ISO/HEVC": if (episodeFile.SceneName.IsNotNullOrWhiteSpace() && Path.GetFileNameWithoutExtension(episodeFile.SceneName).Contains("h265")) { - mediaInfoVideo = "h265"; + videoCodec = "h265"; } else { - mediaInfoVideo = "x265"; + videoCodec = "x265"; } break; default: - mediaInfoVideo = episodeFile.MediaInfo.VideoCodec; + videoCodec = episodeFile.MediaInfo.VideoCodec; break; } - string mediaInfoAudio; + string audioCodec; switch (episodeFile.MediaInfo.AudioFormat) { case "AC-3": - mediaInfoAudio = "AC3"; + audioCodec = "AC3"; break; case "MPEG Audio": if (episodeFile.MediaInfo.AudioProfile == "Layer 3") { - mediaInfoAudio = "MP3"; + audioCodec = "MP3"; } else { - mediaInfoAudio = episodeFile.MediaInfo.AudioFormat; + audioCodec = episodeFile.MediaInfo.AudioFormat; } break; case "DTS": - mediaInfoAudio = episodeFile.MediaInfo.AudioFormat; + audioCodec = episodeFile.MediaInfo.AudioFormat; break; default: - mediaInfoAudio = episodeFile.MediaInfo.AudioFormat; + audioCodec = episodeFile.MediaInfo.AudioFormat; break; } @@ -518,12 +519,22 @@ namespace NzbDrone.Core.Organizer mediaInfoSubtitleLanguages = string.Format("[{0}]", mediaInfoSubtitleLanguages); } - tokenHandlers["{MediaInfo Video}"] = m => mediaInfoVideo; - tokenHandlers["{MediaInfo Audio}"] = m => mediaInfoAudio; + var videoBitDepth = episodeFile.MediaInfo.VideoBitDepth > 0 ? episodeFile.MediaInfo.VideoBitDepth.ToString() : string.Empty; + var audioChannels = episodeFile.MediaInfo.FormattedAudioChannels > 0 ? + episodeFile.MediaInfo.FormattedAudioChannels.ToString(CultureInfo.InvariantCulture) : + string.Empty; - tokenHandlers["{MediaInfo Simple}"] = m => string.Format("{0} {1}", mediaInfoVideo, mediaInfoAudio); + tokenHandlers["{MediaInfo Video}"] = m => videoCodec; + tokenHandlers["{MediaInfo VideoCodec}"] = m => videoCodec; + tokenHandlers["{MediaInfo VideoBitDepth}"] = m => videoBitDepth; - tokenHandlers["{MediaInfo Full}"] = m => string.Format("{0} {1}{2} {3}", mediaInfoVideo, mediaInfoAudio, mediaInfoAudioLanguages, mediaInfoSubtitleLanguages); + tokenHandlers["{MediaInfo Audio}"] = m => audioCodec; + tokenHandlers["{MediaInfo AudioCodec}"] = m => audioCodec; + tokenHandlers["{MediaInfo AudioChannels}"] = m => audioChannels; + + tokenHandlers["{MediaInfo Simple}"] = m => string.Format("{0} {1}", videoCodec, audioCodec); + + tokenHandlers["{MediaInfo Full}"] = m => string.Format("{0} {1}{2} {3}", videoCodec, audioCodec, mediaInfoAudioLanguages, mediaInfoSubtitleLanguages); } private string GetLanguagesToken(string mediaInfoLanguages)