dllmap added for MediaInfo.DLL
Fall back to filesize check if mediainfo is not available Ubuntu package depends on sqlite3 and mediainfo New: mediainfo now used on mono to check runtime when available
This commit is contained in:
parent
53cebdee17
commit
9cb220bf2a
15
build.ps1
15
build.ps1
|
@ -3,6 +3,7 @@ $outputFolder = '.\_output'
|
||||||
$outputFolderMono = '.\_output_mono'
|
$outputFolderMono = '.\_output_mono'
|
||||||
$testPackageFolder = '.\_tests\'
|
$testPackageFolder = '.\_tests\'
|
||||||
$testSearchPattern = '*.Test\bin\x86\Release'
|
$testSearchPattern = '*.Test\bin\x86\Release'
|
||||||
|
$sourceFolder = '.\src'
|
||||||
|
|
||||||
Function Build()
|
Function Build()
|
||||||
{
|
{
|
||||||
|
@ -84,6 +85,9 @@ Function PackageMono()
|
||||||
get-childitem $outputFolderMono -File -Filter sqlite3.* -Recurse | foreach ($_) {remove-item $_.fullname}
|
get-childitem $outputFolderMono -File -Filter sqlite3.* -Recurse | foreach ($_) {remove-item $_.fullname}
|
||||||
get-childitem $outputFolderMono -File -Filter MediaInfo.* -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
|
Write-Host Renaming NzbDrone.Console.exe to NzbDrone.exe
|
||||||
get-childitem $outputFolderMono -File -Filter NzbDrone.exe -Recurse | foreach ($_) {remove-item $_.fullname}
|
get-childitem $outputFolderMono -File -Filter NzbDrone.exe -Recurse | foreach ($_) {remove-item $_.fullname}
|
||||||
Rename-Item "$outputFolderMono\NzbDrone.Console.exe" "NzbDrone.exe"
|
Rename-Item "$outputFolderMono\NzbDrone.Console.exe" "NzbDrone.exe"
|
||||||
|
@ -103,7 +107,7 @@ Function PackageTests()
|
||||||
{
|
{
|
||||||
|
|
||||||
Write-Host Packaging Tests
|
Write-Host Packaging Tests
|
||||||
Write-Host "##teamcity[progressStart 'Creating Mono Package']"
|
Write-Host "##teamcity[progressStart 'Creating Test Package']"
|
||||||
|
|
||||||
if(Test-Path $testPackageFolder)
|
if(Test-Path $testPackageFolder)
|
||||||
{
|
{
|
||||||
|
@ -117,8 +121,8 @@ Function PackageTests()
|
||||||
|
|
||||||
.\src\.nuget\NuGet.exe install NUnit.Runners -Version 2.6.1 -Output $testPackageFolder
|
.\src\.nuget\NuGet.exe install NUnit.Runners -Version 2.6.1 -Output $testPackageFolder
|
||||||
|
|
||||||
Copy-Item $outputFolder\*.dll -Destination $testPackageFolder -Force
|
Copy-Item $outputFolder\*.dll -Destination $testPackageFolder -Force
|
||||||
Copy-Item $outputFolder\*.pdb -Destination $testPackageFolder -Force
|
Copy-Item $outputFolder\*.pdb -Destination $testPackageFolder -Force
|
||||||
|
|
||||||
Copy-Item .\*.sh -Destination $testPackageFolder -Force
|
Copy-Item .\*.sh -Destination $testPackageFolder -Force
|
||||||
|
|
||||||
|
@ -126,7 +130,10 @@ Function PackageTests()
|
||||||
|
|
||||||
CleanFolder $testPackageFolder
|
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']"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -8,5 +8,5 @@ Vcs-Browser: https://github.com/NzbDrone/NzbDrone
|
||||||
|
|
||||||
Package: nzbdrone
|
Package: nzbdrone
|
||||||
Architecture: all
|
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
|
Description: NZBDrone is a PVR for newsgroup users
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<configuration>
|
||||||
|
<dllmap os="osx" dll="MediaInfo.dll" target="libmediainfo.dylib"/>
|
||||||
|
<dllmap os="linux" dll="MediaInfo.dll" target="libmediainfo.so.0" />
|
||||||
|
</configuration>
|
|
@ -85,21 +85,8 @@ namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport.Specifications
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void should_not_run_runtime_check_on_linux()
|
public void should_use_runtime()
|
||||||
{
|
{
|
||||||
LinuxOnly();
|
|
||||||
GivenFileSize(1000.Megabytes());
|
|
||||||
|
|
||||||
Subject.IsSatisfiedBy(_localEpisode);
|
|
||||||
|
|
||||||
Mocker.GetMock<IVideoFileInfoReader>().Verify(v => v.GetRunTime(It.IsAny<String>()), Times.Never());
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void should_run_runtime_check_on_windows()
|
|
||||||
{
|
|
||||||
WindowsOnly();
|
|
||||||
|
|
||||||
GivenRuntime(120);
|
GivenRuntime(120);
|
||||||
GivenFileSize(1000.Megabytes());
|
GivenFileSize(1000.Megabytes());
|
||||||
|
|
||||||
|
@ -111,7 +98,6 @@ namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport.Specifications
|
||||||
[Test]
|
[Test]
|
||||||
public void should_return_false_if_runtime_is_less_than_minimum()
|
public void should_return_false_if_runtime_is_less_than_minimum()
|
||||||
{
|
{
|
||||||
WindowsOnly();
|
|
||||||
GivenRuntime(60);
|
GivenRuntime(60);
|
||||||
|
|
||||||
Subject.IsSatisfiedBy(_localEpisode).Should().BeFalse();
|
Subject.IsSatisfiedBy(_localEpisode).Should().BeFalse();
|
||||||
|
@ -120,32 +106,30 @@ namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport.Specifications
|
||||||
[Test]
|
[Test]
|
||||||
public void should_return_true_if_runtime_greater_than_than_minimum()
|
public void should_return_true_if_runtime_greater_than_than_minimum()
|
||||||
{
|
{
|
||||||
WindowsOnly();
|
|
||||||
GivenRuntime(120);
|
GivenRuntime(120);
|
||||||
|
|
||||||
Subject.IsSatisfiedBy(_localEpisode).Should().BeTrue();
|
Subject.IsSatisfiedBy(_localEpisode).Should().BeTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[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<IVideoFileInfoReader>()
|
||||||
|
.Setup(s => s.GetRunTime(It.IsAny<String>()))
|
||||||
|
.Throws<DllNotFoundException>();
|
||||||
|
|
||||||
GivenRuntime(120);
|
GivenFileSize(1000.Megabytes());
|
||||||
GivenFileSize(20.Megabytes());
|
Subject.IsSatisfiedBy(_localEpisode).Should().BeTrue();
|
||||||
|
|
||||||
Subject.IsSatisfiedBy(_localEpisode).Should().BeFalse();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[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();
|
Mocker.GetMock<IVideoFileInfoReader>()
|
||||||
|
.Setup(s => s.GetRunTime(It.IsAny<String>()))
|
||||||
GivenRuntime(120);
|
.Throws<DllNotFoundException>();
|
||||||
GivenFileSize(120.Megabytes());
|
|
||||||
_localEpisode.Quality = new QualityModel(Quality.Bluray1080p);
|
|
||||||
|
|
||||||
|
GivenFileSize(1.Megabytes());
|
||||||
Subject.IsSatisfiedBy(_localEpisode).Should().BeFalse();
|
Subject.IsSatisfiedBy(_localEpisode).Should().BeFalse();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using FluentAssertions;
|
using FluentAssertions;
|
||||||
|
using Moq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
using NzbDrone.Common;
|
||||||
using NzbDrone.Core.MediaFiles.MediaInfo;
|
using NzbDrone.Core.MediaFiles.MediaInfo;
|
||||||
using NzbDrone.Core.Test.Framework;
|
using NzbDrone.Core.Test.Framework;
|
||||||
using NzbDrone.Test.Common.Categories;
|
using NzbDrone.Test.Common.Categories;
|
||||||
|
@ -11,6 +13,14 @@ namespace NzbDrone.Core.Test.MediaFiles.MediaInfo
|
||||||
[DiskAccessTest]
|
[DiskAccessTest]
|
||||||
public class VideoFileInfoReaderFixture : CoreTest<VideoFileInfoReader>
|
public class VideoFileInfoReaderFixture : CoreTest<VideoFileInfoReader>
|
||||||
{
|
{
|
||||||
|
[SetUp]
|
||||||
|
public void Setup()
|
||||||
|
{
|
||||||
|
Mocker.GetMock<IDiskProvider>()
|
||||||
|
.Setup(s => s.FileExists(It.IsAny<string>()))
|
||||||
|
.Returns(true);
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void get_runtime()
|
public void get_runtime()
|
||||||
{
|
{
|
||||||
|
|
|
@ -61,7 +61,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Specifications
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (OsInfo.IsWindows)
|
try
|
||||||
{
|
{
|
||||||
var runTime = _videoFileInfoReader.GetRunTime(localEpisode.Path);
|
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);
|
_logger.Trace("[{0}] appears to be a sample. Size: {1} Runtime: {2}", localEpisode.Path, localEpisode.Size, runTime);
|
||||||
return false;
|
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)
|
private bool CheckSize(LocalEpisode localEpisode)
|
||||||
|
@ -90,12 +95,14 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Specifications
|
||||||
{
|
{
|
||||||
if (localEpisode.Size < SampleSizeLimit * 2)
|
if (localEpisode.Size < SampleSizeLimit * 2)
|
||||||
{
|
{
|
||||||
|
_logger.Trace("1080p file is less than sample limit");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (localEpisode.Size < SampleSizeLimit)
|
if (localEpisode.Size < SampleSizeLimit)
|
||||||
{
|
{
|
||||||
|
_logger.Trace("File is less than sample limit");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
namespace NzbDrone.Core.MediaFiles.MediaInfo
|
using System;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.MediaFiles.MediaInfo
|
||||||
{
|
{
|
||||||
public class MediaInfoModel
|
public class MediaInfoModel
|
||||||
{
|
{
|
||||||
|
@ -8,7 +10,7 @@
|
||||||
public int Height { get; set; }
|
public int Height { get; set; }
|
||||||
public string AudioFormat { get; set; }
|
public string AudioFormat { get; set; }
|
||||||
public int AudioBitrate { get; set; }
|
public int AudioBitrate { get; set; }
|
||||||
public int RunTime { get; set; }
|
public TimeSpan RunTime { get; set; }
|
||||||
public int AudioStreamCount { get; set; }
|
public int AudioStreamCount { get; set; }
|
||||||
public int AudioChannels { get; set; }
|
public int AudioChannels { get; set; }
|
||||||
public string AudioProfile { get; set; }
|
public string AudioProfile { get; set; }
|
||||||
|
|
|
@ -30,10 +30,11 @@ namespace NzbDrone.Core.MediaFiles.MediaInfo
|
||||||
if (!_diskProvider.FileExists(filename))
|
if (!_diskProvider.FileExists(filename))
|
||||||
throw new FileNotFoundException("Media file does not exist: " + filename);
|
throw new FileNotFoundException("Media file does not exist: " + filename);
|
||||||
|
|
||||||
var mediaInfo = new MediaInfoLib.MediaInfo();
|
MediaInfoLib.MediaInfo mediaInfo = null;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
mediaInfo = new MediaInfoLib.MediaInfo();
|
||||||
_logger.Trace("Getting media info from {0}", filename);
|
_logger.Trace("Getting media info from {0}", filename);
|
||||||
|
|
||||||
mediaInfo.Option("ParseSpeed", "0.2");
|
mediaInfo.Option("ParseSpeed", "0.2");
|
||||||
|
@ -56,26 +57,26 @@ namespace NzbDrone.Core.MediaFiles.MediaInfo
|
||||||
Int32.TryParse(mediaInfo.Get(StreamKind.Video, 0, "BitRate"), out videoBitRate);
|
Int32.TryParse(mediaInfo.Get(StreamKind.Video, 0, "BitRate"), out videoBitRate);
|
||||||
|
|
||||||
string aBitRate = mediaInfo.Get(StreamKind.Audio, 0, "BitRate");
|
string aBitRate = mediaInfo.Get(StreamKind.Audio, 0, "BitRate");
|
||||||
int ABindex = aBitRate.IndexOf(" /");
|
int aBindex = aBitRate.IndexOf(" /", StringComparison.InvariantCultureIgnoreCase);
|
||||||
if (ABindex > 0)
|
if (aBindex > 0)
|
||||||
aBitRate = aBitRate.Remove(ABindex);
|
aBitRate = aBitRate.Remove(aBindex);
|
||||||
|
|
||||||
Int32.TryParse(aBitRate, out audioBitRate);
|
Int32.TryParse(aBitRate, out audioBitRate);
|
||||||
Int32.TryParse(mediaInfo.Get(StreamKind.Video, 0, "PlayTime"), out runTime);
|
Int32.TryParse(mediaInfo.Get(StreamKind.Video, 0, "PlayTime"), out runTime);
|
||||||
Int32.TryParse(mediaInfo.Get(StreamKind.Audio, 0, "StreamCount"), out streamCount);
|
Int32.TryParse(mediaInfo.Get(StreamKind.Audio, 0, "StreamCount"), out streamCount);
|
||||||
|
|
||||||
string audioChannelsStr = mediaInfo.Get(StreamKind.Audio, 0, "Channel(s)");
|
string audioChannelsStr = mediaInfo.Get(StreamKind.Audio, 0, "Channel(s)");
|
||||||
int ACindex = audioChannelsStr.IndexOf(" /");
|
int aCindex = audioChannelsStr.IndexOf(" /", StringComparison.InvariantCultureIgnoreCase);
|
||||||
if (ACindex > 0)
|
if (aCindex > 0)
|
||||||
audioChannelsStr = audioChannelsStr.Remove(ACindex);
|
audioChannelsStr = audioChannelsStr.Remove(aCindex);
|
||||||
|
|
||||||
string audioLanguages = mediaInfo.Get(StreamKind.General, 0, "Audio_Language_List");
|
string audioLanguages = mediaInfo.Get(StreamKind.General, 0, "Audio_Language_List");
|
||||||
decimal videoFrameRate = Decimal.Parse(mediaInfo.Get(StreamKind.Video, 0, "FrameRate"));
|
decimal videoFrameRate = Decimal.Parse(mediaInfo.Get(StreamKind.Video, 0, "FrameRate"));
|
||||||
string audioProfile = mediaInfo.Get(StreamKind.Audio, 0, "Format_Profile");
|
string audioProfile = mediaInfo.Get(StreamKind.Audio, 0, "Format_Profile");
|
||||||
|
|
||||||
int APindex = audioProfile.IndexOf(" /");
|
int aPindex = audioProfile.IndexOf(" /", StringComparison.InvariantCultureIgnoreCase);
|
||||||
if (APindex > 0)
|
if (aPindex > 0)
|
||||||
audioProfile = audioProfile.Remove(APindex);
|
audioProfile = audioProfile.Remove(aPindex);
|
||||||
|
|
||||||
Int32.TryParse(audioChannelsStr, out audioChannels);
|
Int32.TryParse(audioChannelsStr, out audioChannels);
|
||||||
var mediaInfoModel = new MediaInfoModel
|
var mediaInfoModel = new MediaInfoModel
|
||||||
|
@ -84,9 +85,10 @@ namespace NzbDrone.Core.MediaFiles.MediaInfo
|
||||||
VideoBitrate = videoBitRate,
|
VideoBitrate = videoBitRate,
|
||||||
Height = height,
|
Height = height,
|
||||||
Width = width,
|
Width = width,
|
||||||
|
|
||||||
AudioFormat = mediaInfo.Get(StreamKind.Audio, 0, "Format"),
|
AudioFormat = mediaInfo.Get(StreamKind.Audio, 0, "Format"),
|
||||||
AudioBitrate = audioBitRate,
|
AudioBitrate = audioBitRate,
|
||||||
RunTime = (runTime / 1000), //InSeconds
|
RunTime = TimeSpan.FromMilliseconds(runTime),
|
||||||
AudioStreamCount = streamCount,
|
AudioStreamCount = streamCount,
|
||||||
AudioChannels = audioChannels,
|
AudioChannels = audioChannels,
|
||||||
AudioProfile = audioProfile.Trim(),
|
AudioProfile = audioProfile.Trim(),
|
||||||
|
@ -100,34 +102,10 @@ namespace NzbDrone.Core.MediaFiles.MediaInfo
|
||||||
return mediaInfoModel;
|
return mediaInfoModel;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (DllNotFoundException ex)
|
||||||
{
|
{
|
||||||
_logger.ErrorException("Unable to parse media info from file: " + filename, ex);
|
_logger.ErrorException("mediainfo is required but was not found", ex);
|
||||||
mediaInfo.Close();
|
throw;
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue