mirror of
https://github.com/Radarr/Radarr.git
synced 2024-09-11 12:02:35 +02:00
Fixed: MediaInfo Improvements, Tests
This commit is contained in:
parent
5657a4df9c
commit
582402d45e
@ -24,14 +24,26 @@ public void should_format_audio_format_legacy(string audioFormat, string expecte
|
||||
MediaInfoFormatter.FormatAudioCodec(mediaInfoModel, sceneName).Should().Be(expectedFormat);
|
||||
}
|
||||
|
||||
[TestCase("MPEG Audio, A_MPEG/L2, , ", "droned.s01e03.swedish.720p.hdtv.x264-prince", "MP2")]
|
||||
[TestCase("Vorbis, A_VORBIS, , Xiph.Org libVorbis I 20101101 (Schaufenugget)", "DB Super HDTV", "Vorbis")]
|
||||
[TestCase("PCM, 1, , ", "DW DVDRip XviD-idTV", "PCM")] // Dubbed most likely
|
||||
[TestCase("TrueHD, A_TRUEHD, , ", "", "TrueHD")]
|
||||
[TestCase("WMA, 161, , ", "Droned.wmv", "WMA")]
|
||||
[TestCase("WMA, 162, Pro, ", "B.N.S04E18.720p.WEB-DL", "WMA")]
|
||||
[TestCase("Opus, A_OPUS, , ", "Roadkill Ep3x11 - YouTube.webm", "Opus")]
|
||||
[TestCase("mp3 , 0, , ", "climbing.mp4", "MP3")]
|
||||
[TestCase("MPEG Audio, A_MPEG/L2, , , ", "droned.s01e03.swedish.720p.hdtv.x264-prince", "MP2")]
|
||||
[TestCase("Vorbis, A_VORBIS, , Xiph.Org libVorbis I 20101101 (Schaufenugget), ", "DB Super HDTV", "Vorbis")]
|
||||
[TestCase("PCM, 1, , , ", "DW DVDRip XviD-idTV, ", "PCM")] // Dubbed most likely
|
||||
[TestCase("TrueHD, A_TRUEHD, , , ", "", "TrueHD")]
|
||||
[TestCase("MLP FBA, A_TRUEHD, , , ", "TrueHD", "TrueHD")]
|
||||
[TestCase("MLP FBA, A_TRUEHD, , , 16-ch", "Atmos", "TrueHD Atmos")]
|
||||
[TestCase("WMA, 161, , , ", "Droned.wmv", "WMA")]
|
||||
[TestCase("WMA, 162, Pro, , ", "B.N.S04E18.720p.WEB-DL", "WMA")]
|
||||
[TestCase("Opus, A_OPUS, , , ", "Roadkill Ep3x11 - YouTube.webm", "Opus")]
|
||||
[TestCase("mp3 , 0, , , ", "climbing.mp4", "MP3")]
|
||||
[TestCase("DTS, A_DTS, , , XLL", "DTS-HD.MA", "DTS-HD MA")]
|
||||
[TestCase("DTS, A_DTS, , , XLL X", "DTS-X", "DTS-X")]
|
||||
[TestCase("DTS, A_DTS, , , ES XLL", "DTS-HD.MA", "DTS-HD MA")]
|
||||
[TestCase("DTS, A_DTS, , , ES", "DTS-ES", "DTS-ES")]
|
||||
[TestCase("DTS, A_DTS, , , ES XXCH", "DTS", "DTS-ES")]
|
||||
[TestCase("DTS, A_DTS, , , XBR", "DTSHD-HRA", "DTS-HD HRA")]
|
||||
[TestCase("DTS, A_DTS, , , DTS", "DTS", "DTS")]
|
||||
[TestCase("E-AC-3, A_EAC3, , , JOC", "EAC3", "EAC3")]
|
||||
[TestCase("E-AC-3, A_EAC3, , , ", "DD5.1", "EAC3")]
|
||||
[TestCase("AC-3, A_AC3, , , ", "DD5.1", "AC3")]
|
||||
public void should_format_audio_format(string audioFormatPack, string sceneName, string expectedFormat)
|
||||
{
|
||||
var split = audioFormatPack.Split(new string[] { ", " }, System.StringSplitOptions.None);
|
||||
@ -40,7 +52,8 @@ public void should_format_audio_format(string audioFormatPack, string sceneName,
|
||||
AudioFormat = split[0],
|
||||
AudioCodecID = split[1],
|
||||
AudioProfile = split[2],
|
||||
AudioCodecLibrary = split[3]
|
||||
AudioCodecLibrary = split[3],
|
||||
AudioAdditionalFeatures = split[4]
|
||||
};
|
||||
|
||||
MediaInfoFormatter.FormatAudioCodec(mediaInfoModel, sceneName).Should().Be(expectedFormat);
|
||||
|
@ -78,6 +78,21 @@ public void should_format_video_format_fallbacks(string videoFormatPack, string
|
||||
MediaInfoFormatter.FormatVideoCodec(mediaInfoModel, sceneName).Should().Be(expectedFormat);
|
||||
}
|
||||
|
||||
[TestCase("MPEG-4 Visual, 20, , Intel(R) MPEG-4 encoder based on Intel(R) IPP 6.1 build 137.20[6.1.137.763]", "", "")]
|
||||
public void should_warn_on_unknown_video_format(string videoFormatPack, string sceneName, string expectedFormat)
|
||||
{
|
||||
var split = videoFormatPack.Split(new string[] { ", " }, System.StringSplitOptions.None);
|
||||
var mediaInfoModel = new MediaInfoModel
|
||||
{
|
||||
VideoFormat = split[0],
|
||||
VideoCodecID = split[1],
|
||||
VideoProfile = split[2],
|
||||
VideoCodecLibrary = split[3]
|
||||
};
|
||||
|
||||
MediaInfoFormatter.FormatVideoCodec(mediaInfoModel, sceneName).Should().Be(expectedFormat);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_VideoFormat_by_default()
|
||||
{
|
||||
|
@ -0,0 +1,30 @@
|
||||
using FluentAssertions;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.MediaFiles.MediaInfo;
|
||||
using NzbDrone.Test.Common;
|
||||
|
||||
namespace NzbDrone.Core.Test.MediaFiles.MediaInfo.MediaInfoFormatterTests
|
||||
{
|
||||
[TestFixture]
|
||||
public class FormatVideoDynamicRangeFixture : TestBase
|
||||
{
|
||||
[TestCase(8, "BT.601 NTSC", "BT.709", "")]
|
||||
[TestCase(10, "BT.2020", "PQ", "HDR")]
|
||||
[TestCase(8, "BT.2020", "PQ", "")]
|
||||
[TestCase(10, "BT.601 NTSC", "PQ", "")]
|
||||
[TestCase(10, "BT.2020", "BT.709", "")]
|
||||
[TestCase(10, "BT.2020", "HLG", "HDR")]
|
||||
public void should_format_video_dynamic_range(int bitDepth, string colourPrimaries, string transferCharacteristics, string expectedVideoDynamicRange)
|
||||
{
|
||||
var mediaInfo = new MediaInfoModel
|
||||
{
|
||||
VideoBitDepth = bitDepth,
|
||||
VideoColourPrimaries = colourPrimaries,
|
||||
VideoTransferCharacteristics = transferCharacteristics,
|
||||
SchemaRevision = 5
|
||||
};
|
||||
|
||||
MediaInfoFormatter.FormatVideoDynamicRange(mediaInfo).Should().Be(expectedVideoDynamicRange);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
using System.IO;
|
||||
using FizzWare.NBuilder;
|
||||
using FluentAssertions;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Common.Disk;
|
||||
@ -56,7 +57,7 @@ private void GivenFailedScan(string path)
|
||||
[Test]
|
||||
public void should_skip_up_to_date_media_info()
|
||||
{
|
||||
var episodeFiles = Builder<MovieFile>.CreateListOfSize(3)
|
||||
var movieFiles = Builder<MovieFile>.CreateListOfSize(3)
|
||||
.All()
|
||||
.With(v => v.RelativePath = "media.mkv")
|
||||
.TheFirst(1)
|
||||
@ -65,7 +66,7 @@ public void should_skip_up_to_date_media_info()
|
||||
|
||||
Mocker.GetMock<IMediaFileService>()
|
||||
.Setup(v => v.GetFilesByMovie(1))
|
||||
.Returns(episodeFiles);
|
||||
.Returns(movieFiles);
|
||||
|
||||
GivenFileExists();
|
||||
GivenSuccessfulScan();
|
||||
@ -82,7 +83,7 @@ public void should_skip_up_to_date_media_info()
|
||||
[Test]
|
||||
public void should_skip_not_yet_date_media_info()
|
||||
{
|
||||
var episodeFiles = Builder<MovieFile>.CreateListOfSize(3)
|
||||
var movieFiles = Builder<MovieFile>.CreateListOfSize(3)
|
||||
.All()
|
||||
.With(v => v.RelativePath = "media.mkv")
|
||||
.TheFirst(1)
|
||||
@ -91,7 +92,7 @@ public void should_skip_not_yet_date_media_info()
|
||||
|
||||
Mocker.GetMock<IMediaFileService>()
|
||||
.Setup(v => v.GetFilesByMovie(1))
|
||||
.Returns(episodeFiles);
|
||||
.Returns(movieFiles);
|
||||
|
||||
GivenFileExists();
|
||||
GivenSuccessfulScan();
|
||||
@ -108,7 +109,7 @@ public void should_skip_not_yet_date_media_info()
|
||||
[Test]
|
||||
public void should_update_outdated_media_info()
|
||||
{
|
||||
var episodeFiles = Builder<MovieFile>.CreateListOfSize(3)
|
||||
var movieFiles = Builder<MovieFile>.CreateListOfSize(3)
|
||||
.All()
|
||||
.With(v => v.RelativePath = "media.mkv")
|
||||
.TheFirst(1)
|
||||
@ -117,7 +118,7 @@ public void should_update_outdated_media_info()
|
||||
|
||||
Mocker.GetMock<IMediaFileService>()
|
||||
.Setup(v => v.GetFilesByMovie(1))
|
||||
.Returns(episodeFiles);
|
||||
.Returns(movieFiles);
|
||||
|
||||
GivenFileExists();
|
||||
GivenSuccessfulScan();
|
||||
@ -134,14 +135,14 @@ public void should_update_outdated_media_info()
|
||||
[Test]
|
||||
public void should_ignore_missing_files()
|
||||
{
|
||||
var episodeFiles = Builder<MovieFile>.CreateListOfSize(2)
|
||||
var movieFiles = Builder<MovieFile>.CreateListOfSize(2)
|
||||
.All()
|
||||
.With(v => v.RelativePath = "media.mkv")
|
||||
.BuildList();
|
||||
|
||||
Mocker.GetMock<IMediaFileService>()
|
||||
.Setup(v => v.GetFilesByMovie(1))
|
||||
.Returns(episodeFiles);
|
||||
.Returns(movieFiles);
|
||||
|
||||
GivenSuccessfulScan();
|
||||
|
||||
@ -157,7 +158,7 @@ public void should_ignore_missing_files()
|
||||
[Test]
|
||||
public void should_continue_after_failure()
|
||||
{
|
||||
var episodeFiles = Builder<MovieFile>.CreateListOfSize(2)
|
||||
var movieFiles = Builder<MovieFile>.CreateListOfSize(2)
|
||||
.All()
|
||||
.With(v => v.RelativePath = "media.mkv")
|
||||
.TheFirst(1)
|
||||
@ -166,7 +167,7 @@ public void should_continue_after_failure()
|
||||
|
||||
Mocker.GetMock<IMediaFileService>()
|
||||
.Setup(v => v.GetFilesByMovie(1))
|
||||
.Returns(episodeFiles);
|
||||
.Returns(movieFiles);
|
||||
|
||||
GivenFileExists();
|
||||
GivenSuccessfulScan();
|
||||
@ -180,5 +181,111 @@ public void should_continue_after_failure()
|
||||
Mocker.GetMock<IMediaFileService>()
|
||||
.Verify(v => v.Update(It.IsAny<MovieFile>()), Times.Exactly(1));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_update_files_if_media_info_disabled()
|
||||
{
|
||||
var movieFiles = Builder<MovieFile>.CreateListOfSize(2)
|
||||
.All()
|
||||
.With(v => v.RelativePath = "media.mkv")
|
||||
.TheFirst(1)
|
||||
.With(v => v.RelativePath = "media2.mkv")
|
||||
.BuildList();
|
||||
|
||||
Mocker.GetMock<IMediaFileService>()
|
||||
.Setup(v => v.GetFilesByMovie(1))
|
||||
.Returns(movieFiles);
|
||||
|
||||
Mocker.GetMock<IConfigService>()
|
||||
.SetupGet(s => s.EnableMediaInfo)
|
||||
.Returns(false);
|
||||
|
||||
GivenFileExists();
|
||||
GivenSuccessfulScan();
|
||||
|
||||
Subject.Handle(new MovieScannedEvent(_movie));
|
||||
|
||||
Mocker.GetMock<IVideoFileInfoReader>()
|
||||
.Verify(v => v.GetMediaInfo(It.IsAny<string>()), Times.Never());
|
||||
|
||||
Mocker.GetMock<IMediaFileService>()
|
||||
.Verify(v => v.Update(It.IsAny<MovieFile>()), Times.Never());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_update_if_media_info_disabled()
|
||||
{
|
||||
var movieFile = Builder<MovieFile>.CreateNew()
|
||||
.With(v => v.RelativePath = "media.mkv")
|
||||
.Build();
|
||||
|
||||
Mocker.GetMock<IConfigService>()
|
||||
.SetupGet(s => s.EnableMediaInfo)
|
||||
.Returns(false);
|
||||
|
||||
GivenFileExists();
|
||||
GivenSuccessfulScan();
|
||||
|
||||
Subject.Update(movieFile, _movie);
|
||||
|
||||
Mocker.GetMock<IVideoFileInfoReader>()
|
||||
.Verify(v => v.GetMediaInfo(It.IsAny<string>()), Times.Never());
|
||||
|
||||
Mocker.GetMock<IMediaFileService>()
|
||||
.Verify(v => v.Update(It.IsAny<MovieFile>()), Times.Never());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_update_media_info()
|
||||
{
|
||||
var movieFile = Builder<MovieFile>.CreateNew()
|
||||
.With(v => v.RelativePath = "media.mkv")
|
||||
.With(e => e.MediaInfo = new MediaInfoModel{SchemaRevision = 3})
|
||||
.Build();
|
||||
|
||||
GivenFileExists();
|
||||
GivenSuccessfulScan();
|
||||
|
||||
Subject.Update(movieFile, _movie);
|
||||
|
||||
Mocker.GetMock<IVideoFileInfoReader>()
|
||||
.Verify(v => v.GetMediaInfo(Path.Combine(_movie.Path, "media.mkv")), Times.Once());
|
||||
|
||||
Mocker.GetMock<IMediaFileService>()
|
||||
.Verify(v => v.Update(movieFile), Times.Once());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_update_media_info_if_new_info_is_null()
|
||||
{
|
||||
var movieFile = Builder<MovieFile>.CreateNew()
|
||||
.With(v => v.RelativePath = "media.mkv")
|
||||
.With(e => e.MediaInfo = new MediaInfoModel{SchemaRevision = 3})
|
||||
.Build();
|
||||
|
||||
GivenFileExists();
|
||||
GivenFailedScan(Path.Combine(_movie.Path, "media.mkv"));
|
||||
|
||||
Subject.Update(movieFile, _movie);
|
||||
|
||||
movieFile.MediaInfo.Should().NotBeNull();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_save_movie_file_if_new_info_is_null()
|
||||
{
|
||||
var movieFile = Builder<MovieFile>.CreateNew()
|
||||
.With(v => v.RelativePath = "media.mkv")
|
||||
.With(e => e.MediaInfo = new MediaInfoModel{SchemaRevision = 3})
|
||||
.Build();
|
||||
|
||||
GivenFileExists();
|
||||
GivenFailedScan(Path.Combine(_movie.Path, "media.mkv"));
|
||||
|
||||
Subject.Update(movieFile, _movie);
|
||||
|
||||
Mocker.GetMock<IMediaFileService>()
|
||||
.Verify(v => v.Update(movieFile), Times.Never());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -40,20 +40,18 @@ public void get_info()
|
||||
|
||||
var info = Subject.GetMediaInfo(path);
|
||||
|
||||
info.VideoCodec.Should().BeNull();
|
||||
info.VideoFormat.Should().Be("AVC");
|
||||
info.VideoCodecID.Should().Be("avc1");
|
||||
info.VideoProfile.Should().Be("Baseline@L2.1");
|
||||
info.VideoCodecLibrary.Should().Be("");
|
||||
info.VideoMultiViewCount.Should().Be(0);
|
||||
info.VideoColourPrimaries.Should().Be("BT.601 NTSC");
|
||||
info.VideoTransferCharacteristics.Should().Be("BT.709");
|
||||
info.AudioFormat.Should().Be("AAC");
|
||||
info.AudioCodecID.Should().BeOneOf("40", "mp4a-40-2");
|
||||
info.AudioProfile.Should().BeOneOf("", "LC");
|
||||
info.AudioCodecLibrary.Should().Be("");
|
||||
info.AudioBitrate.Should().Be(128000);
|
||||
info.AudioChannels.Should().Be(2);
|
||||
info.AudioLanguages.Should().Be("English");
|
||||
info.AudioAdditionalFeatures.Should().BeOneOf("", "LC");
|
||||
info.Height.Should().Be(320);
|
||||
info.RunTime.Seconds.Should().Be(10);
|
||||
info.ScanType.Should().Be("Progressive");
|
||||
@ -61,6 +59,10 @@ public void get_info()
|
||||
info.VideoBitrate.Should().Be(193329);
|
||||
info.VideoFps.Should().Be(24);
|
||||
info.Width.Should().Be(480);
|
||||
info.VideoColourPrimaries.Should().Be("BT.601 NTSC");
|
||||
info.VideoTransferCharacteristics.Should().Be("BT.709");
|
||||
info.AudioAdditionalFeatures.Should().BeOneOf("", "LC");
|
||||
|
||||
}
|
||||
|
||||
[Test]
|
||||
@ -77,20 +79,18 @@ public void get_info_unicode()
|
||||
|
||||
var info = Subject.GetMediaInfo(path);
|
||||
|
||||
info.VideoCodec.Should().BeNull();
|
||||
info.VideoFormat.Should().Be("AVC");
|
||||
info.VideoCodecID.Should().Be("avc1");
|
||||
info.VideoProfile.Should().Be("Baseline@L2.1");
|
||||
info.VideoCodecLibrary.Should().Be("");
|
||||
info.VideoMultiViewCount.Should().Be(0);
|
||||
info.VideoColourPrimaries.Should().Be("BT.601 NTSC");
|
||||
info.VideoTransferCharacteristics.Should().Be("BT.709");
|
||||
info.AudioFormat.Should().Be("AAC");
|
||||
info.AudioCodecID.Should().BeOneOf("40", "mp4a-40-2");
|
||||
info.AudioProfile.Should().BeOneOf("", "LC");
|
||||
info.AudioCodecLibrary.Should().Be("");
|
||||
info.AudioBitrate.Should().Be(128000);
|
||||
info.AudioChannels.Should().Be(2);
|
||||
info.AudioLanguages.Should().Be("English");
|
||||
info.AudioAdditionalFeatures.Should().BeOneOf("", "LC");
|
||||
info.Height.Should().Be(320);
|
||||
info.RunTime.Seconds.Should().Be(10);
|
||||
info.ScanType.Should().Be("Progressive");
|
||||
@ -98,6 +98,9 @@ public void get_info_unicode()
|
||||
info.VideoBitrate.Should().Be(193329);
|
||||
info.VideoFps.Should().Be(24);
|
||||
info.Width.Should().Be(480);
|
||||
info.VideoColourPrimaries.Should().Be("BT.601 NTSC");
|
||||
info.VideoTransferCharacteristics.Should().Be("BT.709");
|
||||
info.AudioAdditionalFeatures.Should().BeOneOf("", "LC");
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -292,6 +292,7 @@
|
||||
<Compile Include="MediaFiles\DownloadedMoviesCommandServiceFixture.cs" />
|
||||
<Compile Include="MediaFiles\DownloadedMoviesImportServiceFixture.cs" />
|
||||
<Compile Include="MediaFiles\EpisodeFileMovingServiceTests\MoveEpisodeFileFixture.cs" />
|
||||
<Compile Include="MediaFiles\MediaInfo\MediaInfoFormatterTests\FormatVideoDynamicRangeFixture.cs" />
|
||||
<Compile Include="MediaFiles\MovieImport\ImportDecisionMakerFixture.cs" />
|
||||
<Compile Include="MediaFiles\MovieImport\SampleServiceFixture.cs" />
|
||||
<Compile Include="MediaFiles\MovieImport\Specifications\FreeSpaceSpecificationFixture.cs" />
|
||||
|
@ -9,6 +9,8 @@
|
||||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
using NzbDrone.Core.Movies;
|
||||
using NzbDrone.Core.MediaFiles.MediaInfo;
|
||||
using Moq;
|
||||
|
||||
namespace NzbDrone.Core.Test.OrganizerTests.FileNameBuilderTests
|
||||
{
|
||||
@ -305,26 +307,6 @@ public void should_format_mediainfo_3d_properly()
|
||||
.Should().Be("South.Park.3D.h264.DTS");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_format_mediainfo_hdr_properly()
|
||||
{
|
||||
_namingConfig.StandardMovieFormat = "{Movie.Title}.{MEDIAINFO.HDR}.{MediaInfo.Simple}";
|
||||
|
||||
_movieFile.MediaInfo = new Core.MediaFiles.MediaInfo.MediaInfoModel()
|
||||
{
|
||||
VideoFormat = "AVC",
|
||||
VideoBitDepth = 10,
|
||||
VideoColourPrimaries = "BT.2020",
|
||||
VideoTransferCharacteristics = "PQ",
|
||||
AudioFormat = "DTS",
|
||||
AudioLanguages = "English",
|
||||
Subtitles = "English/Spanish/Italian"
|
||||
};
|
||||
|
||||
Subject.BuildFileName(_movie, _movieFile)
|
||||
.Should().Be("South.Park.HDR.h264.DTS");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_remove_duplicate_non_word_characters()
|
||||
{
|
||||
@ -506,6 +488,138 @@ public void should_use_existing_casing_for_release_group(string releaseGroup)
|
||||
.Should().Be(releaseGroup);
|
||||
}
|
||||
|
||||
[TestCase("English", "")]
|
||||
[TestCase("English/German", "[EN+DE]")]
|
||||
public void should_format_audio_languages(string audioLanguages, string expected)
|
||||
{
|
||||
_movieFile.ReleaseGroup = null;
|
||||
|
||||
GivenMediaInfoModel(audioLanguages: audioLanguages);
|
||||
|
||||
|
||||
_namingConfig.StandardMovieFormat = "{MediaInfo AudioLanguages}";
|
||||
|
||||
|
||||
Subject.BuildFileName( _movie , _movieFile)
|
||||
.Should().Be(expected);
|
||||
}
|
||||
|
||||
[TestCase("English", "[EN]")]
|
||||
[TestCase("English/German", "[EN+DE]")]
|
||||
public void should_format_audio_languages_all(string audioLanguages, string expected)
|
||||
{
|
||||
_movieFile.ReleaseGroup = null;
|
||||
|
||||
GivenMediaInfoModel(audioLanguages: audioLanguages);
|
||||
|
||||
|
||||
_namingConfig.StandardMovieFormat = "{MediaInfo AudioLanguagesAll}";
|
||||
|
||||
|
||||
Subject.BuildFileName( _movie , _movieFile)
|
||||
.Should().Be(expected);
|
||||
}
|
||||
|
||||
[TestCase(8, "BT.601 NTSC", "BT.709", "South.Park")]
|
||||
[TestCase(10, "BT.2020", "PQ", "South.Park.HDR")]
|
||||
[TestCase(10, "BT.2020", "HLG", "South.Park.HDR")]
|
||||
[TestCase(0, null, null, "South.Park")]
|
||||
public void should_include_hdr_for_mediainfo_videodynamicrange_with_valid_properties(int bitDepth, string colourPrimaries,
|
||||
string transferCharacteristics, string expectedName)
|
||||
{
|
||||
_namingConfig.StandardMovieFormat =
|
||||
"{Movie.Title}.{MediaInfo VideoDynamicRange}";
|
||||
|
||||
GivenMediaInfoModel(videoBitDepth: bitDepth, videoColourPrimaries: colourPrimaries, videoTransferCharacteristics: transferCharacteristics);
|
||||
|
||||
Subject.BuildFileName(_movie, _movieFile)
|
||||
.Should().Be(expectedName);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_update_media_info_if_token_configured_and_revision_is_old()
|
||||
{
|
||||
_namingConfig.StandardMovieFormat =
|
||||
"{Movie.Title}.{MediaInfo VideoDynamicRange}";
|
||||
|
||||
GivenMediaInfoModel(schemaRevision: 3);
|
||||
|
||||
Subject.BuildFileName( _movie, _movieFile);
|
||||
|
||||
Mocker.GetMock<IUpdateMediaInfo>().Verify(v => v.Update(_movieFile, _movie), Times.Once());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_update_media_info_if_no_movie_path_available()
|
||||
{
|
||||
_namingConfig.StandardMovieFormat =
|
||||
"{Movie.Title}.{MediaInfo VideoDynamicRange}";
|
||||
|
||||
GivenMediaInfoModel(schemaRevision: 3);
|
||||
_movie.Path = null;
|
||||
|
||||
Subject.BuildFileName( _movie, _movieFile);
|
||||
|
||||
Mocker.GetMock<IUpdateMediaInfo>().Verify(v => v.Update(_movieFile, _movie), Times.Never());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_update_media_info_if_token_not_configured_and_revision_is_old()
|
||||
{
|
||||
_namingConfig.StandardMovieFormat =
|
||||
"{Movie.Title}";
|
||||
|
||||
GivenMediaInfoModel(schemaRevision: 3);
|
||||
|
||||
Subject.BuildFileName( _movie, _movieFile);
|
||||
|
||||
Mocker.GetMock<IUpdateMediaInfo>().Verify(v => v.Update(_movieFile, _movie), Times.Never());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_update_media_info_if_token_configured_and_revision_is_current()
|
||||
{
|
||||
_namingConfig.StandardMovieFormat =
|
||||
"{Movie.Title}.{MediaInfo VideoDynamicRange}";
|
||||
|
||||
GivenMediaInfoModel(schemaRevision: 5);
|
||||
|
||||
Subject.BuildFileName( _movie, _movieFile);
|
||||
|
||||
Mocker.GetMock<IUpdateMediaInfo>().Verify(v => v.Update(_movieFile, _movie), Times.Never());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_update_media_info_if_token_configured_and_revision_is_newer()
|
||||
{
|
||||
_namingConfig.StandardMovieFormat =
|
||||
"{Movie.Title}.{MediaInfo VideoDynamicRange}";
|
||||
|
||||
GivenMediaInfoModel(schemaRevision: 8);
|
||||
|
||||
Subject.BuildFileName(_movie, _movieFile);
|
||||
|
||||
Mocker.GetMock<IUpdateMediaInfo>().Verify(v => v.Update(_movieFile, _movie), Times.Never());
|
||||
}
|
||||
|
||||
private void GivenMediaInfoModel(string videoCodec = "AVC", string audioCodec = "DTS", int audioChannels = 6, int videoBitDepth = 8,
|
||||
string videoColourPrimaries = "", string videoTransferCharacteristics = "", string audioLanguages = "English",
|
||||
string subtitles = "English/Spanish/Italian", int schemaRevision = 5)
|
||||
{
|
||||
_movieFile.MediaInfo = new MediaInfoModel
|
||||
{
|
||||
VideoCodec = videoCodec,
|
||||
AudioFormat = audioCodec,
|
||||
AudioChannels = audioChannels,
|
||||
AudioLanguages = audioLanguages,
|
||||
Subtitles = subtitles,
|
||||
VideoBitDepth = videoBitDepth,
|
||||
VideoColourPrimaries = videoColourPrimaries,
|
||||
VideoTransferCharacteristics = videoTransferCharacteristics,
|
||||
SchemaRevision = schemaRevision
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,6 @@
|
||||
using NzbDrone.Core.Movies;
|
||||
using NzbDrone.Core.Movies.Events;
|
||||
using NzbDrone.Common;
|
||||
using System;
|
||||
|
||||
namespace NzbDrone.Core.MediaFiles
|
||||
{
|
||||
@ -28,15 +27,13 @@ public class MediaFileService : IMediaFileService, IHandleAsync<MovieDeletedEven
|
||||
{
|
||||
private readonly IEventAggregator _eventAggregator;
|
||||
private readonly IMediaFileRepository _mediaFileRepository;
|
||||
private readonly IMovieService _movieService;
|
||||
private readonly Logger _logger;
|
||||
|
||||
public MediaFileService(IMediaFileRepository mediaFileRepository, IMovieService movieService,
|
||||
public MediaFileService(IMediaFileRepository mediaFileRepository,
|
||||
IEventAggregator eventAggregator, Logger logger)
|
||||
{
|
||||
_mediaFileRepository = mediaFileRepository;
|
||||
_eventAggregator = eventAggregator;
|
||||
_movieService = movieService;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
|
@ -4,13 +4,17 @@
|
||||
using NzbDrone.Core.MediaFiles.Events;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
using NzbDrone.Core.Movies;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NzbDrone.Core.Configuration;
|
||||
|
||||
namespace NzbDrone.Core.MediaFiles.MediaInfo
|
||||
{
|
||||
public class UpdateMediaInfoService : IHandle<MovieScannedEvent>
|
||||
public interface IUpdateMediaInfo
|
||||
{
|
||||
void Update(MovieFile movieFile, Movie movie);
|
||||
}
|
||||
|
||||
public class UpdateMediaInfoService : IHandle<MovieScannedEvent>, IUpdateMediaInfo
|
||||
{
|
||||
private readonly IDiskProvider _diskProvider;
|
||||
private readonly IMediaFileService _mediaFileService;
|
||||
@ -31,28 +35,6 @@ public UpdateMediaInfoService(IDiskProvider diskProvider,
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
private void UpdateMediaInfo(Movie movie, List<MovieFile> mediaFiles)
|
||||
{
|
||||
foreach (var mediaFile in mediaFiles)
|
||||
{
|
||||
var path = Path.Combine(movie.Path, mediaFile.RelativePath);
|
||||
|
||||
if (!_diskProvider.FileExists(path))
|
||||
{
|
||||
_logger.Debug("Can't update MediaInfo because '{0}' does not exist", path);
|
||||
continue;
|
||||
}
|
||||
|
||||
mediaFile.MediaInfo = _videoFileInfoReader.GetMediaInfo(path);
|
||||
|
||||
if (mediaFile.MediaInfo != null)
|
||||
{
|
||||
_mediaFileService.Update(mediaFile);
|
||||
_logger.Debug("Updated MediaInfo for '{0}'", path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Handle(MovieScannedEvent message)
|
||||
{
|
||||
if (!_configService.EnableMediaInfo)
|
||||
@ -62,9 +44,45 @@ public void Handle(MovieScannedEvent message)
|
||||
}
|
||||
|
||||
var allMediaFiles = _mediaFileService.GetFilesByMovie(message.Movie.Id);
|
||||
var filteredMediaFiles = allMediaFiles.Where(c => c.MediaInfo == null || c.MediaInfo.SchemaRevision < VideoFileInfoReader.MINIMUM_MEDIA_INFO_SCHEMA_REVISION).ToList();
|
||||
var filteredMediaFiles = allMediaFiles.Where(c =>
|
||||
c.MediaInfo == null ||
|
||||
c.MediaInfo.SchemaRevision < VideoFileInfoReader.MINIMUM_MEDIA_INFO_SCHEMA_REVISION).ToList();
|
||||
|
||||
UpdateMediaInfo(message.Movie, filteredMediaFiles);
|
||||
foreach (var mediaFile in filteredMediaFiles)
|
||||
{
|
||||
UpdateMediaInfo(mediaFile, message.Movie);
|
||||
}
|
||||
}
|
||||
|
||||
public void Update(MovieFile movieFile, Movie movie)
|
||||
{
|
||||
if (!_configService.EnableMediaInfo)
|
||||
{
|
||||
_logger.Debug("MediaInfo is disabled");
|
||||
return;
|
||||
}
|
||||
|
||||
UpdateMediaInfo(movieFile, movie);
|
||||
}
|
||||
|
||||
private void UpdateMediaInfo(MovieFile movieFile, Movie movie)
|
||||
{
|
||||
var path = Path.Combine(movie.Path, movieFile.RelativePath);
|
||||
|
||||
if (!_diskProvider.FileExists(path))
|
||||
{
|
||||
_logger.Debug("Can't update MediaInfo because '{0}' does not exist", path);
|
||||
return;
|
||||
}
|
||||
|
||||
var updatedMediaInfo = _videoFileInfoReader.GetMediaInfo(path);
|
||||
|
||||
if (updatedMediaInfo != null)
|
||||
{
|
||||
movieFile.MediaInfo = updatedMediaInfo;
|
||||
_mediaFileService.Update(movieFile);
|
||||
_logger.Debug("Updated MediaInfo for '{0}'", path);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,6 @@
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Cache;
|
||||
using NzbDrone.Common.EnsureThat;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
@ -28,8 +27,7 @@ public class FileNameBuilder : IBuildFileNames
|
||||
{
|
||||
private readonly INamingConfigService _namingConfigService;
|
||||
private readonly IQualityDefinitionService _qualityDefinitionService;
|
||||
private readonly ICached<EpisodeFormat[]> _episodeFormatCache;
|
||||
private readonly ICached<AbsoluteEpisodeFormat[]> _absoluteEpisodeFormatCache;
|
||||
private readonly IUpdateMediaInfo _mediaInfoUpdater;
|
||||
private readonly Logger _logger;
|
||||
|
||||
private static readonly Regex TitleRegex = new Regex(@"\{(?<prefix>[- ._\[(]*)(?<token>(?:[a-z0-9]+)(?:(?<separator>[- ._]+)(?:[a-z0-9]+))?)(?::(?<customFormat>[a-z0-9]+))?(?<suffix>[- ._)\]]*)\}",
|
||||
@ -65,14 +63,12 @@ public class FileNameBuilder : IBuildFileNames
|
||||
|
||||
public FileNameBuilder(INamingConfigService namingConfigService,
|
||||
IQualityDefinitionService qualityDefinitionService,
|
||||
ICacheManager cacheManager,
|
||||
IUpdateMediaInfo mediaInfoUpdater,
|
||||
Logger logger)
|
||||
{
|
||||
_namingConfigService = namingConfigService;
|
||||
_qualityDefinitionService = qualityDefinitionService;
|
||||
//_movieFormatCache = cacheManager.GetCache<MovieFormat>(GetType(), "movieFormat");
|
||||
_episodeFormatCache = cacheManager.GetCache<EpisodeFormat[]>(GetType(), "episodeFormat");
|
||||
_absoluteEpisodeFormatCache = cacheManager.GetCache<AbsoluteEpisodeFormat[]>(GetType(), "absoluteEpisodeFormat");
|
||||
_mediaInfoUpdater = mediaInfoUpdater;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
@ -91,6 +87,8 @@ public string BuildFileName(Movie movie, MovieFile movieFile, NamingConfig namin
|
||||
var pattern = namingConfig.StandardMovieFormat;
|
||||
var tokenHandlers = new Dictionary<string, Func<TokenMatch, string>>(FileNameBuilderTokenEqualityComparer.Instance);
|
||||
|
||||
UpdateMediaInfoIfNeeded(pattern, movieFile, movie);
|
||||
|
||||
AddMovieTokens(tokenHandlers, movie);
|
||||
AddReleaseDateTokens(tokenHandlers, movie.Year);
|
||||
AddImdbIdTokens(tokenHandlers, movie.ImdbId);
|
||||
@ -312,34 +310,44 @@ private void AddQualityTokens(Dictionary<string, Func<TokenMatch, string>> token
|
||||
tokenHandlers["{Quality Real}"] = m => qualityReal;
|
||||
}
|
||||
|
||||
private const string MediaInfoVideoDynamicRangeToken = "{MediaInfo VideoDynamicRange}";
|
||||
private static readonly IDictionary<string, int> MinimumMediaInfoSchemaRevisions =
|
||||
new Dictionary<string, int>(FileNameBuilderTokenEqualityComparer.Instance)
|
||||
{
|
||||
{MediaInfoVideoDynamicRangeToken, 5}
|
||||
};
|
||||
|
||||
private void AddMediaInfoTokens(Dictionary<string, Func<TokenMatch, string>> tokenHandlers, MovieFile movieFile)
|
||||
{
|
||||
if (movieFile.MediaInfo == null) return;
|
||||
if (movieFile.MediaInfo == null)
|
||||
{
|
||||
_logger.Trace("Media info is unavailable for {0}", movieFile);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var sceneName = movieFile.GetSceneOrFileName();
|
||||
|
||||
|
||||
var videoCodec = MediaInfoFormatter.FormatVideoCodec(movieFile.MediaInfo, sceneName);
|
||||
var audioCodec = MediaInfoFormatter.FormatAudioCodec(movieFile.MediaInfo, sceneName);
|
||||
var audioChannels = MediaInfoFormatter.FormatAudioChannels(movieFile.MediaInfo);
|
||||
var audioLanguages = movieFile.MediaInfo.AudioLanguages ?? string.Empty;
|
||||
var subtitles = movieFile.MediaInfo.Subtitles ?? string.Empty;
|
||||
|
||||
// Workaround until https://github.com/MediaArea/MediaInfo/issues/299 is fixed and release
|
||||
if (audioCodec.EqualsIgnoreCase("DTS-X"))
|
||||
{
|
||||
audioChannels = audioChannels - 1 + 0.1m;
|
||||
}
|
||||
|
||||
var mediaInfoAudioLanguages = GetLanguagesToken(movieFile.MediaInfo.AudioLanguages);
|
||||
var mediaInfoAudioLanguages = GetLanguagesToken(audioLanguages);
|
||||
if (!mediaInfoAudioLanguages.IsNullOrWhiteSpace())
|
||||
{
|
||||
mediaInfoAudioLanguages = $"[{mediaInfoAudioLanguages}]";
|
||||
}
|
||||
|
||||
var mediaInfoAudioLanguagesAll = mediaInfoAudioLanguages;
|
||||
if (mediaInfoAudioLanguages == "[EN]")
|
||||
{
|
||||
mediaInfoAudioLanguages = string.Empty;
|
||||
}
|
||||
|
||||
var mediaInfoSubtitleLanguages = GetLanguagesToken(movieFile.MediaInfo.Subtitles);
|
||||
var mediaInfoSubtitleLanguages = GetLanguagesToken(subtitles);
|
||||
if (!mediaInfoSubtitleLanguages.IsNullOrWhiteSpace())
|
||||
{
|
||||
mediaInfoSubtitleLanguages = $"[{mediaInfoSubtitleLanguages}]";
|
||||
@ -347,25 +355,11 @@ private void AddMediaInfoTokens(Dictionary<string, Func<TokenMatch, string>> tok
|
||||
|
||||
var videoBitDepth = movieFile.MediaInfo.VideoBitDepth > 0 ? movieFile.MediaInfo.VideoBitDepth.ToString() : string.Empty;
|
||||
var audioChannelsFormatted = audioChannels > 0 ?
|
||||
audioChannels.ToString("F1", CultureInfo.InvariantCulture) :
|
||||
string.Empty;
|
||||
audioChannels.ToString("F1", CultureInfo.InvariantCulture) :
|
||||
string.Empty;
|
||||
|
||||
var mediaInfo3D = movieFile.MediaInfo.VideoMultiViewCount > 1 ? "3D" : string.Empty;
|
||||
|
||||
var videoColourPrimaries = movieFile.MediaInfo.VideoColourPrimaries ?? string.Empty;
|
||||
var videoTransferCharacteristics = movieFile.MediaInfo.VideoTransferCharacteristics ?? string.Empty;
|
||||
var mediaInfoHDR = string.Empty;
|
||||
|
||||
if (movieFile.MediaInfo.VideoBitDepth >= 10 && !videoColourPrimaries.IsNullOrWhiteSpace() && !videoTransferCharacteristics.IsNullOrWhiteSpace())
|
||||
{
|
||||
string[] validTransferFunctions = new string[] { "PQ", "HLG" };
|
||||
|
||||
if (videoColourPrimaries.EqualsIgnoreCase("BT.2020") && validTransferFunctions.Any(videoTransferCharacteristics.Contains))
|
||||
{
|
||||
mediaInfoHDR = "HDR";
|
||||
}
|
||||
}
|
||||
|
||||
tokenHandlers["{MediaInfo Video}"] = m => videoCodec;
|
||||
tokenHandlers["{MediaInfo VideoCodec}"] = m => videoCodec;
|
||||
tokenHandlers["{MediaInfo VideoBitDepth}"] = m => videoBitDepth;
|
||||
@ -377,12 +371,15 @@ private void AddMediaInfoTokens(Dictionary<string, Func<TokenMatch, string>> tok
|
||||
tokenHandlers["{MediaInfo AudioLanguagesAll}"] = m => mediaInfoAudioLanguagesAll;
|
||||
|
||||
tokenHandlers["{MediaInfo SubtitleLanguages}"] = m => mediaInfoSubtitleLanguages;
|
||||
tokenHandlers["{MediaInfo SubtitleLanguagesAll}"] = m => mediaInfoSubtitleLanguages;
|
||||
|
||||
tokenHandlers["{MediaInfo 3D}"] = m => mediaInfo3D;
|
||||
tokenHandlers["{MediaInfo HDR}"] = m => mediaInfoHDR;
|
||||
|
||||
tokenHandlers["{MediaInfo Simple}"] = m => $"{videoCodec} {audioCodec}";
|
||||
tokenHandlers["{MediaInfo Full}"] = m => $"{videoCodec} {audioCodec}{mediaInfoAudioLanguages} {mediaInfoSubtitleLanguages}";
|
||||
|
||||
tokenHandlers[MediaInfoVideoDynamicRangeToken] =
|
||||
m => MediaInfoFormatter.FormatVideoDynamicRange(movieFile.MediaInfo);
|
||||
}
|
||||
|
||||
private string GetLanguagesToken(string mediaInfoLanguages)
|
||||
@ -394,7 +391,7 @@ private string GetLanguagesToken(string mediaInfoLanguages)
|
||||
tokens.Add(item.Trim());
|
||||
}
|
||||
|
||||
var cultures = System.Globalization.CultureInfo.GetCultures(System.Globalization.CultureTypes.NeutralCultures);
|
||||
var cultures = CultureInfo.GetCultures(CultureTypes.NeutralCultures);
|
||||
for (int i = 0; i < tokens.Count; i++)
|
||||
{
|
||||
try
|
||||
@ -412,6 +409,26 @@ private string GetLanguagesToken(string mediaInfoLanguages)
|
||||
return string.Join("+", tokens.Distinct());
|
||||
}
|
||||
|
||||
private void UpdateMediaInfoIfNeeded(string pattern, MovieFile movieFile, Movie movie)
|
||||
{
|
||||
if (movie.Path.IsNullOrWhiteSpace())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var schemaRevision = movieFile.MediaInfo != null ? movieFile.MediaInfo.SchemaRevision : 0;
|
||||
var matches = TitleRegex.Matches(pattern);
|
||||
|
||||
var shouldUpdateMediaInfo = matches.Cast<Match>()
|
||||
.Select(m => MinimumMediaInfoSchemaRevisions.GetValueOrDefault(m.Value, -1))
|
||||
.Any(r => schemaRevision < r);
|
||||
|
||||
if (shouldUpdateMediaInfo)
|
||||
{
|
||||
_mediaInfoUpdater.Update(movieFile, movie);
|
||||
}
|
||||
}
|
||||
|
||||
private string ReplaceTokens(string pattern, Dictionary<string, Func<TokenMatch, string>> tokenHandlers, NamingConfig namingConfig)
|
||||
{
|
||||
return TitleRegex.Replace(pattern, match => ReplaceToken(match, tokenHandlers, namingConfig));
|
||||
|
Loading…
Reference in New Issue
Block a user