mirror of https://github.com/Radarr/Radarr
Integrated MediaInfo wrapper to be able to properly handle Unicode on Linux.
This commit is contained in:
parent
96578ca59b
commit
5cd2d71e6f
|
@ -114,8 +114,8 @@ 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 "Adding NzbDrone.Core.dll.config (for dllmap)"
|
||||
Copy-Item "$sourceFolder\NzbDrone.Core\NzbDrone.Core.dll.config" $outputFolderMono
|
||||
|
||||
Write-Host Renaming NzbDrone.Console.exe to NzbDrone.exe
|
||||
Get-ChildItem $outputFolderMono -File -Filter "NzbDrone.exe*" -Recurse | foreach ($_) {remove-item $_.fullname}
|
||||
|
@ -212,8 +212,8 @@ Function PackageTests()
|
|||
|
||||
CleanFolder $testPackageFolder $true
|
||||
|
||||
Write-Host "Adding MediaInfoDotNet.dll.config (for dllmap)"
|
||||
Copy-Item "$sourceFolder\MediaInfoDotNet.dll.config" -Destination $testPackageFolder -Force
|
||||
Write-Host "Adding NzbDrone.Core.dll.config (for dllmap)"
|
||||
Copy-Item "$sourceFolder\NzbDrone.Core\NzbDrone.Core.dll.config" -Destination $testPackageFolder -Force
|
||||
|
||||
Write-Host "##teamcity[progressFinish 'Creating Test Package']"
|
||||
}
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<dllmap os="osx" dll="MediaInfo.dll" target="libmediainfo.0.dylib"/>
|
||||
<dllmap os="linux" dll="MediaInfo.dll" target="libmediainfo.so.0" />
|
||||
<dllmap os="freebsd" dll="MediaInfo.dll" target="libmediainfo.so.0" />
|
||||
<dllmap os="solaris" dll="MediaInfo.dll" target="libmediainfo.so.0.0.0" />
|
||||
</configuration>
|
|
@ -19,6 +19,10 @@ namespace NzbDrone.Core.Test.MediaFiles.MediaInfo
|
|||
Mocker.GetMock<IDiskProvider>()
|
||||
.Setup(s => s.FileExists(It.IsAny<string>()))
|
||||
.Returns(true);
|
||||
|
||||
Mocker.GetMock<IDiskProvider>()
|
||||
.Setup(s => s.OpenReadStream(It.IsAny<string>()))
|
||||
.Returns<string>(s => new FileStream(s, FileMode.Open, FileAccess.Read));
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -56,7 +60,6 @@ namespace NzbDrone.Core.Test.MediaFiles.MediaInfo
|
|||
}
|
||||
|
||||
[Test]
|
||||
[Ignore]
|
||||
public void get_info_unicode()
|
||||
{
|
||||
var srcPath = Path.Combine(Directory.GetCurrentDirectory(), "Files", "Media", "H264_sample.mp4");
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using MediaInfoLib;
|
||||
using NzbDrone.Core.MediaFiles.MediaInfo;
|
||||
|
||||
namespace NzbDrone.Core.HealthCheck.Checks
|
||||
{
|
||||
|
|
|
@ -0,0 +1,328 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using NzbDrone.Common.EnvironmentInfo;
|
||||
|
||||
namespace NzbDrone.Core.MediaFiles.MediaInfo
|
||||
{
|
||||
public enum StreamKind
|
||||
{
|
||||
General,
|
||||
Video,
|
||||
Audio,
|
||||
Text,
|
||||
Other,
|
||||
Image,
|
||||
Menu,
|
||||
}
|
||||
|
||||
public enum InfoKind
|
||||
{
|
||||
Name,
|
||||
Text,
|
||||
Measure,
|
||||
Options,
|
||||
NameText,
|
||||
MeasureText,
|
||||
Info,
|
||||
HowTo
|
||||
}
|
||||
|
||||
public enum InfoOptions
|
||||
{
|
||||
ShowInInform,
|
||||
Support,
|
||||
ShowInSupported,
|
||||
TypeOfValue
|
||||
}
|
||||
|
||||
public enum InfoFileOptions
|
||||
{
|
||||
FileOption_Nothing = 0x00,
|
||||
FileOption_NoRecursive = 0x01,
|
||||
FileOption_CloseAll = 0x02,
|
||||
FileOption_Max = 0x04
|
||||
};
|
||||
|
||||
|
||||
public class MediaInfo : IDisposable
|
||||
{
|
||||
private IntPtr _handle;
|
||||
|
||||
public bool MustUseAnsi { get; set; }
|
||||
public Encoding Encoding { get; set; }
|
||||
|
||||
public MediaInfo()
|
||||
{
|
||||
_handle = MediaInfo_New();
|
||||
|
||||
InitializeEncoding();
|
||||
}
|
||||
|
||||
~MediaInfo()
|
||||
{
|
||||
MediaInfo_Delete(_handle);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
MediaInfo_Delete(_handle);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
private void InitializeEncoding()
|
||||
{
|
||||
if (Environment.OSVersion.ToString().IndexOf("Windows") != -1)
|
||||
{
|
||||
// Windows guaranteed UCS-2
|
||||
MustUseAnsi = false;
|
||||
Encoding = Encoding.Unicode;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Linux normally UCS-4. As fallback we try UCS-2 and plain Ansi.
|
||||
MustUseAnsi = false;
|
||||
Encoding = Encoding.UTF32;
|
||||
|
||||
if (Option("Info_Version", "").StartsWith("MediaInfoLib"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Encoding = Encoding.Unicode;
|
||||
|
||||
if (Option("Info_Version", "").StartsWith("MediaInfoLib"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
MustUseAnsi = true;
|
||||
Encoding = Encoding.Default;
|
||||
|
||||
if (Option("Info_Version", "").StartsWith("MediaInfoLib"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
throw new NotSupportedException("Unsupported MediaInfoLib encoding");
|
||||
}
|
||||
}
|
||||
|
||||
private IntPtr MakeStringParameter(string value)
|
||||
{
|
||||
var buffer = Encoding.GetBytes(value);
|
||||
|
||||
Array.Resize(ref buffer, buffer.Length + 4);
|
||||
|
||||
var buf = Marshal.AllocHGlobal(buffer.Length);
|
||||
Marshal.Copy(buffer, 0, buf, buffer.Length);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
private string MakeStringResult(IntPtr value)
|
||||
{
|
||||
if (Encoding == Encoding.Unicode)
|
||||
{
|
||||
return Marshal.PtrToStringUni(value);
|
||||
}
|
||||
else if (Encoding == Encoding.UTF32)
|
||||
{
|
||||
int i = 0;
|
||||
for (; i < 1024; i += 4)
|
||||
{
|
||||
var data = Marshal.ReadInt32(value, i);
|
||||
if (data == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
var buffer = new byte[i];
|
||||
Marshal.Copy(value, buffer, 0, i);
|
||||
|
||||
return Encoding.GetString(buffer, 0, i);
|
||||
}
|
||||
else
|
||||
{
|
||||
return Marshal.PtrToStringAnsi(value);
|
||||
}
|
||||
}
|
||||
|
||||
public int Open(string fileName)
|
||||
{
|
||||
var pFileName = MakeStringParameter(fileName);
|
||||
try
|
||||
{
|
||||
if (MustUseAnsi)
|
||||
{
|
||||
return (int)MediaInfoA_Open(_handle, pFileName);
|
||||
}
|
||||
else
|
||||
{
|
||||
return (int)MediaInfo_Open(_handle, pFileName);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
Marshal.FreeHGlobal(pFileName);
|
||||
}
|
||||
}
|
||||
|
||||
public int Open(Stream stream)
|
||||
{
|
||||
var buffer = new byte[64 * 1024];
|
||||
|
||||
var isValid = (int)MediaInfo_Open_Buffer_Init(_handle, stream.Length, 0);
|
||||
if (isValid == 1)
|
||||
{
|
||||
int bufferRead;
|
||||
|
||||
do
|
||||
{
|
||||
bufferRead = stream.Read(buffer, 0, buffer.Length);
|
||||
|
||||
if (MediaInfo_Open_Buffer_Continue(_handle, buffer, (IntPtr)bufferRead) == (IntPtr)0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
var seekPos = MediaInfo_Open_Buffer_Continue_GoTo_Get(_handle);
|
||||
if (seekPos != -1)
|
||||
{
|
||||
seekPos = stream.Seek(seekPos, SeekOrigin.Begin);
|
||||
MediaInfo_Open_Buffer_Init(_handle, stream.Length, seekPos);
|
||||
}
|
||||
} while (bufferRead > 0);
|
||||
|
||||
MediaInfo_Open_Buffer_Finalize(_handle);
|
||||
}
|
||||
|
||||
return isValid;
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
MediaInfo_Close(_handle);
|
||||
}
|
||||
|
||||
public string Get(StreamKind streamKind, int streamNumber, string parameter, InfoKind infoKind = InfoKind.Text, InfoKind searchKind = InfoKind.Name)
|
||||
{
|
||||
var pParameter = MakeStringParameter(parameter);
|
||||
try
|
||||
{
|
||||
if (MustUseAnsi)
|
||||
{
|
||||
return MakeStringResult(MediaInfoA_Get(_handle, (IntPtr)streamKind, (IntPtr)streamNumber, pParameter, (IntPtr)infoKind, (IntPtr)searchKind));
|
||||
}
|
||||
else
|
||||
{
|
||||
return MakeStringResult(MediaInfo_Get(_handle, (IntPtr)streamKind, (IntPtr)streamNumber, pParameter, (IntPtr)infoKind, (IntPtr)searchKind));
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
Marshal.FreeHGlobal(pParameter);
|
||||
}
|
||||
}
|
||||
|
||||
public string Get(StreamKind streamKind, int streamNumber, int parameter, InfoKind infoKind)
|
||||
{
|
||||
if (MustUseAnsi)
|
||||
{
|
||||
return MakeStringResult(MediaInfoA_GetI(_handle, (IntPtr)streamKind, (IntPtr)streamNumber, (IntPtr)parameter, (IntPtr)infoKind));
|
||||
}
|
||||
else
|
||||
{
|
||||
return MakeStringResult(MediaInfo_GetI(_handle, (IntPtr)streamKind, (IntPtr)streamNumber, (IntPtr)parameter, (IntPtr)infoKind));
|
||||
}
|
||||
}
|
||||
|
||||
public String Option(String option, String value)
|
||||
{
|
||||
var pOption = MakeStringParameter(option);
|
||||
var pValue = MakeStringParameter(value);
|
||||
try
|
||||
{
|
||||
if (MustUseAnsi)
|
||||
{
|
||||
return MakeStringResult(MediaInfoA_Option(_handle, pOption, pValue));
|
||||
}
|
||||
else
|
||||
{
|
||||
return MakeStringResult(MediaInfo_Option(_handle, pOption, pValue));
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
Marshal.FreeHGlobal(pOption);
|
||||
Marshal.FreeHGlobal(pValue);
|
||||
}
|
||||
}
|
||||
|
||||
public int State_Get()
|
||||
{
|
||||
return (int)MediaInfo_State_Get(_handle);
|
||||
}
|
||||
|
||||
public int Count_Get(StreamKind streamKind, int streamNumber = -1)
|
||||
{
|
||||
return (int)MediaInfo_Count_Get(_handle, (IntPtr)streamKind, (IntPtr)streamNumber);
|
||||
}
|
||||
|
||||
[DllImport("MediaInfo.dll")]
|
||||
private static extern IntPtr MediaInfo_New();
|
||||
[DllImport("MediaInfo.dll")]
|
||||
private static extern void MediaInfo_Delete(IntPtr handle);
|
||||
[DllImport("MediaInfo.dll")]
|
||||
private static extern IntPtr MediaInfo_Open(IntPtr handle, IntPtr fileName);
|
||||
[DllImport("MediaInfo.dll")]
|
||||
private static extern IntPtr MediaInfo_Open_Buffer_Init(IntPtr handle, Int64 fileSize, Int64 fileOffset);
|
||||
[DllImport("MediaInfo.dll")]
|
||||
private static extern IntPtr MediaInfo_Open_Buffer_Continue(IntPtr handle, byte[] buffer, IntPtr bufferSize);
|
||||
[DllImport("MediaInfo.dll")]
|
||||
private static extern Int64 MediaInfo_Open_Buffer_Continue_GoTo_Get(IntPtr handle);
|
||||
[DllImport("MediaInfo.dll")]
|
||||
private static extern IntPtr MediaInfo_Open_Buffer_Finalize(IntPtr handle);
|
||||
[DllImport("MediaInfo.dll")]
|
||||
private static extern void MediaInfo_Close(IntPtr handle);
|
||||
[DllImport("MediaInfo.dll")]
|
||||
private static extern IntPtr MediaInfo_GetI(IntPtr handle, IntPtr streamKind, IntPtr streamNumber, IntPtr parameter, IntPtr infoKind);
|
||||
[DllImport("MediaInfo.dll")]
|
||||
private static extern IntPtr MediaInfo_Get(IntPtr handle, IntPtr streamKind, IntPtr streamNumber, IntPtr parameter, IntPtr infoKind, IntPtr searchKind);
|
||||
[DllImport("MediaInfo.dll")]
|
||||
private static extern IntPtr MediaInfo_Option(IntPtr handle, IntPtr option, IntPtr value);
|
||||
[DllImport("MediaInfo.dll")]
|
||||
private static extern IntPtr MediaInfo_State_Get(IntPtr handle);
|
||||
[DllImport("MediaInfo.dll")]
|
||||
private static extern IntPtr MediaInfo_Count_Get(IntPtr handle, IntPtr StreamKind, IntPtr streamNumber);
|
||||
|
||||
[DllImport("MediaInfo.dll")]
|
||||
private static extern IntPtr MediaInfoA_New();
|
||||
[DllImport("MediaInfo.dll")]
|
||||
private static extern void MediaInfoA_Delete(IntPtr handle);
|
||||
[DllImport("MediaInfo.dll")]
|
||||
private static extern IntPtr MediaInfoA_Open(IntPtr handle, IntPtr fileName);
|
||||
[DllImport("MediaInfo.dll")]
|
||||
private static extern IntPtr MediaInfoA_Open_Buffer_Init(IntPtr handle, Int64 fileSize, Int64 fileOffset);
|
||||
[DllImport("MediaInfo.dll")]
|
||||
private static extern IntPtr MediaInfoA_Open_Buffer_Continue(IntPtr handle, byte[] buffer, IntPtr bufferSize);
|
||||
[DllImport("MediaInfo.dll")]
|
||||
private static extern Int64 MediaInfoA_Open_Buffer_Continue_GoTo_Get(IntPtr handle);
|
||||
[DllImport("MediaInfo.dll")]
|
||||
private static extern IntPtr MediaInfoA_Open_Buffer_Finalize(IntPtr handle);
|
||||
[DllImport("MediaInfo.dll")]
|
||||
private static extern void MediaInfoA_Close(IntPtr handle);
|
||||
[DllImport("MediaInfo.dll")]
|
||||
private static extern IntPtr MediaInfoA_GetI(IntPtr handle, IntPtr streamKind, IntPtr streamNumber, IntPtr parameter, IntPtr infoKind);
|
||||
[DllImport("MediaInfo.dll")]
|
||||
private static extern IntPtr MediaInfoA_Get(IntPtr handle, IntPtr streamKind, IntPtr streamNumber, IntPtr parameter, IntPtr infoKind, IntPtr searchKind);
|
||||
[DllImport("MediaInfo.dll")]
|
||||
private static extern IntPtr MediaInfoA_Option(IntPtr handle, IntPtr option, IntPtr value);
|
||||
[DllImport("MediaInfo.dll")]
|
||||
private static extern IntPtr MediaInfoA_State_Get(IntPtr handle);
|
||||
[DllImport("MediaInfo.dll")]
|
||||
private static extern IntPtr MediaInfoA_Count_Get(IntPtr handle, IntPtr StreamKind, IntPtr streamNumber);
|
||||
}
|
||||
}
|
|
@ -2,7 +2,6 @@
|
|||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using MediaInfoLib;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Disk;
|
||||
using NzbDrone.Common.EnvironmentInfo;
|
||||
|
@ -33,29 +32,16 @@ namespace NzbDrone.Core.MediaFiles.MediaInfo
|
|||
if (!_diskProvider.FileExists(filename))
|
||||
throw new FileNotFoundException("Media file does not exist: " + filename);
|
||||
|
||||
MediaInfoLib.MediaInfo mediaInfo = null;
|
||||
MediaInfo mediaInfo = null;
|
||||
|
||||
try
|
||||
{
|
||||
mediaInfo = new MediaInfoLib.MediaInfo();
|
||||
mediaInfo = new MediaInfo();
|
||||
_logger.Debug("Getting media info from {0}", filename);
|
||||
|
||||
mediaInfo.Option("ParseSpeed", "0.2");
|
||||
|
||||
int open;
|
||||
if (OsInfo.IsWindows)
|
||||
{
|
||||
open = mediaInfo.Open(filename);
|
||||
}
|
||||
else
|
||||
{
|
||||
mediaInfo.Option("CharSet", "UTF-8");
|
||||
|
||||
// On non-Windows the wrapper uses the ansi library methods, which libmediainfo converts internally to unicode from multibyte (utf8).
|
||||
// To avoid building MediaInfoDotNet ourselves we simply trick the wrapper to send utf8 strings instead of ansi.
|
||||
var utf8filename = Encoding.Default.GetString(Encoding.UTF8.GetBytes(filename));
|
||||
open = mediaInfo.Open(utf8filename);
|
||||
}
|
||||
int open = mediaInfo.Open(_diskProvider.OpenReadStream(filename));
|
||||
|
||||
if (open != 0)
|
||||
{
|
||||
|
|
|
@ -93,9 +93,6 @@
|
|||
<Reference Include="System.Xml" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="MediaInfoDotNet">
|
||||
<HintPath>..\packages\MediaInfoNet.0.3\lib\MediaInfoDotNet.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="NLog">
|
||||
<HintPath>..\packages\NLog.2.1.0\lib\net40\NLog.dll</HintPath>
|
||||
</Reference>
|
||||
|
@ -606,6 +603,7 @@
|
|||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="MediaFiles\MediaFileTableCleanupService.cs" />
|
||||
<Compile Include="MediaFiles\MediaInfo\MediaInfoLib.cs" />
|
||||
<Compile Include="MediaFiles\MediaInfo\MediaInfoModel.cs" />
|
||||
<Compile Include="MediaFiles\MediaInfo\UpdateMediaInfoService.cs" />
|
||||
<Compile Include="MediaFiles\MediaInfo\VideoFileInfoReader.cs" />
|
||||
|
@ -940,6 +938,9 @@
|
|||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="App.config" />
|
||||
<None Include="NzbDrone.Core.dll.config">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="packages.config" />
|
||||
<None Include="Properties\AnalysisRules.ruleset" />
|
||||
</ItemGroup>
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<dllmap os="osx" dll="MediaInfo.dll" target="libmediainfo.0.dylib"/>
|
||||
<dllmap os="linux" dll="MediaInfo.dll" target="libmediainfo.so.0" />
|
||||
<dllmap os="freebsd" dll="MediaInfo.dll" target="libmediainfo.so.0" />
|
||||
<dllmap os="solaris" dll="MediaInfo.dll" target="libmediainfo.so.0.0.0" />
|
||||
</configuration>
|
|
@ -4,7 +4,6 @@
|
|||
<package id="FluentMigrator.Runner" version="1.3.1.0" targetFramework="net40" />
|
||||
<package id="FluentValidation" version="5.5.0.0" targetFramework="net40" />
|
||||
<package id="ImageResizer" version="3.4.3" targetFramework="net40" />
|
||||
<package id="MediaInfoNet" version="0.3" targetFramework="net40" />
|
||||
<package id="Newtonsoft.Json" version="6.0.6" targetFramework="net40" />
|
||||
<package id="NLog" version="2.1.0" targetFramework="net40" />
|
||||
<package id="Prowlin" version="0.9.4456.26422" targetFramework="net40" />
|
||||
|
|
Loading…
Reference in New Issue