You've already forked Sonarr
							
							
				mirror of
				https://github.com/Sonarr/Sonarr.git
				synced 2025-10-31 00:07:55 +02:00 
			
		
		
		
	Integrated MediaInfo wrapper to be able to properly handle Unicode on Linux.
This commit is contained in:
		| @@ -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 | ||||
| { | ||||
|   | ||||
							
								
								
									
										328
									
								
								src/NzbDrone.Core/MediaFiles/MediaInfo/MediaInfoLib.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										328
									
								
								src/NzbDrone.Core/MediaFiles/MediaInfo/MediaInfoLib.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -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> | ||||
|   | ||||
							
								
								
									
										7
									
								
								src/NzbDrone.Core/NzbDrone.Core.dll.config
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								src/NzbDrone.Core/NzbDrone.Core.dll.config
									
									
									
									
									
										Normal file
									
								
							| @@ -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" /> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user