diff --git a/build.ps1 b/build.ps1
index 486549865..a84a1de8e 100644
--- a/build.ps1
+++ b/build.ps1
@@ -3,6 +3,7 @@ $outputFolder = '.\_output'
$outputFolderMono = '.\_output_mono'
$testPackageFolder = '.\_tests\'
$testSearchPattern = '*.Test\bin\x86\Release'
+$sourceFolder = '.\src'
Function Build()
{
@@ -84,6 +85,9 @@ Function PackageMono()
get-childitem $outputFolderMono -File -Filter sqlite3.* -Recurse | foreach ($_) {remove-item $_.fullname}
get-childitem $outputFolderMono -File -Filter MediaInfo.* -Recurse | foreach ($_) {remove-item $_.fullname}
+ Write-Host "Adding MediaInfoDotNet.dll.config (for dllmap)"
+ Copy-Item "$sourceFolder\MediaInfoDotNet.dll.config" $outputFolderMono
+
Write-Host Renaming NzbDrone.Console.exe to NzbDrone.exe
get-childitem $outputFolderMono -File -Filter NzbDrone.exe -Recurse | foreach ($_) {remove-item $_.fullname}
Rename-Item "$outputFolderMono\NzbDrone.Console.exe" "NzbDrone.exe"
@@ -103,7 +107,7 @@ Function PackageTests()
{
Write-Host Packaging Tests
- Write-Host "##teamcity[progressStart 'Creating Mono Package']"
+ Write-Host "##teamcity[progressStart 'Creating Test Package']"
if(Test-Path $testPackageFolder)
{
@@ -117,8 +121,8 @@ Function PackageTests()
.\src\.nuget\NuGet.exe install NUnit.Runners -Version 2.6.1 -Output $testPackageFolder
- Copy-Item $outputFolder\*.dll -Destination $testPackageFolder -Force
- Copy-Item $outputFolder\*.pdb -Destination $testPackageFolder -Force
+ Copy-Item $outputFolder\*.dll -Destination $testPackageFolder -Force
+ Copy-Item $outputFolder\*.pdb -Destination $testPackageFolder -Force
Copy-Item .\*.sh -Destination $testPackageFolder -Force
@@ -126,7 +130,10 @@ Function PackageTests()
CleanFolder $testPackageFolder
- Write-Host "##teamcity[progressFinish 'Creating Mono Package']"
+ Write-Host "Adding MediaInfoDotNet.dll.config (for dllmap)"
+ Copy-Item "$sourceFolder\MediaInfoDotNet.dll.config" -Destination $testPackageFolder -Force
+
+ Write-Host "##teamcity[progressFinish 'Creating Test Package']"
}
diff --git a/debian/control b/debian/control
index e7f6a7b11..99d801309 100644
--- a/debian/control
+++ b/debian/control
@@ -8,5 +8,5 @@ Vcs-Browser: https://github.com/NzbDrone/NzbDrone
Package: nzbdrone
Architecture: all
-Depends: libmono-cil-dev (>= 2.10.1)
+Depends: libmono-cil-dev (>= 2.10.1), sqlite3 (>= 3.7), mediainfo (>= 0.7.52)
Description: NZBDrone is a PVR for newsgroup users
diff --git a/src/MediaInfoDotNet.dll.config b/src/MediaInfoDotNet.dll.config
new file mode 100644
index 000000000..3de7bdea3
--- /dev/null
+++ b/src/MediaInfoDotNet.dll.config
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/src/NzbDrone.Core.Test/MediaFiles/EpisodeImport/Specifications/NotSampleSpecificationFixture.cs b/src/NzbDrone.Core.Test/MediaFiles/EpisodeImport/Specifications/NotSampleSpecificationFixture.cs
index b8fe97056..9088e46ee 100644
--- a/src/NzbDrone.Core.Test/MediaFiles/EpisodeImport/Specifications/NotSampleSpecificationFixture.cs
+++ b/src/NzbDrone.Core.Test/MediaFiles/EpisodeImport/Specifications/NotSampleSpecificationFixture.cs
@@ -85,21 +85,8 @@ namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport.Specifications
}
[Test]
- public void should_not_run_runtime_check_on_linux()
+ public void should_use_runtime()
{
- LinuxOnly();
- GivenFileSize(1000.Megabytes());
-
- Subject.IsSatisfiedBy(_localEpisode);
-
- Mocker.GetMock().Verify(v => v.GetRunTime(It.IsAny()), Times.Never());
- }
-
- [Test]
- public void should_run_runtime_check_on_windows()
- {
- WindowsOnly();
-
GivenRuntime(120);
GivenFileSize(1000.Megabytes());
@@ -111,7 +98,6 @@ namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport.Specifications
[Test]
public void should_return_false_if_runtime_is_less_than_minimum()
{
- WindowsOnly();
GivenRuntime(60);
Subject.IsSatisfiedBy(_localEpisode).Should().BeFalse();
@@ -120,32 +106,30 @@ namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport.Specifications
[Test]
public void should_return_true_if_runtime_greater_than_than_minimum()
{
- WindowsOnly();
GivenRuntime(120);
Subject.IsSatisfiedBy(_localEpisode).Should().BeTrue();
}
[Test]
- public void should_return_false_if_file_size_is_under_minimum()
+ public void should_fall_back_to_file_size_if_mediainfo_dll_not_found_acceptable_size()
{
- LinuxOnly();
+ Mocker.GetMock()
+ .Setup(s => s.GetRunTime(It.IsAny()))
+ .Throws();
- GivenRuntime(120);
- GivenFileSize(20.Megabytes());
-
- Subject.IsSatisfiedBy(_localEpisode).Should().BeFalse();
+ GivenFileSize(1000.Megabytes());
+ Subject.IsSatisfiedBy(_localEpisode).Should().BeTrue();
}
[Test]
- public void should_return_false_if_file_size_is_under_minimum_for_larger_limits()
+ public void should_fall_back_to_file_size_if_mediainfo_dll_not_found_undersize()
{
- LinuxOnly();
-
- GivenRuntime(120);
- GivenFileSize(120.Megabytes());
- _localEpisode.Quality = new QualityModel(Quality.Bluray1080p);
+ Mocker.GetMock()
+ .Setup(s => s.GetRunTime(It.IsAny()))
+ .Throws();
+ GivenFileSize(1.Megabytes());
Subject.IsSatisfiedBy(_localEpisode).Should().BeFalse();
}
}
diff --git a/src/NzbDrone.Core.Test/MediaFiles/MediaInfo/VideoFileInfoReaderFixture.cs b/src/NzbDrone.Core.Test/MediaFiles/MediaInfo/VideoFileInfoReaderFixture.cs
index c3267089b..dbf6aba36 100644
--- a/src/NzbDrone.Core.Test/MediaFiles/MediaInfo/VideoFileInfoReaderFixture.cs
+++ b/src/NzbDrone.Core.Test/MediaFiles/MediaInfo/VideoFileInfoReaderFixture.cs
@@ -1,6 +1,8 @@
using System.IO;
using FluentAssertions;
+using Moq;
using NUnit.Framework;
+using NzbDrone.Common;
using NzbDrone.Core.MediaFiles.MediaInfo;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Test.Common.Categories;
@@ -11,6 +13,14 @@ namespace NzbDrone.Core.Test.MediaFiles.MediaInfo
[DiskAccessTest]
public class VideoFileInfoReaderFixture : CoreTest
{
+ [SetUp]
+ public void Setup()
+ {
+ Mocker.GetMock()
+ .Setup(s => s.FileExists(It.IsAny()))
+ .Returns(true);
+ }
+
[Test]
public void get_runtime()
{
diff --git a/src/NzbDrone.Core/MediaFiles/EpisodeImport/Specifications/NotSampleSpecification.cs b/src/NzbDrone.Core/MediaFiles/EpisodeImport/Specifications/NotSampleSpecification.cs
index ccf833ce7..7e2fd7ed6 100644
--- a/src/NzbDrone.Core/MediaFiles/EpisodeImport/Specifications/NotSampleSpecification.cs
+++ b/src/NzbDrone.Core/MediaFiles/EpisodeImport/Specifications/NotSampleSpecification.cs
@@ -61,7 +61,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Specifications
return true;
}
- if (OsInfo.IsWindows)
+ try
{
var runTime = _videoFileInfoReader.GetRunTime(localEpisode.Path);
@@ -76,12 +76,17 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Specifications
_logger.Trace("[{0}] appears to be a sample. Size: {1} Runtime: {2}", localEpisode.Path, localEpisode.Size, runTime);
return false;
}
-
- _logger.Trace("Runtime is over 2 minutes, skipping file size check");
- return true;
}
- return CheckSize(localEpisode);
+ catch (DllNotFoundException)
+ {
+ _logger.Trace("Falling back to file size detection");
+
+ return CheckSize(localEpisode);
+ }
+
+ _logger.Trace("Runtime is over 90 seconds");
+ return true;
}
private bool CheckSize(LocalEpisode localEpisode)
@@ -90,12 +95,14 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Specifications
{
if (localEpisode.Size < SampleSizeLimit * 2)
{
+ _logger.Trace("1080p file is less than sample limit");
return false;
}
}
if (localEpisode.Size < SampleSizeLimit)
{
+ _logger.Trace("File is less than sample limit");
return false;
}
diff --git a/src/NzbDrone.Core/MediaFiles/MediaInfo/MediaInfoModel.cs b/src/NzbDrone.Core/MediaFiles/MediaInfo/MediaInfoModel.cs
index 69e8f4760..c18ec0870 100644
--- a/src/NzbDrone.Core/MediaFiles/MediaInfo/MediaInfoModel.cs
+++ b/src/NzbDrone.Core/MediaFiles/MediaInfo/MediaInfoModel.cs
@@ -1,4 +1,6 @@
-namespace NzbDrone.Core.MediaFiles.MediaInfo
+using System;
+
+namespace NzbDrone.Core.MediaFiles.MediaInfo
{
public class MediaInfoModel
{
@@ -8,7 +10,7 @@
public int Height { get; set; }
public string AudioFormat { get; set; }
public int AudioBitrate { get; set; }
- public int RunTime { get; set; }
+ public TimeSpan RunTime { get; set; }
public int AudioStreamCount { get; set; }
public int AudioChannels { get; set; }
public string AudioProfile { get; set; }
diff --git a/src/NzbDrone.Core/MediaFiles/MediaInfo/VideoFileInfoReader.cs b/src/NzbDrone.Core/MediaFiles/MediaInfo/VideoFileInfoReader.cs
index 2ad10fa14..60cee01a4 100644
--- a/src/NzbDrone.Core/MediaFiles/MediaInfo/VideoFileInfoReader.cs
+++ b/src/NzbDrone.Core/MediaFiles/MediaInfo/VideoFileInfoReader.cs
@@ -30,10 +30,11 @@ namespace NzbDrone.Core.MediaFiles.MediaInfo
if (!_diskProvider.FileExists(filename))
throw new FileNotFoundException("Media file does not exist: " + filename);
- var mediaInfo = new MediaInfoLib.MediaInfo();
+ MediaInfoLib.MediaInfo mediaInfo = null;
try
{
+ mediaInfo = new MediaInfoLib.MediaInfo();
_logger.Trace("Getting media info from {0}", filename);
mediaInfo.Option("ParseSpeed", "0.2");
@@ -56,26 +57,26 @@ namespace NzbDrone.Core.MediaFiles.MediaInfo
Int32.TryParse(mediaInfo.Get(StreamKind.Video, 0, "BitRate"), out videoBitRate);
string aBitRate = mediaInfo.Get(StreamKind.Audio, 0, "BitRate");
- int ABindex = aBitRate.IndexOf(" /");
- if (ABindex > 0)
- aBitRate = aBitRate.Remove(ABindex);
+ int aBindex = aBitRate.IndexOf(" /", StringComparison.InvariantCultureIgnoreCase);
+ if (aBindex > 0)
+ aBitRate = aBitRate.Remove(aBindex);
Int32.TryParse(aBitRate, out audioBitRate);
Int32.TryParse(mediaInfo.Get(StreamKind.Video, 0, "PlayTime"), out runTime);
Int32.TryParse(mediaInfo.Get(StreamKind.Audio, 0, "StreamCount"), out streamCount);
string audioChannelsStr = mediaInfo.Get(StreamKind.Audio, 0, "Channel(s)");
- int ACindex = audioChannelsStr.IndexOf(" /");
- if (ACindex > 0)
- audioChannelsStr = audioChannelsStr.Remove(ACindex);
+ int aCindex = audioChannelsStr.IndexOf(" /", StringComparison.InvariantCultureIgnoreCase);
+ if (aCindex > 0)
+ audioChannelsStr = audioChannelsStr.Remove(aCindex);
string audioLanguages = mediaInfo.Get(StreamKind.General, 0, "Audio_Language_List");
decimal videoFrameRate = Decimal.Parse(mediaInfo.Get(StreamKind.Video, 0, "FrameRate"));
string audioProfile = mediaInfo.Get(StreamKind.Audio, 0, "Format_Profile");
- int APindex = audioProfile.IndexOf(" /");
- if (APindex > 0)
- audioProfile = audioProfile.Remove(APindex);
+ int aPindex = audioProfile.IndexOf(" /", StringComparison.InvariantCultureIgnoreCase);
+ if (aPindex > 0)
+ audioProfile = audioProfile.Remove(aPindex);
Int32.TryParse(audioChannelsStr, out audioChannels);
var mediaInfoModel = new MediaInfoModel
@@ -84,9 +85,10 @@ namespace NzbDrone.Core.MediaFiles.MediaInfo
VideoBitrate = videoBitRate,
Height = height,
Width = width,
+
AudioFormat = mediaInfo.Get(StreamKind.Audio, 0, "Format"),
AudioBitrate = audioBitRate,
- RunTime = (runTime / 1000), //InSeconds
+ RunTime = TimeSpan.FromMilliseconds(runTime),
AudioStreamCount = streamCount,
AudioChannels = audioChannels,
AudioProfile = audioProfile.Trim(),
@@ -100,34 +102,10 @@ namespace NzbDrone.Core.MediaFiles.MediaInfo
return mediaInfoModel;
}
}
- catch (Exception ex)
+ catch (DllNotFoundException ex)
{
- _logger.ErrorException("Unable to parse media info from file: " + filename, ex);
- mediaInfo.Close();
- }
-
- return null;
- }
-
- public TimeSpan GetRunTime(string filename)
- {
- MediaInfoLib.MediaInfo mediaInfo = null;
- try
- {
- mediaInfo = new MediaInfoLib.MediaInfo();
- _logger.Trace("Getting media info from {0}", filename);
-
- mediaInfo.Option("ParseSpeed", "0.2");
- int open = mediaInfo.Open(filename);
-
- if (open != 0)
- {
- int runTime;
- Int32.TryParse(mediaInfo.Get(StreamKind.Video, 0, "PlayTime"), out runTime);
-
- mediaInfo.Close();
- return TimeSpan.FromMilliseconds(runTime);
- }
+ _logger.ErrorException("mediainfo is required but was not found", ex);
+ throw;
}
catch (Exception ex)
{
@@ -141,7 +119,19 @@ namespace NzbDrone.Core.MediaFiles.MediaInfo
}
}
- return new TimeSpan();
+ return null;
+ }
+
+ public TimeSpan GetRunTime(string filename)
+ {
+ var info = GetMediaInfo(filename);
+
+ if (info == null)
+ {
+ return new TimeSpan();
+ }
+
+ return info.RunTime;
}
}
}