Răsfoiți Sursa

Merge pull request #2633 from MediaBrowser/beta

Beta
Luke 8 ani în urmă
părinte
comite
1a6ee3d48a
100 a modificat fișierele cu 1413 adăugiri și 1233 ștergeri
  1. 63 16
      Emby.Common.Implementations/IO/ManagedFileSystem.cs
  2. 25 5
      Emby.Common.Implementations/IO/SharpCifsFileSystem.cs
  3. 1 1
      Emby.Common.Implementations/project.json
  4. 1 4
      Emby.Dlna/DlnaManager.cs
  5. 0 6
      Emby.Dlna/Emby.Dlna.csproj
  6. 0 146
      Emby.Dlna/Profiles/BubbleUpnpProfile.cs
  7. 54 8
      Emby.Dlna/Profiles/DefaultProfile.cs
  8. 0 151
      Emby.Dlna/Profiles/KodiProfile.cs
  9. 0 149
      Emby.Dlna/Profiles/VlcProfile.cs
  10. 0 29
      Emby.Dlna/Profiles/Xml/BubbleUPnp.xml
  11. 13 5
      Emby.Dlna/Profiles/Xml/Default.xml
  12. 11 3
      Emby.Dlna/Profiles/Xml/Denon AVR.xml
  13. 2 2
      Emby.Dlna/Profiles/Xml/DirecTV HD-DVR.xml
  14. 2 2
      Emby.Dlna/Profiles/Xml/Dish Hopper-Joey.xml
  15. 0 29
      Emby.Dlna/Profiles/Xml/Kodi.xml
  16. 2 2
      Emby.Dlna/Profiles/Xml/LG Smart TV.xml
  17. 2 2
      Emby.Dlna/Profiles/Xml/Linksys DMA2100.xml
  18. 11 3
      Emby.Dlna/Profiles/Xml/MediaMonkey.xml
  19. 2 2
      Emby.Dlna/Profiles/Xml/Panasonic Viera.xml
  20. 2 2
      Emby.Dlna/Profiles/Xml/Popcorn Hour.xml
  21. 2 2
      Emby.Dlna/Profiles/Xml/Samsung Smart TV.xml
  22. 2 2
      Emby.Dlna/Profiles/Xml/Sharp Smart TV.xml
  23. 2 2
      Emby.Dlna/Profiles/Xml/Sony Blu-ray Player 2013.xml
  24. 2 2
      Emby.Dlna/Profiles/Xml/Sony Blu-ray Player 2014.xml
  25. 2 2
      Emby.Dlna/Profiles/Xml/Sony Blu-ray Player 2015.xml
  26. 2 2
      Emby.Dlna/Profiles/Xml/Sony Blu-ray Player 2016.xml
  27. 2 2
      Emby.Dlna/Profiles/Xml/Sony Blu-ray Player.xml
  28. 2 2
      Emby.Dlna/Profiles/Xml/Sony Bravia (2010).xml
  29. 2 2
      Emby.Dlna/Profiles/Xml/Sony Bravia (2011).xml
  30. 2 2
      Emby.Dlna/Profiles/Xml/Sony Bravia (2012).xml
  31. 2 2
      Emby.Dlna/Profiles/Xml/Sony Bravia (2013).xml
  32. 2 2
      Emby.Dlna/Profiles/Xml/Sony Bravia (2014).xml
  33. 2 2
      Emby.Dlna/Profiles/Xml/Sony PlayStation 3.xml
  34. 2 2
      Emby.Dlna/Profiles/Xml/Sony PlayStation 4.xml
  35. 0 29
      Emby.Dlna/Profiles/Xml/Vlc.xml
  36. 2 2
      Emby.Dlna/Profiles/Xml/WDTV Live.xml
  37. 2 2
      Emby.Dlna/Profiles/Xml/Xbox 360.xml
  38. 2 2
      Emby.Dlna/Profiles/Xml/Xbox One.xml
  39. 11 3
      Emby.Dlna/Profiles/Xml/foobar2000.xml
  40. 5 11
      Emby.Drawing.ImageMagick/ImageMagickEncoder.cs
  41. 7 10
      Emby.Drawing.Net/GDIImageEncoder.cs
  42. 80 0
      Emby.Drawing.Skia/Emby.Drawing.Skia.csproj
  43. 31 0
      Emby.Drawing.Skia/PercentPlayedDrawer.cs
  44. 120 0
      Emby.Drawing.Skia/PlayedIndicatorDrawer.cs
  45. 25 0
      Emby.Drawing.Skia/Properties/AssemblyInfo.cs
  46. 387 0
      Emby.Drawing.Skia/SkiaEncoder.cs
  47. 190 0
      Emby.Drawing.Skia/StripCollageBuilder.cs
  48. 68 0
      Emby.Drawing.Skia/UnplayedCountIndicator.cs
  49. 4 0
      Emby.Drawing.Skia/packages.config
  50. 52 81
      Emby.Drawing/ImageProcessor.cs
  51. 5 0
      Emby.Drawing/NullImageEncoder.cs
  52. 8 11
      Emby.Server.Core/ApplicationHost.cs
  53. 1 1
      Emby.Server.Core/IO/LibraryMonitor.cs
  54. 1 1
      Emby.Server.Core/project.json
  55. 2 2
      Emby.Server.Implementations/Activity/ActivityRepository.cs
  56. 2 2
      Emby.Server.Implementations/AppBase/BaseConfigurationManager.cs
  57. 1 1
      Emby.Server.Implementations/AppBase/ConfigurationHelper.cs
  58. 5 5
      Emby.Server.Implementations/Data/SqliteDisplayPreferencesRepository.cs
  59. 6 6
      Emby.Server.Implementations/Data/SqliteExtensions.cs
  60. 4 4
      Emby.Server.Implementations/Data/SqliteFileOrganizationRepository.cs
  61. 28 28
      Emby.Server.Implementations/Data/SqliteItemRepository.cs
  62. 4 4
      Emby.Server.Implementations/Data/SqliteUserDataRepository.cs
  63. 3 3
      Emby.Server.Implementations/Data/SqliteUserRepository.cs
  64. 1 1
      Emby.Server.Implementations/Devices/DeviceManager.cs
  65. 2 2
      Emby.Server.Implementations/Devices/DeviceRepository.cs
  66. 1 1
      Emby.Server.Implementations/Emby.Server.Implementations.csproj
  67. 2 2
      Emby.Server.Implementations/FFMpeg/FFMpegLoader.cs
  68. 6 3
      Emby.Server.Implementations/HttpServer/HttpListenerHost.cs
  69. 18 28
      Emby.Server.Implementations/HttpServer/HttpResultFactory.cs
  70. 16 4
      Emby.Server.Implementations/HttpServer/LoggerUtils.cs
  71. 5 2
      Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs
  72. 9 0
      Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpResponse.cs
  73. 9 1
      Emby.Server.Implementations/IO/FileRefresher.cs
  74. 1 1
      Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs
  75. 1 0
      Emby.Server.Implementations/Library/LibraryManager.cs
  76. 1 1
      Emby.Server.Implementations/Library/Validators/ArtistsValidator.cs
  77. 1 1
      Emby.Server.Implementations/Library/Validators/GameGenresValidator.cs
  78. 1 1
      Emby.Server.Implementations/Library/Validators/GenresValidator.cs
  79. 1 1
      Emby.Server.Implementations/Library/Validators/MusicGenresValidator.cs
  80. 1 1
      Emby.Server.Implementations/Library/Validators/StudiosValidator.cs
  81. 3 1
      Emby.Server.Implementations/Library/Validators/YearsPostScanTask.cs
  82. 9 9
      Emby.Server.Implementations/Notifications/SqliteNotificationsRepository.cs
  83. 3 3
      Emby.Server.Implementations/Security/AuthenticationRepository.cs
  84. 3 3
      Emby.Server.Implementations/Social/SharingRepository.cs
  85. 12 2
      Emby.Server.Implementations/Updates/InstallationManager.cs
  86. 1 1
      Emby.Server.Implementations/packages.config
  87. 0 2
      Emby.Server.sln
  88. 0 4
      MediaBrowser.Api/MediaBrowser.Api.csproj
  89. 4 1
      MediaBrowser.Api/Playback/BaseStreamingService.cs
  90. 4 8
      MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs
  91. 2 0
      MediaBrowser.Api/Playback/Hls/VideoHlsService.cs
  92. 2 1
      MediaBrowser.Api/Reports/Common/HeaderMetadata.cs
  93. 5 0
      MediaBrowser.Api/Reports/Common/ReportBuilderBase.cs
  94. 10 3
      MediaBrowser.Api/Reports/Data/ReportBuilder.cs
  95. 0 256
      MediaBrowser.Api/Reports/Stat/ReportStatBuilder.cs
  96. 0 33
      MediaBrowser.Api/Reports/Stat/ReportStatGroup.cs
  97. 0 23
      MediaBrowser.Api/Reports/Stat/ReportStatItem.cs
  98. 0 24
      MediaBrowser.Api/Reports/Stat/ReportStatResult.cs
  99. 2 6
      MediaBrowser.Controller/Drawing/IImageEncoder.cs
  100. 2 0
      MediaBrowser.Controller/Drawing/IImageProcessor.cs

+ 63 - 16
Emby.Common.Implementations/IO/ManagedFileSystem.cs

@@ -392,10 +392,27 @@ namespace Emby.Common.Implementations.IO
 
 
             if (_supportsAsyncFileStreams && isAsync)
             if (_supportsAsyncFileStreams && isAsync)
             {
             {
-                return new FileStream(path, GetFileMode(mode), GetFileAccess(access), GetFileShare(share), 262144, true);
+                return GetFileStream(path, mode, access, share, FileOpenOptions.Asynchronous);
             }
             }
 
 
-            return new FileStream(path, GetFileMode(mode), GetFileAccess(access), GetFileShare(share), 262144);
+            return GetFileStream(path, mode, access, share, FileOpenOptions.None);
+        }
+
+        public Stream GetFileStream(string path, FileOpenMode mode, FileAccessMode access, FileShareMode share, FileOpenOptions fileOpenOptions)
+        {
+            if (_sharpCifsFileSystem.IsEnabledForPath(path))
+            {
+                return _sharpCifsFileSystem.GetFileStream(path, mode, access, share);
+            }
+
+            var defaultBufferSize = 4096;
+            return new FileStream(path, GetFileMode(mode), GetFileAccess(access), GetFileShare(share), defaultBufferSize, GetFileOptions(fileOpenOptions));
+        }
+
+        private FileOptions GetFileOptions(FileOpenOptions mode)
+        {
+            var val = (int)mode;
+            return (FileOptions)val;
         }
         }
 
 
         private FileMode GetFileMode(FileOpenMode mode)
         private FileMode GetFileMode(FileOpenMode mode)
@@ -501,6 +518,49 @@ namespace Emby.Common.Implementations.IO
             }
             }
         }
         }
 
 
+        public void SetAttributes(string path, bool isHidden, bool isReadOnly)
+        {
+            if (_sharpCifsFileSystem.IsEnabledForPath(path))
+            {
+                _sharpCifsFileSystem.SetAttributes(path, isHidden, isReadOnly);
+                return;
+            }
+
+            var info = GetFileInfo(path);
+
+            if (!info.Exists)
+            {
+                return;
+            }
+
+            if (info.IsReadOnly == isReadOnly && info.IsHidden == isHidden)
+            {
+                return;
+            }
+
+            var attributes = File.GetAttributes(path);
+
+            if (isReadOnly)
+            {
+                attributes = attributes | FileAttributes.ReadOnly;
+            }
+            else
+            {
+                attributes = RemoveAttribute(attributes, FileAttributes.ReadOnly);
+            }
+
+            if (isHidden)
+            {
+                attributes = attributes | FileAttributes.Hidden;
+            }
+            else
+            {
+                attributes = RemoveAttribute(attributes, FileAttributes.Hidden);
+            }
+
+            File.SetAttributes(path, attributes);
+        }
+
         private static FileAttributes RemoveAttribute(FileAttributes attributes, FileAttributes attributesToRemove)
         private static FileAttributes RemoveAttribute(FileAttributes attributes, FileAttributes attributesToRemove)
         {
         {
             return attributes & ~attributesToRemove;
             return attributes & ~attributesToRemove;
@@ -673,20 +733,7 @@ namespace Emby.Common.Implementations.IO
                 return;
                 return;
             }
             }
 
 
-            var fileInfo = GetFileInfo(path);
-
-            if (fileInfo.Exists)
-            {
-                if (fileInfo.IsHidden)
-                {
-                    SetHidden(path, false);
-                }
-                if (fileInfo.IsReadOnly)
-                {
-                    SetReadOnly(path, false);
-                }
-            }
-
+            SetAttributes(path, false, false);
             File.Delete(path);
             File.Delete(path);
         }
         }
 
 

+ 25 - 5
Emby.Common.Implementations/IO/SharpCifsFileSystem.cs

@@ -53,6 +53,11 @@ namespace Emby.Common.Implementations.IO
             if (separator == '/')
             if (separator == '/')
             {
             {
                 result = result.Replace('\\', '/');
                 result = result.Replace('\\', '/');
+
+                if (result.StartsWith("smb:/", StringComparison.OrdinalIgnoreCase) && !result.StartsWith("smb://", StringComparison.OrdinalIgnoreCase))
+                {
+                    result = result.Replace("smb:/", "smb://");
+                }
             }
             }
 
 
             return result;
             return result;
@@ -161,23 +166,38 @@ namespace Emby.Common.Implementations.IO
         public void SetHidden(string path, bool isHidden)
         public void SetHidden(string path, bool isHidden)
         {
         {
             var file = CreateSmbFile(path);
             var file = CreateSmbFile(path);
+            SetHidden(file, isHidden);
+        }
+
+        public void SetReadOnly(string path, bool isReadOnly)
+        {
+            var file = CreateSmbFile(path);
+            SetReadOnly(file, isReadOnly);
+        }
 
 
+        public void SetAttributes(string path, bool isHidden, bool isReadOnly)
+        {
+            var file = CreateSmbFile(path);
+            SetHidden(file, isHidden);
+            SetReadOnly(file, isReadOnly);
+        }
+
+        private void SetHidden(SmbFile file, bool isHidden)
+        {
             var isCurrentlyHidden = file.IsHidden();
             var isCurrentlyHidden = file.IsHidden();
 
 
             if (isCurrentlyHidden && !isHidden)
             if (isCurrentlyHidden && !isHidden)
             {
             {
-                file.SetAttributes(file.GetAttributes() & ~SmbFile.AttrReadonly);
+                file.SetAttributes(file.GetAttributes() & ~SmbFile.AttrHidden);
             }
             }
             else if (!isCurrentlyHidden && isHidden)
             else if (!isCurrentlyHidden && isHidden)
             {
             {
-                file.SetAttributes(file.GetAttributes() | SmbFile.AttrReadonly);
+                file.SetAttributes(file.GetAttributes() | SmbFile.AttrHidden);
             }
             }
         }
         }
 
 
-        public void SetReadOnly(string path, bool isReadOnly)
+        private void SetReadOnly(SmbFile file, bool isReadOnly)
         {
         {
-            var file = CreateSmbFile(path);
-
             var isCurrentlyReadOnly = !file.CanWrite();
             var isCurrentlyReadOnly = !file.CanWrite();
 
 
             if (isCurrentlyReadOnly && !isReadOnly)
             if (isCurrentlyReadOnly && !isReadOnly)

+ 1 - 1
Emby.Common.Implementations/project.json

@@ -45,7 +45,7 @@
         "System.Net.Requests": "4.3.0",
         "System.Net.Requests": "4.3.0",
         "System.Xml.ReaderWriter": "4.3.0",
         "System.Xml.ReaderWriter": "4.3.0",
         "System.Xml.XmlSerializer": "4.3.0",
         "System.Xml.XmlSerializer": "4.3.0",
-        "System.Net.Http": "4.3.0",
+        "System.Net.Http": "4.3.2",
         "System.Net.Primitives": "4.3.0",
         "System.Net.Primitives": "4.3.0",
         "System.Net.Sockets": "4.3.0",
         "System.Net.Sockets": "4.3.0",
         "System.Net.NetworkInformation": "4.3.0",
         "System.Net.NetworkInformation": "4.3.0",

+ 1 - 4
Emby.Dlna/DlnaManager.cs

@@ -587,10 +587,7 @@ namespace Emby.Dlna
                 new DirectTvProfile(),
                 new DirectTvProfile(),
                 new DishHopperJoeyProfile(),
                 new DishHopperJoeyProfile(),
                 new DefaultProfile(),
                 new DefaultProfile(),
-                new PopcornHourProfile(),
-                new VlcProfile(),
-                new BubbleUpnpProfile(),
-                new KodiProfile(),
+                new PopcornHourProfile()
             };
             };
 
 
             foreach (var item in list)
             foreach (var item in list)

+ 0 - 6
Emby.Dlna/Emby.Dlna.csproj

@@ -79,13 +79,11 @@
     <Compile Include="PlayTo\uParserObject.cs" />
     <Compile Include="PlayTo\uParserObject.cs" />
     <Compile Include="PlayTo\UpnpContainer.cs" />
     <Compile Include="PlayTo\UpnpContainer.cs" />
     <Compile Include="PlayTo\uPnpNamespaces.cs" />
     <Compile Include="PlayTo\uPnpNamespaces.cs" />
-    <Compile Include="Profiles\BubbleUpnpProfile.cs" />
     <Compile Include="Profiles\DefaultProfile.cs" />
     <Compile Include="Profiles\DefaultProfile.cs" />
     <Compile Include="Profiles\DenonAvrProfile.cs" />
     <Compile Include="Profiles\DenonAvrProfile.cs" />
     <Compile Include="Profiles\DirectTvProfile.cs" />
     <Compile Include="Profiles\DirectTvProfile.cs" />
     <Compile Include="Profiles\DishHopperJoeyProfile.cs" />
     <Compile Include="Profiles\DishHopperJoeyProfile.cs" />
     <Compile Include="Profiles\Foobar2000Profile.cs" />
     <Compile Include="Profiles\Foobar2000Profile.cs" />
-    <Compile Include="Profiles\KodiProfile.cs" />
     <Compile Include="Profiles\LgTvProfile.cs" />
     <Compile Include="Profiles\LgTvProfile.cs" />
     <Compile Include="Profiles\LinksysDMA2100Profile.cs" />
     <Compile Include="Profiles\LinksysDMA2100Profile.cs" />
     <Compile Include="Profiles\MediaMonkeyProfile.cs" />
     <Compile Include="Profiles\MediaMonkeyProfile.cs" />
@@ -105,7 +103,6 @@
     <Compile Include="Profiles\SonyBravia2014Profile.cs" />
     <Compile Include="Profiles\SonyBravia2014Profile.cs" />
     <Compile Include="Profiles\SonyPs3Profile.cs" />
     <Compile Include="Profiles\SonyPs3Profile.cs" />
     <Compile Include="Profiles\SonyPs4Profile.cs" />
     <Compile Include="Profiles\SonyPs4Profile.cs" />
-    <Compile Include="Profiles\VlcProfile.cs" />
     <Compile Include="Profiles\WdtvLiveProfile.cs" />
     <Compile Include="Profiles\WdtvLiveProfile.cs" />
     <Compile Include="Profiles\Xbox360Profile.cs" />
     <Compile Include="Profiles\Xbox360Profile.cs" />
     <Compile Include="Profiles\XboxOneProfile.cs" />
     <Compile Include="Profiles\XboxOneProfile.cs" />
@@ -153,13 +150,11 @@
     <EmbeddedResource Include="Profiles\Xml\Sharp Smart TV.xml" />
     <EmbeddedResource Include="Profiles\Xml\Sharp Smart TV.xml" />
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
-    <EmbeddedResource Include="Profiles\Xml\BubbleUPnp.xml" />
     <EmbeddedResource Include="Profiles\Xml\Default.xml" />
     <EmbeddedResource Include="Profiles\Xml\Default.xml" />
     <EmbeddedResource Include="Profiles\Xml\Denon AVR.xml" />
     <EmbeddedResource Include="Profiles\Xml\Denon AVR.xml" />
     <EmbeddedResource Include="Profiles\Xml\DirecTV HD-DVR.xml" />
     <EmbeddedResource Include="Profiles\Xml\DirecTV HD-DVR.xml" />
     <EmbeddedResource Include="Profiles\Xml\Dish Hopper-Joey.xml" />
     <EmbeddedResource Include="Profiles\Xml\Dish Hopper-Joey.xml" />
     <EmbeddedResource Include="Profiles\Xml\foobar2000.xml" />
     <EmbeddedResource Include="Profiles\Xml\foobar2000.xml" />
-    <EmbeddedResource Include="Profiles\Xml\Kodi.xml" />
     <EmbeddedResource Include="Profiles\Xml\LG Smart TV.xml" />
     <EmbeddedResource Include="Profiles\Xml\LG Smart TV.xml" />
     <EmbeddedResource Include="Profiles\Xml\Linksys DMA2100.xml" />
     <EmbeddedResource Include="Profiles\Xml\Linksys DMA2100.xml" />
     <EmbeddedResource Include="Profiles\Xml\MediaMonkey.xml" />
     <EmbeddedResource Include="Profiles\Xml\MediaMonkey.xml" />
@@ -178,7 +173,6 @@
     <EmbeddedResource Include="Profiles\Xml\Sony Bravia %282014%29.xml" />
     <EmbeddedResource Include="Profiles\Xml\Sony Bravia %282014%29.xml" />
     <EmbeddedResource Include="Profiles\Xml\Sony PlayStation 3.xml" />
     <EmbeddedResource Include="Profiles\Xml\Sony PlayStation 3.xml" />
     <EmbeddedResource Include="Profiles\Xml\Sony PlayStation 4.xml" />
     <EmbeddedResource Include="Profiles\Xml\Sony PlayStation 4.xml" />
-    <EmbeddedResource Include="Profiles\Xml\Vlc.xml" />
     <EmbeddedResource Include="Profiles\Xml\WDTV Live.xml" />
     <EmbeddedResource Include="Profiles\Xml\WDTV Live.xml" />
     <EmbeddedResource Include="Profiles\Xml\Xbox 360.xml" />
     <EmbeddedResource Include="Profiles\Xml\Xbox 360.xml" />
     <EmbeddedResource Include="Profiles\Xml\Xbox One.xml" />
     <EmbeddedResource Include="Profiles\Xml\Xbox One.xml" />

+ 0 - 146
Emby.Dlna/Profiles/BubbleUpnpProfile.cs

@@ -1,146 +0,0 @@
-using MediaBrowser.Model.Dlna;
-using System.Xml.Serialization;
-
-namespace Emby.Dlna.Profiles
-{
-    [XmlRoot("Profile")]
-    public class BubbleUpnpProfile : DefaultProfile
-    {
-        public BubbleUpnpProfile()
-        {
-            Name = "BubbleUPnp";
-
-            Identification = new DeviceIdentification
-            {
-                ModelName = "BubbleUPnp",
-
-                Headers = new[]
-                {
-                    new HttpHeaderInfo {Name = "User-Agent", Value = "BubbleUPnp", Match = HeaderMatchType.Substring}
-                }
-            };
-
-            TranscodingProfiles = new[]
-            {
-                new TranscodingProfile
-                {
-                    Container = "mp3",
-                    AudioCodec = "mp3",
-                    Type = DlnaProfileType.Audio
-                },
-
-                new TranscodingProfile
-                {
-                    Container = "ts",
-                    Type = DlnaProfileType.Video,
-                    AudioCodec = "aac",
-                    VideoCodec = "h264"
-                },
-
-                new TranscodingProfile
-                {
-                    Container = "jpeg",
-                    Type = DlnaProfileType.Photo
-                }
-            };
-
-            DirectPlayProfiles = new[]
-            {
-                new DirectPlayProfile
-                {
-                    Container = "",
-                    Type = DlnaProfileType.Video
-                },
-
-                new DirectPlayProfile
-                {
-                    Container = "",
-                    Type = DlnaProfileType.Audio
-                },
-
-                new DirectPlayProfile
-                {
-                    Container = "",
-                    Type = DlnaProfileType.Photo,
-                }
-            };
-
-            ResponseProfiles = new ResponseProfile[] { };
-
-            ContainerProfiles = new ContainerProfile[] { };
-
-            CodecProfiles = new CodecProfile[] { };
-
-            SubtitleProfiles = new[]
-            {
-                new SubtitleProfile
-                {
-                    Format = "srt",
-                    Method = SubtitleDeliveryMethod.External,
-                },
-
-                new SubtitleProfile
-                {
-                    Format = "sub",
-                    Method = SubtitleDeliveryMethod.External,
-                },
-
-                new SubtitleProfile
-                {
-                    Format = "srt",
-                    Method = SubtitleDeliveryMethod.Embed,
-                    DidlMode = "",
-                },
-
-                new SubtitleProfile
-                {
-                    Format = "ass",
-                    Method = SubtitleDeliveryMethod.Embed,
-                    DidlMode = "",
-                },
-
-                new SubtitleProfile
-                {
-                    Format = "ssa",
-                    Method = SubtitleDeliveryMethod.Embed,
-                    DidlMode = "",
-                },
-
-                new SubtitleProfile
-                {
-                    Format = "smi",
-                    Method = SubtitleDeliveryMethod.Embed,
-                    DidlMode = "",
-                },
-
-                new SubtitleProfile
-                {
-                    Format = "dvdsub",
-                    Method = SubtitleDeliveryMethod.Embed,
-                    DidlMode = "",
-                },
-
-                new SubtitleProfile
-                {
-                    Format = "pgs",
-                    Method = SubtitleDeliveryMethod.Embed,
-                    DidlMode = "",
-                },
-
-                new SubtitleProfile
-                {
-                    Format = "pgssub",
-                    Method = SubtitleDeliveryMethod.Embed,
-                    DidlMode = "",
-                },
-
-                new SubtitleProfile
-                {
-                    Format = "sub",
-                    Method = SubtitleDeliveryMethod.Embed,
-                    DidlMode = "",
-                }
-            };
-        }
-    }
-}

+ 54 - 8
Emby.Dlna/Profiles/DefaultProfile.cs

@@ -30,8 +30,8 @@ namespace Emby.Dlna.Profiles
             MaxIconWidth = 48;
             MaxIconWidth = 48;
             MaxIconHeight = 48;
             MaxIconHeight = 48;
 
 
-            MaxStreamingBitrate = 30000000;
-            MaxStaticBitrate = 30000000;
+            MaxStreamingBitrate = 40000000;
+            MaxStaticBitrate = 40000000;
             MusicStreamingTranscodingBitrate = 192000;
             MusicStreamingTranscodingBitrate = 192000;
 
 
             EnableAlbumArtInDidl = false;
             EnableAlbumArtInDidl = false;
@@ -64,15 +64,13 @@ namespace Emby.Dlna.Profiles
             {
             {
                 new DirectPlayProfile
                 new DirectPlayProfile
                 {
                 {
-                    Container = "m4v,ts,mpegts,mkv,avi,mpg,mpeg,mp4,mov",
-                    VideoCodec = "h264",
-                    AudioCodec = "aac,mp3,ac3",
+                    Container = "m4v,mpegts,ts,3gp,mov,xvid,vob,mkv,wmv,asf,ogm,ogv,m2v,avi,mpg,mpeg,mp4,webm,wtv,m2ts,dvr-ms",
                     Type = DlnaProfileType.Video
                     Type = DlnaProfileType.Video
                 },
                 },
 
 
                 new DirectPlayProfile
                 new DirectPlayProfile
                 {
                 {
-                    Container = "mp3,wma,aac,wav,flac",
+                    Container = "aac,mp3,mpa,wav,wma,mp2,ogg,oga,webma,ape,opus,flac",
                     Type = DlnaProfileType.Audio
                     Type = DlnaProfileType.Audio
                 }
                 }
             };
             };
@@ -82,13 +80,61 @@ namespace Emby.Dlna.Profiles
                 new SubtitleProfile
                 new SubtitleProfile
                 {
                 {
                     Format = "srt",
                     Format = "srt",
-                    Method = SubtitleDeliveryMethod.Embed
+                    Method = SubtitleDeliveryMethod.External,
                 },
                 },
 
 
                 new SubtitleProfile
                 new SubtitleProfile
                 {
                 {
-                    Format = "srt",
+                    Format = "sub",
                     Method = SubtitleDeliveryMethod.External,
                     Method = SubtitleDeliveryMethod.External,
+                },
+
+                new SubtitleProfile
+                {
+                    Format = "srt",
+                    Method = SubtitleDeliveryMethod.Embed
+                },
+
+                new SubtitleProfile
+                {
+                    Format = "ass",
+                    Method = SubtitleDeliveryMethod.Embed
+                },
+
+                new SubtitleProfile
+                {
+                    Format = "ssa",
+                    Method = SubtitleDeliveryMethod.Embed
+                },
+
+                new SubtitleProfile
+                {
+                    Format = "smi",
+                    Method = SubtitleDeliveryMethod.Embed
+                },
+
+                new SubtitleProfile
+                {
+                    Format = "dvdsub",
+                    Method = SubtitleDeliveryMethod.Embed
+                },
+
+                new SubtitleProfile
+                {
+                    Format = "pgs",
+                    Method = SubtitleDeliveryMethod.Embed
+                },
+
+                new SubtitleProfile
+                {
+                    Format = "pgssub",
+                    Method = SubtitleDeliveryMethod.Embed
+                },
+
+                new SubtitleProfile
+                {
+                    Format = "sub",
+                    Method = SubtitleDeliveryMethod.Embed
                 }
                 }
             };
             };
 
 

+ 0 - 151
Emby.Dlna/Profiles/KodiProfile.cs

@@ -1,151 +0,0 @@
-using MediaBrowser.Model.Dlna;
-using System.Xml.Serialization;
-
-namespace Emby.Dlna.Profiles
-{
-    [XmlRoot("Profile")]
-    public class KodiProfile : DefaultProfile
-    {
-        public KodiProfile()
-        {
-            Name = "Kodi";
-
-            MaxStreamingBitrate = 100000000;
-            MusicStreamingTranscodingBitrate = 1280000;
-
-            TimelineOffsetSeconds = 5;
-
-            Identification = new DeviceIdentification
-            {
-                ModelName = "Kodi",
-
-                Headers = new[]
-                {
-                    new HttpHeaderInfo {Name = "User-Agent", Value = "Kodi", Match = HeaderMatchType.Substring}
-                }
-            };
-
-            TranscodingProfiles = new[]
-            {
-                new TranscodingProfile
-                {
-                    Container = "mp3",
-                    AudioCodec = "mp3",
-                    Type = DlnaProfileType.Audio
-                },
-
-                new TranscodingProfile
-                {
-                    Container = "ts",
-                    Type = DlnaProfileType.Video,
-                    AudioCodec = "aac",
-                    VideoCodec = "h264"
-                },
-
-                new TranscodingProfile
-                {
-                    Container = "jpeg",
-                    Type = DlnaProfileType.Photo
-                }
-            };
-
-            DirectPlayProfiles = new[]
-            {
-                new DirectPlayProfile
-                {
-                    Container = "",
-                    Type = DlnaProfileType.Video
-                },
-
-                new DirectPlayProfile
-                {
-                    Container = "",
-                    Type = DlnaProfileType.Audio
-                },
-
-                new DirectPlayProfile
-                {
-                    Container = "",
-                    Type = DlnaProfileType.Photo,
-                }
-            };
-
-            ResponseProfiles = new ResponseProfile[] { };
-
-            ContainerProfiles = new ContainerProfile[] { };
-
-            CodecProfiles = new CodecProfile[] { };
-
-            SubtitleProfiles = new[]
-            {
-                new SubtitleProfile
-                {
-                    Format = "srt",
-                    Method = SubtitleDeliveryMethod.External,
-                },
-
-                new SubtitleProfile
-                {
-                    Format = "sub",
-                    Method = SubtitleDeliveryMethod.External,
-                },
-
-                new SubtitleProfile
-                {
-                    Format = "srt",
-                    Method = SubtitleDeliveryMethod.Embed,
-                    DidlMode = "",
-                },
-
-                new SubtitleProfile
-                {
-                    Format = "ass",
-                    Method = SubtitleDeliveryMethod.Embed,
-                    DidlMode = "",
-                },
-
-                new SubtitleProfile
-                {
-                    Format = "ssa",
-                    Method = SubtitleDeliveryMethod.Embed,
-                    DidlMode = "",
-                },
-
-                new SubtitleProfile
-                {
-                    Format = "smi",
-                    Method = SubtitleDeliveryMethod.Embed,
-                    DidlMode = "",
-                },
-
-                new SubtitleProfile
-                {
-                    Format = "dvdsub",
-                    Method = SubtitleDeliveryMethod.Embed,
-                    DidlMode = "",
-                },
-
-                new SubtitleProfile
-                {
-                    Format = "pgs",
-                    Method = SubtitleDeliveryMethod.Embed,
-                    DidlMode = "",
-                },
-
-                new SubtitleProfile
-                {
-                    Format = "pgssub",
-                    Method = SubtitleDeliveryMethod.Embed,
-                    DidlMode = "",
-                },
-
-                new SubtitleProfile
-                {
-                    Format = "sub",
-                    Method = SubtitleDeliveryMethod.Embed,
-                    DidlMode = "",
-                }
-            };
-        }
-    }
-}

+ 0 - 149
Emby.Dlna/Profiles/VlcProfile.cs

@@ -1,149 +0,0 @@
-using MediaBrowser.Model.Dlna;
-using System.Xml.Serialization;
-
-namespace Emby.Dlna.Profiles
-{
-    [XmlRoot("Profile")]
-    public class VlcProfile : DefaultProfile
-    {
-        public VlcProfile()
-        {
-            Name = "Vlc";
-
-
-            TimelineOffsetSeconds = 5;
-
-            Identification = new DeviceIdentification
-            {
-                ModelName = "Vlc",
-
-                Headers = new[]
-                {
-                    new HttpHeaderInfo {Name = "User-Agent", Value = "vlc", Match = HeaderMatchType.Substring}
-                }
-            };
-
-            TranscodingProfiles = new[]
-            {
-                new TranscodingProfile
-                {
-                    Container = "mp3",
-                    AudioCodec = "mp3",
-                    Type = DlnaProfileType.Audio
-                },
-
-                new TranscodingProfile
-                {
-                    Container = "ts",
-                    Type = DlnaProfileType.Video,
-                    AudioCodec = "aac",
-                    VideoCodec = "h264"
-                },
-
-                new TranscodingProfile
-                {
-                    Container = "jpeg",
-                    Type = DlnaProfileType.Photo
-                }
-            };
-
-            DirectPlayProfiles = new[]
-            {
-                new DirectPlayProfile
-                {
-                    Container = "",
-                    Type = DlnaProfileType.Video
-                },
-
-                new DirectPlayProfile
-                {
-                    Container = "",
-                    Type = DlnaProfileType.Audio
-                },
-
-                new DirectPlayProfile
-                {
-                    Container = "",
-                    Type = DlnaProfileType.Photo,
-                }
-            };
-
-            ResponseProfiles = new ResponseProfile[] { };
-
-            ContainerProfiles = new ContainerProfile[] { };
-
-            CodecProfiles = new CodecProfile[] { };
-
-            SubtitleProfiles = new[]
-            {
-                new SubtitleProfile
-                {
-                    Format = "srt",
-                    Method = SubtitleDeliveryMethod.External,
-                },
-
-                new SubtitleProfile
-                {
-                    Format = "sub",
-                    Method = SubtitleDeliveryMethod.External,
-                },
-
-                new SubtitleProfile
-                {
-                    Format = "srt",
-                    Method = SubtitleDeliveryMethod.Embed,
-                    DidlMode = "",
-                },
-
-                new SubtitleProfile
-                {
-                    Format = "ass",
-                    Method = SubtitleDeliveryMethod.Embed,
-                    DidlMode = "",
-                },
-
-                new SubtitleProfile
-                {
-                    Format = "ssa",
-                    Method = SubtitleDeliveryMethod.Embed,
-                    DidlMode = "",
-                },
-
-                new SubtitleProfile
-                {
-                    Format = "smi",
-                    Method = SubtitleDeliveryMethod.Embed,
-                    DidlMode = "",
-                },
-
-                new SubtitleProfile
-                {
-                    Format = "dvdsub",
-                    Method = SubtitleDeliveryMethod.Embed,
-                    DidlMode = "",
-                },
-
-                new SubtitleProfile
-                {
-                    Format = "pgs",
-                    Method = SubtitleDeliveryMethod.Embed,
-                    DidlMode = "",
-                },
-
-                new SubtitleProfile
-                {
-                    Format = "pgssub",
-                    Method = SubtitleDeliveryMethod.Embed,
-                    DidlMode = "",
-                },
-
-                new SubtitleProfile
-                {
-                    Format = "sub",
-                    Method = SubtitleDeliveryMethod.Embed,
-                    DidlMode = "",
-                }
-            };
-        }
-    }
-}

Fișier diff suprimat deoarece este prea mare
+ 0 - 29
Emby.Dlna/Profiles/Xml/BubbleUPnp.xml


+ 13 - 5
Emby.Dlna/Profiles/Xml/Default.xml

@@ -16,8 +16,8 @@
   <MaxAlbumArtHeight>480</MaxAlbumArtHeight>
   <MaxAlbumArtHeight>480</MaxAlbumArtHeight>
   <MaxIconWidth>48</MaxIconWidth>
   <MaxIconWidth>48</MaxIconWidth>
   <MaxIconHeight>48</MaxIconHeight>
   <MaxIconHeight>48</MaxIconHeight>
-  <MaxStreamingBitrate>30000000</MaxStreamingBitrate>
-  <MaxStaticBitrate>30000000</MaxStaticBitrate>
+  <MaxStreamingBitrate>40000000</MaxStreamingBitrate>
+  <MaxStaticBitrate>40000000</MaxStaticBitrate>
   <MusicStreamingTranscodingBitrate>192000</MusicStreamingTranscodingBitrate>
   <MusicStreamingTranscodingBitrate>192000</MusicStreamingTranscodingBitrate>
   <MaxStaticMusicBitrate xsi:nil="true" />
   <MaxStaticMusicBitrate xsi:nil="true" />
   <XDlnaDoc>DMS-1.50</XDlnaDoc>
   <XDlnaDoc>DMS-1.50</XDlnaDoc>
@@ -29,8 +29,8 @@
   <IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
   <IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
   <XmlRootAttributes />
   <XmlRootAttributes />
   <DirectPlayProfiles>
   <DirectPlayProfiles>
-    <DirectPlayProfile container="m4v,ts,mpegts,mkv,avi,mpg,mpeg,mp4,mov" audioCodec="aac,mp3,ac3" videoCodec="h264" type="Video" />
-    <DirectPlayProfile container="mp3,wma,aac,wav,flac" type="Audio" />
+    <DirectPlayProfile container="m4v,mpegts,ts,3gp,mov,xvid,vob,mkv,wmv,asf,ogm,ogv,m2v,avi,mpg,mpeg,mp4,webm,wtv,m2ts,dvr-ms" type="Video" />
+    <DirectPlayProfile container="aac,mp3,mpa,wav,wma,mp2,ogg,oga,webma,ape,opus,flac" type="Audio" />
   </DirectPlayProfiles>
   </DirectPlayProfiles>
   <TranscodingProfiles>
   <TranscodingProfiles>
     <TranscodingProfile container="mp3" type="Audio" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" enableSubtitlesInManifest="false" minSegments="0" segmentLength="0" breakOnNonKeyFrames="false" />
     <TranscodingProfile container="mp3" type="Audio" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" enableSubtitlesInManifest="false" minSegments="0" segmentLength="0" breakOnNonKeyFrames="false" />
@@ -45,7 +45,15 @@
     </ResponseProfile>
     </ResponseProfile>
   </ResponseProfiles>
   </ResponseProfiles>
   <SubtitleProfiles>
   <SubtitleProfiles>
-    <SubtitleProfile format="srt" method="Embed" />
     <SubtitleProfile format="srt" method="External" />
     <SubtitleProfile format="srt" method="External" />
+    <SubtitleProfile format="sub" method="External" />
+    <SubtitleProfile format="srt" method="Embed" />
+    <SubtitleProfile format="ass" method="Embed" />
+    <SubtitleProfile format="ssa" method="Embed" />
+    <SubtitleProfile format="smi" method="Embed" />
+    <SubtitleProfile format="dvdsub" method="Embed" />
+    <SubtitleProfile format="pgs" method="Embed" />
+    <SubtitleProfile format="pgssub" method="Embed" />
+    <SubtitleProfile format="sub" method="Embed" />
   </SubtitleProfiles>
   </SubtitleProfiles>
 </Profile>
 </Profile>

+ 11 - 3
Emby.Dlna/Profiles/Xml/Denon AVR.xml

@@ -21,8 +21,8 @@
   <MaxAlbumArtHeight>480</MaxAlbumArtHeight>
   <MaxAlbumArtHeight>480</MaxAlbumArtHeight>
   <MaxIconWidth>48</MaxIconWidth>
   <MaxIconWidth>48</MaxIconWidth>
   <MaxIconHeight>48</MaxIconHeight>
   <MaxIconHeight>48</MaxIconHeight>
-  <MaxStreamingBitrate>30000000</MaxStreamingBitrate>
-  <MaxStaticBitrate>30000000</MaxStaticBitrate>
+  <MaxStreamingBitrate>40000000</MaxStreamingBitrate>
+  <MaxStaticBitrate>40000000</MaxStaticBitrate>
   <MusicStreamingTranscodingBitrate>192000</MusicStreamingTranscodingBitrate>
   <MusicStreamingTranscodingBitrate>192000</MusicStreamingTranscodingBitrate>
   <MaxStaticMusicBitrate xsi:nil="true" />
   <MaxStaticMusicBitrate xsi:nil="true" />
   <XDlnaDoc>DMS-1.50</XDlnaDoc>
   <XDlnaDoc>DMS-1.50</XDlnaDoc>
@@ -45,7 +45,15 @@
   <CodecProfiles />
   <CodecProfiles />
   <ResponseProfiles />
   <ResponseProfiles />
   <SubtitleProfiles>
   <SubtitleProfiles>
-    <SubtitleProfile format="srt" method="Embed" />
     <SubtitleProfile format="srt" method="External" />
     <SubtitleProfile format="srt" method="External" />
+    <SubtitleProfile format="sub" method="External" />
+    <SubtitleProfile format="srt" method="Embed" />
+    <SubtitleProfile format="ass" method="Embed" />
+    <SubtitleProfile format="ssa" method="Embed" />
+    <SubtitleProfile format="smi" method="Embed" />
+    <SubtitleProfile format="dvdsub" method="Embed" />
+    <SubtitleProfile format="pgs" method="Embed" />
+    <SubtitleProfile format="pgssub" method="Embed" />
+    <SubtitleProfile format="sub" method="Embed" />
   </SubtitleProfiles>
   </SubtitleProfiles>
 </Profile>
 </Profile>

+ 2 - 2
Emby.Dlna/Profiles/Xml/DirecTV HD-DVR.xml

@@ -22,8 +22,8 @@
   <MaxAlbumArtHeight>480</MaxAlbumArtHeight>
   <MaxAlbumArtHeight>480</MaxAlbumArtHeight>
   <MaxIconWidth>48</MaxIconWidth>
   <MaxIconWidth>48</MaxIconWidth>
   <MaxIconHeight>48</MaxIconHeight>
   <MaxIconHeight>48</MaxIconHeight>
-  <MaxStreamingBitrate>30000000</MaxStreamingBitrate>
-  <MaxStaticBitrate>30000000</MaxStaticBitrate>
+  <MaxStreamingBitrate>40000000</MaxStreamingBitrate>
+  <MaxStaticBitrate>40000000</MaxStaticBitrate>
   <MusicStreamingTranscodingBitrate>192000</MusicStreamingTranscodingBitrate>
   <MusicStreamingTranscodingBitrate>192000</MusicStreamingTranscodingBitrate>
   <MaxStaticMusicBitrate xsi:nil="true" />
   <MaxStaticMusicBitrate xsi:nil="true" />
   <XDlnaDoc>DMS-1.50</XDlnaDoc>
   <XDlnaDoc>DMS-1.50</XDlnaDoc>

+ 2 - 2
Emby.Dlna/Profiles/Xml/Dish Hopper-Joey.xml

@@ -23,8 +23,8 @@
   <MaxAlbumArtHeight>480</MaxAlbumArtHeight>
   <MaxAlbumArtHeight>480</MaxAlbumArtHeight>
   <MaxIconWidth>48</MaxIconWidth>
   <MaxIconWidth>48</MaxIconWidth>
   <MaxIconHeight>48</MaxIconHeight>
   <MaxIconHeight>48</MaxIconHeight>
-  <MaxStreamingBitrate>30000000</MaxStreamingBitrate>
-  <MaxStaticBitrate>30000000</MaxStaticBitrate>
+  <MaxStreamingBitrate>40000000</MaxStreamingBitrate>
+  <MaxStaticBitrate>40000000</MaxStaticBitrate>
   <MusicStreamingTranscodingBitrate>192000</MusicStreamingTranscodingBitrate>
   <MusicStreamingTranscodingBitrate>192000</MusicStreamingTranscodingBitrate>
   <MaxStaticMusicBitrate xsi:nil="true" />
   <MaxStaticMusicBitrate xsi:nil="true" />
   <XDlnaDoc>DMS-1.50</XDlnaDoc>
   <XDlnaDoc>DMS-1.50</XDlnaDoc>

Fișier diff suprimat deoarece este prea mare
+ 0 - 29
Emby.Dlna/Profiles/Xml/Kodi.xml


+ 2 - 2
Emby.Dlna/Profiles/Xml/LG Smart TV.xml

@@ -22,8 +22,8 @@
   <MaxAlbumArtHeight>480</MaxAlbumArtHeight>
   <MaxAlbumArtHeight>480</MaxAlbumArtHeight>
   <MaxIconWidth>48</MaxIconWidth>
   <MaxIconWidth>48</MaxIconWidth>
   <MaxIconHeight>48</MaxIconHeight>
   <MaxIconHeight>48</MaxIconHeight>
-  <MaxStreamingBitrate>30000000</MaxStreamingBitrate>
-  <MaxStaticBitrate>30000000</MaxStaticBitrate>
+  <MaxStreamingBitrate>40000000</MaxStreamingBitrate>
+  <MaxStaticBitrate>40000000</MaxStaticBitrate>
   <MusicStreamingTranscodingBitrate>192000</MusicStreamingTranscodingBitrate>
   <MusicStreamingTranscodingBitrate>192000</MusicStreamingTranscodingBitrate>
   <MaxStaticMusicBitrate xsi:nil="true" />
   <MaxStaticMusicBitrate xsi:nil="true" />
   <XDlnaDoc>DMS-1.50</XDlnaDoc>
   <XDlnaDoc>DMS-1.50</XDlnaDoc>

+ 2 - 2
Emby.Dlna/Profiles/Xml/Linksys DMA2100.xml

@@ -20,8 +20,8 @@
   <MaxAlbumArtHeight>480</MaxAlbumArtHeight>
   <MaxAlbumArtHeight>480</MaxAlbumArtHeight>
   <MaxIconWidth>48</MaxIconWidth>
   <MaxIconWidth>48</MaxIconWidth>
   <MaxIconHeight>48</MaxIconHeight>
   <MaxIconHeight>48</MaxIconHeight>
-  <MaxStreamingBitrate>30000000</MaxStreamingBitrate>
-  <MaxStaticBitrate>30000000</MaxStaticBitrate>
+  <MaxStreamingBitrate>40000000</MaxStreamingBitrate>
+  <MaxStaticBitrate>40000000</MaxStaticBitrate>
   <MusicStreamingTranscodingBitrate>192000</MusicStreamingTranscodingBitrate>
   <MusicStreamingTranscodingBitrate>192000</MusicStreamingTranscodingBitrate>
   <MaxStaticMusicBitrate xsi:nil="true" />
   <MaxStaticMusicBitrate xsi:nil="true" />
   <XDlnaDoc>DMS-1.50</XDlnaDoc>
   <XDlnaDoc>DMS-1.50</XDlnaDoc>

+ 11 - 3
Emby.Dlna/Profiles/Xml/MediaMonkey.xml

@@ -22,8 +22,8 @@
   <MaxAlbumArtHeight>480</MaxAlbumArtHeight>
   <MaxAlbumArtHeight>480</MaxAlbumArtHeight>
   <MaxIconWidth>48</MaxIconWidth>
   <MaxIconWidth>48</MaxIconWidth>
   <MaxIconHeight>48</MaxIconHeight>
   <MaxIconHeight>48</MaxIconHeight>
-  <MaxStreamingBitrate>30000000</MaxStreamingBitrate>
-  <MaxStaticBitrate>30000000</MaxStaticBitrate>
+  <MaxStreamingBitrate>40000000</MaxStreamingBitrate>
+  <MaxStaticBitrate>40000000</MaxStaticBitrate>
   <MusicStreamingTranscodingBitrate>192000</MusicStreamingTranscodingBitrate>
   <MusicStreamingTranscodingBitrate>192000</MusicStreamingTranscodingBitrate>
   <MaxStaticMusicBitrate xsi:nil="true" />
   <MaxStaticMusicBitrate xsi:nil="true" />
   <XDlnaDoc>DMS-1.50</XDlnaDoc>
   <XDlnaDoc>DMS-1.50</XDlnaDoc>
@@ -51,7 +51,15 @@
   <CodecProfiles />
   <CodecProfiles />
   <ResponseProfiles />
   <ResponseProfiles />
   <SubtitleProfiles>
   <SubtitleProfiles>
-    <SubtitleProfile format="srt" method="Embed" />
     <SubtitleProfile format="srt" method="External" />
     <SubtitleProfile format="srt" method="External" />
+    <SubtitleProfile format="sub" method="External" />
+    <SubtitleProfile format="srt" method="Embed" />
+    <SubtitleProfile format="ass" method="Embed" />
+    <SubtitleProfile format="ssa" method="Embed" />
+    <SubtitleProfile format="smi" method="Embed" />
+    <SubtitleProfile format="dvdsub" method="Embed" />
+    <SubtitleProfile format="pgs" method="Embed" />
+    <SubtitleProfile format="pgssub" method="Embed" />
+    <SubtitleProfile format="sub" method="Embed" />
   </SubtitleProfiles>
   </SubtitleProfiles>
 </Profile>
 </Profile>

+ 2 - 2
Emby.Dlna/Profiles/Xml/Panasonic Viera.xml

@@ -23,8 +23,8 @@
   <MaxAlbumArtHeight>480</MaxAlbumArtHeight>
   <MaxAlbumArtHeight>480</MaxAlbumArtHeight>
   <MaxIconWidth>48</MaxIconWidth>
   <MaxIconWidth>48</MaxIconWidth>
   <MaxIconHeight>48</MaxIconHeight>
   <MaxIconHeight>48</MaxIconHeight>
-  <MaxStreamingBitrate>30000000</MaxStreamingBitrate>
-  <MaxStaticBitrate>30000000</MaxStaticBitrate>
+  <MaxStreamingBitrate>40000000</MaxStreamingBitrate>
+  <MaxStaticBitrate>40000000</MaxStaticBitrate>
   <MusicStreamingTranscodingBitrate>192000</MusicStreamingTranscodingBitrate>
   <MusicStreamingTranscodingBitrate>192000</MusicStreamingTranscodingBitrate>
   <MaxStaticMusicBitrate xsi:nil="true" />
   <MaxStaticMusicBitrate xsi:nil="true" />
   <XDlnaDoc>DMS-1.50</XDlnaDoc>
   <XDlnaDoc>DMS-1.50</XDlnaDoc>

+ 2 - 2
Emby.Dlna/Profiles/Xml/Popcorn Hour.xml

@@ -16,8 +16,8 @@
   <MaxAlbumArtHeight>480</MaxAlbumArtHeight>
   <MaxAlbumArtHeight>480</MaxAlbumArtHeight>
   <MaxIconWidth>48</MaxIconWidth>
   <MaxIconWidth>48</MaxIconWidth>
   <MaxIconHeight>48</MaxIconHeight>
   <MaxIconHeight>48</MaxIconHeight>
-  <MaxStreamingBitrate>30000000</MaxStreamingBitrate>
-  <MaxStaticBitrate>30000000</MaxStaticBitrate>
+  <MaxStreamingBitrate>40000000</MaxStreamingBitrate>
+  <MaxStaticBitrate>40000000</MaxStaticBitrate>
   <MusicStreamingTranscodingBitrate>192000</MusicStreamingTranscodingBitrate>
   <MusicStreamingTranscodingBitrate>192000</MusicStreamingTranscodingBitrate>
   <MaxStaticMusicBitrate xsi:nil="true" />
   <MaxStaticMusicBitrate xsi:nil="true" />
   <XDlnaDoc>DMS-1.50</XDlnaDoc>
   <XDlnaDoc>DMS-1.50</XDlnaDoc>

+ 2 - 2
Emby.Dlna/Profiles/Xml/Samsung Smart TV.xml

@@ -22,8 +22,8 @@
   <MaxAlbumArtHeight>480</MaxAlbumArtHeight>
   <MaxAlbumArtHeight>480</MaxAlbumArtHeight>
   <MaxIconWidth>48</MaxIconWidth>
   <MaxIconWidth>48</MaxIconWidth>
   <MaxIconHeight>48</MaxIconHeight>
   <MaxIconHeight>48</MaxIconHeight>
-  <MaxStreamingBitrate>30000000</MaxStreamingBitrate>
-  <MaxStaticBitrate>30000000</MaxStaticBitrate>
+  <MaxStreamingBitrate>40000000</MaxStreamingBitrate>
+  <MaxStaticBitrate>40000000</MaxStaticBitrate>
   <MusicStreamingTranscodingBitrate>192000</MusicStreamingTranscodingBitrate>
   <MusicStreamingTranscodingBitrate>192000</MusicStreamingTranscodingBitrate>
   <MaxStaticMusicBitrate xsi:nil="true" />
   <MaxStaticMusicBitrate xsi:nil="true" />
   <XDlnaDoc>DMS-1.50</XDlnaDoc>
   <XDlnaDoc>DMS-1.50</XDlnaDoc>

+ 2 - 2
Emby.Dlna/Profiles/Xml/Sharp Smart TV.xml

@@ -22,8 +22,8 @@
   <MaxAlbumArtHeight>480</MaxAlbumArtHeight>
   <MaxAlbumArtHeight>480</MaxAlbumArtHeight>
   <MaxIconWidth>48</MaxIconWidth>
   <MaxIconWidth>48</MaxIconWidth>
   <MaxIconHeight>48</MaxIconHeight>
   <MaxIconHeight>48</MaxIconHeight>
-  <MaxStreamingBitrate>30000000</MaxStreamingBitrate>
-  <MaxStaticBitrate>30000000</MaxStaticBitrate>
+  <MaxStreamingBitrate>40000000</MaxStreamingBitrate>
+  <MaxStaticBitrate>40000000</MaxStaticBitrate>
   <MusicStreamingTranscodingBitrate>192000</MusicStreamingTranscodingBitrate>
   <MusicStreamingTranscodingBitrate>192000</MusicStreamingTranscodingBitrate>
   <MaxStaticMusicBitrate xsi:nil="true" />
   <MaxStaticMusicBitrate xsi:nil="true" />
   <XDlnaDoc>DMS-1.50</XDlnaDoc>
   <XDlnaDoc>DMS-1.50</XDlnaDoc>

+ 2 - 2
Emby.Dlna/Profiles/Xml/Sony Blu-ray Player 2013.xml

@@ -26,8 +26,8 @@
   <MaxAlbumArtHeight>480</MaxAlbumArtHeight>
   <MaxAlbumArtHeight>480</MaxAlbumArtHeight>
   <MaxIconWidth>48</MaxIconWidth>
   <MaxIconWidth>48</MaxIconWidth>
   <MaxIconHeight>48</MaxIconHeight>
   <MaxIconHeight>48</MaxIconHeight>
-  <MaxStreamingBitrate>30000000</MaxStreamingBitrate>
-  <MaxStaticBitrate>30000000</MaxStaticBitrate>
+  <MaxStreamingBitrate>40000000</MaxStreamingBitrate>
+  <MaxStaticBitrate>40000000</MaxStaticBitrate>
   <MusicStreamingTranscodingBitrate>192000</MusicStreamingTranscodingBitrate>
   <MusicStreamingTranscodingBitrate>192000</MusicStreamingTranscodingBitrate>
   <MaxStaticMusicBitrate xsi:nil="true" />
   <MaxStaticMusicBitrate xsi:nil="true" />
   <XDlnaDoc>DMS-1.50</XDlnaDoc>
   <XDlnaDoc>DMS-1.50</XDlnaDoc>

+ 2 - 2
Emby.Dlna/Profiles/Xml/Sony Blu-ray Player 2014.xml

@@ -26,8 +26,8 @@
   <MaxAlbumArtHeight>480</MaxAlbumArtHeight>
   <MaxAlbumArtHeight>480</MaxAlbumArtHeight>
   <MaxIconWidth>48</MaxIconWidth>
   <MaxIconWidth>48</MaxIconWidth>
   <MaxIconHeight>48</MaxIconHeight>
   <MaxIconHeight>48</MaxIconHeight>
-  <MaxStreamingBitrate>30000000</MaxStreamingBitrate>
-  <MaxStaticBitrate>30000000</MaxStaticBitrate>
+  <MaxStreamingBitrate>40000000</MaxStreamingBitrate>
+  <MaxStaticBitrate>40000000</MaxStaticBitrate>
   <MusicStreamingTranscodingBitrate>192000</MusicStreamingTranscodingBitrate>
   <MusicStreamingTranscodingBitrate>192000</MusicStreamingTranscodingBitrate>
   <MaxStaticMusicBitrate xsi:nil="true" />
   <MaxStaticMusicBitrate xsi:nil="true" />
   <XDlnaDoc>DMS-1.50</XDlnaDoc>
   <XDlnaDoc>DMS-1.50</XDlnaDoc>

+ 2 - 2
Emby.Dlna/Profiles/Xml/Sony Blu-ray Player 2015.xml

@@ -24,8 +24,8 @@
   <MaxAlbumArtHeight>480</MaxAlbumArtHeight>
   <MaxAlbumArtHeight>480</MaxAlbumArtHeight>
   <MaxIconWidth>48</MaxIconWidth>
   <MaxIconWidth>48</MaxIconWidth>
   <MaxIconHeight>48</MaxIconHeight>
   <MaxIconHeight>48</MaxIconHeight>
-  <MaxStreamingBitrate>30000000</MaxStreamingBitrate>
-  <MaxStaticBitrate>30000000</MaxStaticBitrate>
+  <MaxStreamingBitrate>40000000</MaxStreamingBitrate>
+  <MaxStaticBitrate>40000000</MaxStaticBitrate>
   <MusicStreamingTranscodingBitrate>192000</MusicStreamingTranscodingBitrate>
   <MusicStreamingTranscodingBitrate>192000</MusicStreamingTranscodingBitrate>
   <MaxStaticMusicBitrate xsi:nil="true" />
   <MaxStaticMusicBitrate xsi:nil="true" />
   <XDlnaDoc>DMS-1.50</XDlnaDoc>
   <XDlnaDoc>DMS-1.50</XDlnaDoc>

+ 2 - 2
Emby.Dlna/Profiles/Xml/Sony Blu-ray Player 2016.xml

@@ -24,8 +24,8 @@
   <MaxAlbumArtHeight>480</MaxAlbumArtHeight>
   <MaxAlbumArtHeight>480</MaxAlbumArtHeight>
   <MaxIconWidth>48</MaxIconWidth>
   <MaxIconWidth>48</MaxIconWidth>
   <MaxIconHeight>48</MaxIconHeight>
   <MaxIconHeight>48</MaxIconHeight>
-  <MaxStreamingBitrate>30000000</MaxStreamingBitrate>
-  <MaxStaticBitrate>30000000</MaxStaticBitrate>
+  <MaxStreamingBitrate>40000000</MaxStreamingBitrate>
+  <MaxStaticBitrate>40000000</MaxStaticBitrate>
   <MusicStreamingTranscodingBitrate>192000</MusicStreamingTranscodingBitrate>
   <MusicStreamingTranscodingBitrate>192000</MusicStreamingTranscodingBitrate>
   <MaxStaticMusicBitrate xsi:nil="true" />
   <MaxStaticMusicBitrate xsi:nil="true" />
   <XDlnaDoc>DMS-1.50</XDlnaDoc>
   <XDlnaDoc>DMS-1.50</XDlnaDoc>

+ 2 - 2
Emby.Dlna/Profiles/Xml/Sony Blu-ray Player.xml

@@ -24,8 +24,8 @@
   <MaxAlbumArtHeight>480</MaxAlbumArtHeight>
   <MaxAlbumArtHeight>480</MaxAlbumArtHeight>
   <MaxIconWidth>48</MaxIconWidth>
   <MaxIconWidth>48</MaxIconWidth>
   <MaxIconHeight>48</MaxIconHeight>
   <MaxIconHeight>48</MaxIconHeight>
-  <MaxStreamingBitrate>30000000</MaxStreamingBitrate>
-  <MaxStaticBitrate>30000000</MaxStaticBitrate>
+  <MaxStreamingBitrate>40000000</MaxStreamingBitrate>
+  <MaxStaticBitrate>40000000</MaxStaticBitrate>
   <MusicStreamingTranscodingBitrate>192000</MusicStreamingTranscodingBitrate>
   <MusicStreamingTranscodingBitrate>192000</MusicStreamingTranscodingBitrate>
   <MaxStaticMusicBitrate xsi:nil="true" />
   <MaxStaticMusicBitrate xsi:nil="true" />
   <XDlnaDoc>DMS-1.50</XDlnaDoc>
   <XDlnaDoc>DMS-1.50</XDlnaDoc>

+ 2 - 2
Emby.Dlna/Profiles/Xml/Sony Bravia (2010).xml

@@ -23,8 +23,8 @@
   <MaxAlbumArtHeight>480</MaxAlbumArtHeight>
   <MaxAlbumArtHeight>480</MaxAlbumArtHeight>
   <MaxIconWidth>48</MaxIconWidth>
   <MaxIconWidth>48</MaxIconWidth>
   <MaxIconHeight>48</MaxIconHeight>
   <MaxIconHeight>48</MaxIconHeight>
-  <MaxStreamingBitrate>30000000</MaxStreamingBitrate>
-  <MaxStaticBitrate>30000000</MaxStaticBitrate>
+  <MaxStreamingBitrate>40000000</MaxStreamingBitrate>
+  <MaxStaticBitrate>40000000</MaxStaticBitrate>
   <MusicStreamingTranscodingBitrate>192000</MusicStreamingTranscodingBitrate>
   <MusicStreamingTranscodingBitrate>192000</MusicStreamingTranscodingBitrate>
   <MaxStaticMusicBitrate xsi:nil="true" />
   <MaxStaticMusicBitrate xsi:nil="true" />
   <XDlnaDoc>DMS-1.50</XDlnaDoc>
   <XDlnaDoc>DMS-1.50</XDlnaDoc>

+ 2 - 2
Emby.Dlna/Profiles/Xml/Sony Bravia (2011).xml

@@ -23,8 +23,8 @@
   <MaxAlbumArtHeight>480</MaxAlbumArtHeight>
   <MaxAlbumArtHeight>480</MaxAlbumArtHeight>
   <MaxIconWidth>48</MaxIconWidth>
   <MaxIconWidth>48</MaxIconWidth>
   <MaxIconHeight>48</MaxIconHeight>
   <MaxIconHeight>48</MaxIconHeight>
-  <MaxStreamingBitrate>30000000</MaxStreamingBitrate>
-  <MaxStaticBitrate>30000000</MaxStaticBitrate>
+  <MaxStreamingBitrate>40000000</MaxStreamingBitrate>
+  <MaxStaticBitrate>40000000</MaxStaticBitrate>
   <MusicStreamingTranscodingBitrate>192000</MusicStreamingTranscodingBitrate>
   <MusicStreamingTranscodingBitrate>192000</MusicStreamingTranscodingBitrate>
   <MaxStaticMusicBitrate xsi:nil="true" />
   <MaxStaticMusicBitrate xsi:nil="true" />
   <XDlnaDoc>DMS-1.50</XDlnaDoc>
   <XDlnaDoc>DMS-1.50</XDlnaDoc>

+ 2 - 2
Emby.Dlna/Profiles/Xml/Sony Bravia (2012).xml

@@ -23,8 +23,8 @@
   <MaxAlbumArtHeight>480</MaxAlbumArtHeight>
   <MaxAlbumArtHeight>480</MaxAlbumArtHeight>
   <MaxIconWidth>48</MaxIconWidth>
   <MaxIconWidth>48</MaxIconWidth>
   <MaxIconHeight>48</MaxIconHeight>
   <MaxIconHeight>48</MaxIconHeight>
-  <MaxStreamingBitrate>30000000</MaxStreamingBitrate>
-  <MaxStaticBitrate>30000000</MaxStaticBitrate>
+  <MaxStreamingBitrate>40000000</MaxStreamingBitrate>
+  <MaxStaticBitrate>40000000</MaxStaticBitrate>
   <MusicStreamingTranscodingBitrate>192000</MusicStreamingTranscodingBitrate>
   <MusicStreamingTranscodingBitrate>192000</MusicStreamingTranscodingBitrate>
   <MaxStaticMusicBitrate xsi:nil="true" />
   <MaxStaticMusicBitrate xsi:nil="true" />
   <XDlnaDoc>DMS-1.50</XDlnaDoc>
   <XDlnaDoc>DMS-1.50</XDlnaDoc>

+ 2 - 2
Emby.Dlna/Profiles/Xml/Sony Bravia (2013).xml

@@ -23,8 +23,8 @@
   <MaxAlbumArtHeight>480</MaxAlbumArtHeight>
   <MaxAlbumArtHeight>480</MaxAlbumArtHeight>
   <MaxIconWidth>48</MaxIconWidth>
   <MaxIconWidth>48</MaxIconWidth>
   <MaxIconHeight>48</MaxIconHeight>
   <MaxIconHeight>48</MaxIconHeight>
-  <MaxStreamingBitrate>30000000</MaxStreamingBitrate>
-  <MaxStaticBitrate>30000000</MaxStaticBitrate>
+  <MaxStreamingBitrate>40000000</MaxStreamingBitrate>
+  <MaxStaticBitrate>40000000</MaxStaticBitrate>
   <MusicStreamingTranscodingBitrate>192000</MusicStreamingTranscodingBitrate>
   <MusicStreamingTranscodingBitrate>192000</MusicStreamingTranscodingBitrate>
   <MaxStaticMusicBitrate xsi:nil="true" />
   <MaxStaticMusicBitrate xsi:nil="true" />
   <XDlnaDoc>DMS-1.50</XDlnaDoc>
   <XDlnaDoc>DMS-1.50</XDlnaDoc>

+ 2 - 2
Emby.Dlna/Profiles/Xml/Sony Bravia (2014).xml

@@ -23,8 +23,8 @@
   <MaxAlbumArtHeight>480</MaxAlbumArtHeight>
   <MaxAlbumArtHeight>480</MaxAlbumArtHeight>
   <MaxIconWidth>48</MaxIconWidth>
   <MaxIconWidth>48</MaxIconWidth>
   <MaxIconHeight>48</MaxIconHeight>
   <MaxIconHeight>48</MaxIconHeight>
-  <MaxStreamingBitrate>30000000</MaxStreamingBitrate>
-  <MaxStaticBitrate>30000000</MaxStaticBitrate>
+  <MaxStreamingBitrate>40000000</MaxStreamingBitrate>
+  <MaxStaticBitrate>40000000</MaxStaticBitrate>
   <MusicStreamingTranscodingBitrate>192000</MusicStreamingTranscodingBitrate>
   <MusicStreamingTranscodingBitrate>192000</MusicStreamingTranscodingBitrate>
   <MaxStaticMusicBitrate xsi:nil="true" />
   <MaxStaticMusicBitrate xsi:nil="true" />
   <XDlnaDoc>DMS-1.50</XDlnaDoc>
   <XDlnaDoc>DMS-1.50</XDlnaDoc>

+ 2 - 2
Emby.Dlna/Profiles/Xml/Sony PlayStation 3.xml

@@ -23,8 +23,8 @@
   <MaxAlbumArtHeight>480</MaxAlbumArtHeight>
   <MaxAlbumArtHeight>480</MaxAlbumArtHeight>
   <MaxIconWidth>48</MaxIconWidth>
   <MaxIconWidth>48</MaxIconWidth>
   <MaxIconHeight>48</MaxIconHeight>
   <MaxIconHeight>48</MaxIconHeight>
-  <MaxStreamingBitrate>30000000</MaxStreamingBitrate>
-  <MaxStaticBitrate>30000000</MaxStaticBitrate>
+  <MaxStreamingBitrate>40000000</MaxStreamingBitrate>
+  <MaxStaticBitrate>40000000</MaxStaticBitrate>
   <MusicStreamingTranscodingBitrate>192000</MusicStreamingTranscodingBitrate>
   <MusicStreamingTranscodingBitrate>192000</MusicStreamingTranscodingBitrate>
   <MaxStaticMusicBitrate xsi:nil="true" />
   <MaxStaticMusicBitrate xsi:nil="true" />
   <XDlnaDoc>DMS-1.50</XDlnaDoc>
   <XDlnaDoc>DMS-1.50</XDlnaDoc>

+ 2 - 2
Emby.Dlna/Profiles/Xml/Sony PlayStation 4.xml

@@ -23,8 +23,8 @@
   <MaxAlbumArtHeight>480</MaxAlbumArtHeight>
   <MaxAlbumArtHeight>480</MaxAlbumArtHeight>
   <MaxIconWidth>48</MaxIconWidth>
   <MaxIconWidth>48</MaxIconWidth>
   <MaxIconHeight>48</MaxIconHeight>
   <MaxIconHeight>48</MaxIconHeight>
-  <MaxStreamingBitrate>30000000</MaxStreamingBitrate>
-  <MaxStaticBitrate>30000000</MaxStaticBitrate>
+  <MaxStreamingBitrate>40000000</MaxStreamingBitrate>
+  <MaxStaticBitrate>40000000</MaxStaticBitrate>
   <MusicStreamingTranscodingBitrate>192000</MusicStreamingTranscodingBitrate>
   <MusicStreamingTranscodingBitrate>192000</MusicStreamingTranscodingBitrate>
   <MaxStaticMusicBitrate xsi:nil="true" />
   <MaxStaticMusicBitrate xsi:nil="true" />
   <XDlnaDoc>DMS-1.50</XDlnaDoc>
   <XDlnaDoc>DMS-1.50</XDlnaDoc>

Fișier diff suprimat deoarece este prea mare
+ 0 - 29
Emby.Dlna/Profiles/Xml/Vlc.xml


+ 2 - 2
Emby.Dlna/Profiles/Xml/WDTV Live.xml

@@ -23,8 +23,8 @@
   <MaxAlbumArtHeight>480</MaxAlbumArtHeight>
   <MaxAlbumArtHeight>480</MaxAlbumArtHeight>
   <MaxIconWidth>48</MaxIconWidth>
   <MaxIconWidth>48</MaxIconWidth>
   <MaxIconHeight>48</MaxIconHeight>
   <MaxIconHeight>48</MaxIconHeight>
-  <MaxStreamingBitrate>30000000</MaxStreamingBitrate>
-  <MaxStaticBitrate>30000000</MaxStaticBitrate>
+  <MaxStreamingBitrate>40000000</MaxStreamingBitrate>
+  <MaxStaticBitrate>40000000</MaxStaticBitrate>
   <MusicStreamingTranscodingBitrate>192000</MusicStreamingTranscodingBitrate>
   <MusicStreamingTranscodingBitrate>192000</MusicStreamingTranscodingBitrate>
   <MaxStaticMusicBitrate xsi:nil="true" />
   <MaxStaticMusicBitrate xsi:nil="true" />
   <XDlnaDoc>DMS-1.50</XDlnaDoc>
   <XDlnaDoc>DMS-1.50</XDlnaDoc>

+ 2 - 2
Emby.Dlna/Profiles/Xml/Xbox 360.xml

@@ -24,8 +24,8 @@
   <MaxAlbumArtHeight>480</MaxAlbumArtHeight>
   <MaxAlbumArtHeight>480</MaxAlbumArtHeight>
   <MaxIconWidth>48</MaxIconWidth>
   <MaxIconWidth>48</MaxIconWidth>
   <MaxIconHeight>48</MaxIconHeight>
   <MaxIconHeight>48</MaxIconHeight>
-  <MaxStreamingBitrate>30000000</MaxStreamingBitrate>
-  <MaxStaticBitrate>30000000</MaxStaticBitrate>
+  <MaxStreamingBitrate>40000000</MaxStreamingBitrate>
+  <MaxStaticBitrate>40000000</MaxStaticBitrate>
   <MusicStreamingTranscodingBitrate>192000</MusicStreamingTranscodingBitrate>
   <MusicStreamingTranscodingBitrate>192000</MusicStreamingTranscodingBitrate>
   <MaxStaticMusicBitrate xsi:nil="true" />
   <MaxStaticMusicBitrate xsi:nil="true" />
   <XDlnaDoc>DMS-1.50</XDlnaDoc>
   <XDlnaDoc>DMS-1.50</XDlnaDoc>

+ 2 - 2
Emby.Dlna/Profiles/Xml/Xbox One.xml

@@ -23,8 +23,8 @@
   <MaxAlbumArtHeight>480</MaxAlbumArtHeight>
   <MaxAlbumArtHeight>480</MaxAlbumArtHeight>
   <MaxIconWidth>48</MaxIconWidth>
   <MaxIconWidth>48</MaxIconWidth>
   <MaxIconHeight>48</MaxIconHeight>
   <MaxIconHeight>48</MaxIconHeight>
-  <MaxStreamingBitrate>30000000</MaxStreamingBitrate>
-  <MaxStaticBitrate>30000000</MaxStaticBitrate>
+  <MaxStreamingBitrate>40000000</MaxStreamingBitrate>
+  <MaxStaticBitrate>40000000</MaxStaticBitrate>
   <MusicStreamingTranscodingBitrate>192000</MusicStreamingTranscodingBitrate>
   <MusicStreamingTranscodingBitrate>192000</MusicStreamingTranscodingBitrate>
   <MaxStaticMusicBitrate xsi:nil="true" />
   <MaxStaticMusicBitrate xsi:nil="true" />
   <XDlnaDoc>DMS-1.50</XDlnaDoc>
   <XDlnaDoc>DMS-1.50</XDlnaDoc>

+ 11 - 3
Emby.Dlna/Profiles/Xml/foobar2000.xml

@@ -22,8 +22,8 @@
   <MaxAlbumArtHeight>480</MaxAlbumArtHeight>
   <MaxAlbumArtHeight>480</MaxAlbumArtHeight>
   <MaxIconWidth>48</MaxIconWidth>
   <MaxIconWidth>48</MaxIconWidth>
   <MaxIconHeight>48</MaxIconHeight>
   <MaxIconHeight>48</MaxIconHeight>
-  <MaxStreamingBitrate>30000000</MaxStreamingBitrate>
-  <MaxStaticBitrate>30000000</MaxStaticBitrate>
+  <MaxStreamingBitrate>40000000</MaxStreamingBitrate>
+  <MaxStaticBitrate>40000000</MaxStaticBitrate>
   <MusicStreamingTranscodingBitrate>192000</MusicStreamingTranscodingBitrate>
   <MusicStreamingTranscodingBitrate>192000</MusicStreamingTranscodingBitrate>
   <MaxStaticMusicBitrate xsi:nil="true" />
   <MaxStaticMusicBitrate xsi:nil="true" />
   <XDlnaDoc>DMS-1.50</XDlnaDoc>
   <XDlnaDoc>DMS-1.50</XDlnaDoc>
@@ -51,7 +51,15 @@
   <CodecProfiles />
   <CodecProfiles />
   <ResponseProfiles />
   <ResponseProfiles />
   <SubtitleProfiles>
   <SubtitleProfiles>
-    <SubtitleProfile format="srt" method="Embed" />
     <SubtitleProfile format="srt" method="External" />
     <SubtitleProfile format="srt" method="External" />
+    <SubtitleProfile format="sub" method="External" />
+    <SubtitleProfile format="srt" method="Embed" />
+    <SubtitleProfile format="ass" method="Embed" />
+    <SubtitleProfile format="ssa" method="Embed" />
+    <SubtitleProfile format="smi" method="Embed" />
+    <SubtitleProfile format="dvdsub" method="Embed" />
+    <SubtitleProfile format="pgs" method="Embed" />
+    <SubtitleProfile format="pgssub" method="Embed" />
+    <SubtitleProfile format="sub" method="Embed" />
   </SubtitleProfiles>
   </SubtitleProfiles>
 </Profile>
 </Profile>

+ 5 - 11
Emby.Drawing.ImageMagick/ImageMagickEncoder.cs

@@ -105,17 +105,6 @@ namespace Emby.Drawing.ImageMagick
             }
             }
         }
         }
 
 
-        public void CropWhiteSpace(string inputPath, string outputPath)
-        {
-            CheckDisposed();
-
-            using (var wand = new MagickWand(inputPath))
-            {
-                wand.CurrentImage.TrimImage(10);
-                wand.SaveImage(outputPath);
-            }
-        }
-
         public ImageSize GetImageSize(string path)
         public ImageSize GetImageSize(string path)
         {
         {
             CheckDisposed();
             CheckDisposed();
@@ -150,6 +139,11 @@ namespace Emby.Drawing.ImageMagick
             {
             {
                 using (var originalImage = new MagickWand(inputPath))
                 using (var originalImage = new MagickWand(inputPath))
                 {
                 {
+                    if (options.CropWhiteSpace)
+                    {
+                        originalImage.CurrentImage.TrimImage(10);
+                    }
+
                     ScaleImage(originalImage, width, height, options.Blur ?? 0);
                     ScaleImage(originalImage, width, height, options.Blur ?? 0);
 
 
                     if (autoOrient)
                     if (autoOrient)

+ 7 - 10
Emby.Drawing.Net/GDIImageEncoder.cs

@@ -75,27 +75,24 @@ namespace Emby.Drawing.Net
             }
             }
         }
         }
 
 
-        public void CropWhiteSpace(string inputPath, string outputPath)
+        private Image GetImage(string path, bool cropWhitespace)
         {
         {
-            using (var image = (Bitmap)Image.FromFile(inputPath))
+            if (cropWhitespace)
             {
             {
-                using (var croppedImage = image.CropWhitespace())
+                using (var originalImage = (Bitmap)Image.FromFile(path))
                 {
                 {
-                    _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(outputPath));
-
-                    using (var outputStream = _fileSystem.GetFileStream(outputPath, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read, false))
-                    {
-                        croppedImage.Save(System.Drawing.Imaging.ImageFormat.Png, outputStream, 100);
-                    }
+                    return originalImage.CropWhitespace();
                 }
                 }
             }
             }
+
+            return Image.FromFile(path);
         }
         }
 
 
         public void EncodeImage(string inputPath, string cacheFilePath, bool autoOrient, int width, int height, int quality, ImageProcessingOptions options, ImageFormat selectedOutputFormat)
         public void EncodeImage(string inputPath, string cacheFilePath, bool autoOrient, int width, int height, int quality, ImageProcessingOptions options, ImageFormat selectedOutputFormat)
         {
         {
             var hasPostProcessing = !string.IsNullOrEmpty(options.BackgroundColor) || options.UnplayedCount.HasValue || options.AddPlayedIndicator || options.PercentPlayed > 0;
             var hasPostProcessing = !string.IsNullOrEmpty(options.BackgroundColor) || options.UnplayedCount.HasValue || options.AddPlayedIndicator || options.PercentPlayed > 0;
 
 
-            using (var originalImage = Image.FromFile(inputPath))
+            using (var originalImage = GetImage(inputPath, options.CropWhiteSpace))
             {
             {
                 var newWidth = Convert.ToInt32(width);
                 var newWidth = Convert.ToInt32(width);
                 var newHeight = Convert.ToInt32(height);
                 var newHeight = Convert.ToInt32(height);

+ 80 - 0
Emby.Drawing.Skia/Emby.Drawing.Skia.csproj

@@ -0,0 +1,80 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+  <PropertyGroup>
+    <MinimumVisualStudioVersion>11.0</MinimumVisualStudioVersion>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectGuid>{2312DA6D-FF86-4597-9777-BCEEC32D96DD}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>Emby.Drawing.Skia</RootNamespace>
+    <AssemblyName>Emby.Drawing.Skia</AssemblyName>
+    <DefaultLanguage>en-US</DefaultLanguage>
+    <FileAlignment>512</FileAlignment>
+    <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+    <TargetFrameworkProfile>Profile7</TargetFrameworkProfile>
+    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <!-- A reference to the entire .NET Framework is automatically included -->
+    <ProjectReference Include="..\MediaBrowser.Common\MediaBrowser.Common.csproj">
+      <Project>{9142eefa-7570-41e1-bfcc-468bb571af2f}</Project>
+      <Name>MediaBrowser.Common</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\MediaBrowser.Controller\MediaBrowser.Controller.csproj">
+      <Project>{17e1f4e6-8abd-4fe5-9ecf-43d4b6087ba2}</Project>
+      <Name>MediaBrowser.Controller</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj">
+      <Project>{7eeeb4bb-f3e8-48fc-b4c5-70f0fff8329b}</Project>
+      <Name>MediaBrowser.Model</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="..\SharedVersion.cs">
+      <Link>Properties\SharedVersion.cs</Link>
+    </Compile>
+    <Compile Include="PercentPlayedDrawer.cs" />
+    <Compile Include="PlayedIndicatorDrawer.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="SkiaEncoder.cs" />
+    <Compile Include="StripCollageBuilder.cs" />
+    <Compile Include="UnplayedCountIndicator.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <Reference Include="SkiaSharp, Version=1.57.0.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756, processorArchitecture=MSIL">
+      <HintPath>..\packages\SkiaSharp.1.57.1\lib\portable-net45+win8+wpa81+wp8\SkiaSharp.dll</HintPath>
+      <Private>True</Private>
+    </Reference>
+  </ItemGroup>
+  <ItemGroup>
+    <EmbeddedResource Include="fonts\robotoregular.ttf" />
+    <None Include="packages.config" />
+  </ItemGroup>
+  <Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>

+ 31 - 0
Emby.Drawing.Skia/PercentPlayedDrawer.cs

@@ -0,0 +1,31 @@
+using SkiaSharp;
+using MediaBrowser.Model.Drawing;
+using System;
+
+namespace Emby.Drawing.Skia
+{
+    public class PercentPlayedDrawer
+    {
+        private const int IndicatorHeight = 8;
+
+        public void Process(SKCanvas canvas, ImageSize imageSize, double percent)
+        {
+            using (var paint = new SKPaint())
+            {
+                var endX = imageSize.Width - 1;
+                var endY = imageSize.Height - 1;
+
+                paint.Color = SKColor.Parse("#99000000");
+                paint.Style = SKPaintStyle.Fill;
+                canvas.DrawRect(SKRect.Create(0, (float)endY - IndicatorHeight, (float)endX, (float)endY), paint);
+
+                double foregroundWidth = endX;
+                foregroundWidth *= percent;
+                foregroundWidth /= 100;
+
+                paint.Color = SKColor.Parse("#FF52B54B");
+                canvas.DrawRect(SKRect.Create(0, (float)endY - IndicatorHeight, Convert.ToInt32(Math.Round(foregroundWidth)), (float)endY), paint);
+            }
+        }
+    }
+}

+ 120 - 0
Emby.Drawing.Skia/PlayedIndicatorDrawer.cs

@@ -0,0 +1,120 @@
+using SkiaSharp;
+using MediaBrowser.Common.Configuration;
+using MediaBrowser.Common.Net;
+using MediaBrowser.Model.Drawing;
+using System;
+using System.IO;
+using System.Threading.Tasks;
+using MediaBrowser.Common.IO;
+using MediaBrowser.Controller.IO;
+using MediaBrowser.Model.IO;
+using System.Reflection;
+
+namespace Emby.Drawing.Skia
+{
+    public class PlayedIndicatorDrawer
+    {
+        private const int FontSize = 42;
+        private const int OffsetFromTopRightCorner = 38;
+
+        private readonly IApplicationPaths _appPaths;
+        private readonly IHttpClient _iHttpClient;
+        private readonly IFileSystem _fileSystem;
+
+        public PlayedIndicatorDrawer(IApplicationPaths appPaths, IHttpClient iHttpClient, IFileSystem fileSystem)
+        {
+            _appPaths = appPaths;
+            _iHttpClient = iHttpClient;
+            _fileSystem = fileSystem;
+        }
+
+        public async Task DrawPlayedIndicator(SKCanvas canvas, ImageSize imageSize)
+        {
+            var x = imageSize.Width - OffsetFromTopRightCorner;
+
+            using (var paint = new SKPaint())
+            {
+                paint.Color = SKColor.Parse("#CC52B54B");
+                paint.Style = SKPaintStyle.Fill;
+                canvas.DrawCircle((float)x, OffsetFromTopRightCorner, 20, paint);
+            }
+
+            using (var paint = new SKPaint())
+            {
+                paint.Color = new SKColor(255, 255, 255, 255);
+                paint.Style = SKPaintStyle.Fill;
+                paint.Typeface = SKTypeface.FromFile(await DownloadFont("webdings.ttf", "https://github.com/MediaBrowser/Emby.Resources/raw/master/fonts/webdings.ttf",
+                    _appPaths, _iHttpClient, _fileSystem).ConfigureAwait(false));
+                paint.TextSize = FontSize;
+                paint.IsAntialias = true;
+
+                canvas.DrawText("a", (float)x-20, OffsetFromTopRightCorner + 12, paint);
+            }
+        }
+
+        internal static string ExtractFont(string name, IApplicationPaths paths, IFileSystem fileSystem)
+        {
+            var filePath = Path.Combine(paths.ProgramDataPath, "fonts", name);
+
+            if (fileSystem.FileExists(filePath))
+            {
+                return filePath;
+            }
+
+            var namespacePath = typeof(PlayedIndicatorDrawer).Namespace + ".fonts." + name;
+            var tempPath = Path.Combine(paths.TempDirectory, Guid.NewGuid().ToString("N") + ".ttf");
+            fileSystem.CreateDirectory(fileSystem.GetDirectoryName(tempPath));
+
+            using (var stream = typeof(PlayedIndicatorDrawer).GetTypeInfo().Assembly.GetManifestResourceStream(namespacePath))
+            {
+                using (var fileStream = fileSystem.GetFileStream(tempPath, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read))
+                {
+                    stream.CopyTo(fileStream);
+                }
+            }
+
+            fileSystem.CreateDirectory(fileSystem.GetDirectoryName(filePath));
+
+            try
+            {
+                fileSystem.CopyFile(tempPath, filePath, false);
+            }
+            catch (IOException)
+            {
+
+            }
+
+            return tempPath;
+        }
+
+        internal static async Task<string> DownloadFont(string name, string url, IApplicationPaths paths, IHttpClient httpClient, IFileSystem fileSystem)
+        {
+            var filePath = Path.Combine(paths.ProgramDataPath, "fonts", name);
+
+            if (fileSystem.FileExists(filePath))
+            {
+                return filePath;
+            }
+
+            var tempPath = await httpClient.GetTempFile(new HttpRequestOptions
+            {
+                Url = url,
+                Progress = new Progress<double>()
+
+            }).ConfigureAwait(false);
+
+            fileSystem.CreateDirectory(fileSystem.GetDirectoryName(filePath));
+
+            try
+            {
+                fileSystem.CopyFile(tempPath, filePath, false);
+            }
+            catch (IOException)
+            {
+
+            }
+
+            return tempPath;
+        }
+    }
+}

+ 25 - 0
Emby.Drawing.Skia/Properties/AssemblyInfo.cs

@@ -0,0 +1,25 @@
+using System.Resources;
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following 
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Emby.Drawing.Skia")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("Emby.Drawing.Skia")]
+[assembly: AssemblyCopyright("Copyright ©  2017")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+[assembly: NeutralResourcesLanguage("en")]
+
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version 
+//      Build Number
+//      Revision
+//

+ 387 - 0
Emby.Drawing.Skia/SkiaEncoder.cs

@@ -0,0 +1,387 @@
+using MediaBrowser.Common.Configuration;
+using MediaBrowser.Common.Net;
+using MediaBrowser.Controller.Drawing;
+using MediaBrowser.Model.Drawing;
+using MediaBrowser.Model.IO;
+using MediaBrowser.Model.Logging;
+using SkiaSharp;
+using System;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using System.Threading.Tasks;
+
+namespace Emby.Drawing.Skia
+{
+    public class SkiaEncoder : IImageEncoder
+    {
+        private readonly ILogger _logger;
+        private readonly IApplicationPaths _appPaths;
+        private readonly Func<IHttpClient> _httpClientFactory;
+        private readonly IFileSystem _fileSystem;
+
+        public SkiaEncoder(ILogger logger, IApplicationPaths appPaths, Func<IHttpClient> httpClientFactory, IFileSystem fileSystem)
+        {
+            _logger = logger;
+            _appPaths = appPaths;
+            _httpClientFactory = httpClientFactory;
+            _fileSystem = fileSystem;
+
+            LogVersion();
+        }
+
+        public string[] SupportedInputFormats
+        {
+            get
+            {
+                // Some common file name extensions for RAW picture files include: .cr2, .crw, .dng, .nef, .orf, .rw2, .pef, .arw, .sr2, .srf, and .tif.
+                return new[]
+                {
+                    "jpeg",
+                    "jpg",
+                    "png",
+                    "dng",
+                    "webp",
+                    "gif",
+                    "bmp",
+                    "ico",
+                    "astc",
+                    "ktx",
+                    "pkm",
+                    "wbmp"
+                };
+            }
+        }
+
+        public ImageFormat[] SupportedOutputFormats
+        {
+            get
+            {
+                return new[] { ImageFormat.Webp, ImageFormat.Gif, ImageFormat.Jpg, ImageFormat.Png, ImageFormat.Bmp };
+            }
+        }
+
+        private void LogVersion()
+        {
+            _logger.Info("SkiaSharp version: " + GetVersion());
+        }
+
+        public static string GetVersion()
+        {
+            using (var bitmap = new SKBitmap())
+            {
+                return typeof(SKBitmap).GetTypeInfo().Assembly.GetName().Version.ToString();
+            }
+        }
+
+        private static bool IsWhiteSpace(SKColor color)
+        {
+            return (color.Red == 255 && color.Green == 255 && color.Blue == 255) || color.Alpha == 0;
+        }
+
+        public static SKEncodedImageFormat GetImageFormat(ImageFormat selectedFormat)
+        {
+            switch (selectedFormat)
+            {
+                case ImageFormat.Bmp:
+                    return SKEncodedImageFormat.Bmp;
+                case ImageFormat.Jpg:
+                    return SKEncodedImageFormat.Jpeg;
+                case ImageFormat.Gif:
+                    return SKEncodedImageFormat.Gif;
+                case ImageFormat.Webp:
+                    return SKEncodedImageFormat.Webp;
+                default:
+                    return SKEncodedImageFormat.Png;
+            }
+        }
+
+        private static bool IsAllWhiteRow(SKBitmap bmp, int row)
+        {
+            for (var i = 0; i < bmp.Width; ++i)
+            {
+                if (!IsWhiteSpace(bmp.GetPixel(i, row)))
+                {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        private static bool IsAllWhiteColumn(SKBitmap bmp, int col)
+        {
+            for (var i = 0; i < bmp.Height; ++i)
+            {
+                if (!IsWhiteSpace(bmp.GetPixel(col, i)))
+                {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        private SKBitmap CropWhiteSpace(SKBitmap bitmap)
+        {
+            var topmost = 0;
+            for (int row = 0; row < bitmap.Height; ++row)
+            {
+                if (IsAllWhiteRow(bitmap, row))
+                    topmost = row;
+                else break;
+            }
+
+            int bottommost = 0;
+            for (int row = bitmap.Height - 1; row >= 0; --row)
+            {
+                if (IsAllWhiteRow(bitmap, row))
+                    bottommost = row;
+                else break;
+            }
+
+            int leftmost = 0, rightmost = 0;
+            for (int col = 0; col < bitmap.Width; ++col)
+            {
+                if (IsAllWhiteColumn(bitmap, col))
+                    leftmost = col;
+                else
+                    break;
+            }
+
+            for (int col = bitmap.Width - 1; col >= 0; --col)
+            {
+                if (IsAllWhiteColumn(bitmap, col))
+                    rightmost = col;
+                else
+                    break;
+            }
+
+            var newRect = SKRectI.Create(leftmost, topmost, rightmost - leftmost, bottommost - topmost);
+
+            using (var image = SKImage.FromBitmap(bitmap))
+            {
+                using (var subset = image.Subset(newRect))
+                {
+                    return SKBitmap.FromImage(subset);
+                    //using (var data = subset.Encode(StripCollageBuilder.GetEncodedFormat(outputPath), 90))
+                    //{
+                    //    using (var fileStream = _fileSystem.GetFileStream(outputPath, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read))
+                    //    {
+                    //        data.AsStream().CopyTo(fileStream);
+                    //    }
+                    //}
+                }
+            }
+        }
+
+        public ImageSize GetImageSize(string path)
+        {
+            using (var s = new SKFileStream(path))
+            {
+                using (var codec = SKCodec.Create(s))
+                {
+                    var info = codec.Info;
+
+                    return new ImageSize
+                    {
+                        Width = info.Width,
+                        Height = info.Height
+                    };
+                }
+            }
+        }
+
+        private string[] TransparentImageTypes = new string[] { ".png", ".gif", ".webp" };
+        private SKBitmap Decode(string path)
+        {
+            var requiresTransparencyHack = TransparentImageTypes.Contains(Path.GetExtension(path) ?? string.Empty);
+
+            if (requiresTransparencyHack)
+            {
+                using (var stream = new SKFileStream(path))
+                {
+                    var codec = SKCodec.Create(stream);
+
+                    // create the bitmap
+                    var bitmap = new SKBitmap(codec.Info.Width, codec.Info.Height);
+                    // decode
+                    codec.GetPixels(bitmap.Info, bitmap.GetPixels());
+
+                    return bitmap;
+                }
+            }
+
+            return SKBitmap.Decode(path);
+        }
+
+        private SKBitmap GetBitmap(string path, bool cropWhitespace)
+        {
+            if (cropWhitespace)
+            {
+                using (var bitmap = Decode(path))
+                {
+                    return CropWhiteSpace(bitmap);
+                }
+            }
+
+            return Decode(path);
+        }
+
+        public void EncodeImage(string inputPath, string outputPath, bool autoOrient, int width, int height, int quality, ImageProcessingOptions options, ImageFormat selectedOutputFormat)
+        {
+            if (string.IsNullOrWhiteSpace(inputPath))
+            {
+                throw new ArgumentNullException("inputPath");
+            }
+            if (string.IsNullOrWhiteSpace(inputPath))
+            {
+                throw new ArgumentNullException("outputPath");
+            }
+
+            var skiaOutputFormat = GetImageFormat(selectedOutputFormat);
+
+            var hasBackgroundColor = !string.IsNullOrWhiteSpace(options.BackgroundColor);
+            var hasForegroundColor = !string.IsNullOrWhiteSpace(options.ForegroundLayer);
+            var blur = options.Blur ?? 0;
+            var hasIndicator = options.AddPlayedIndicator || options.UnplayedCount.HasValue || !options.PercentPlayed.Equals(0);
+
+            using (var bitmap = GetBitmap(inputPath, options.CropWhiteSpace))
+            {
+                using (var resizedBitmap = new SKBitmap(width, height))//, bitmap.ColorType, bitmap.AlphaType))
+                {
+                    // scale image
+                    var resizeMethod = SKBitmapResizeMethod.Lanczos3;
+
+                    bitmap.Resize(resizedBitmap, resizeMethod);
+
+                    // If all we're doing is resizing then we can stop now
+                    if (!hasBackgroundColor && !hasForegroundColor && blur == 0 && !hasIndicator)
+                    {
+                        using (var outputStream = new SKFileWStream(outputPath))
+                        {
+                            resizedBitmap.Encode(outputStream, skiaOutputFormat, quality);
+                            return;
+                        }
+                    }
+
+                    // create bitmap to use for canvas drawing
+                    using (var saveBitmap = new SKBitmap(width, height))//, bitmap.ColorType, bitmap.AlphaType))
+                    {
+                        // create canvas used to draw into bitmap
+                        using (var canvas = new SKCanvas(saveBitmap))
+                        {
+                            // set background color if present
+                            if (hasBackgroundColor)
+                            {
+                                canvas.Clear(SKColor.Parse(options.BackgroundColor));
+                            }
+
+                            // Add blur if option is present
+                            if (blur > 0)
+                            {
+                                using (var paint = new SKPaint())
+                                {
+                                    // create image from resized bitmap to apply blur
+                                    using (var filter = SKImageFilter.CreateBlur(blur, blur))
+                                    {
+                                        paint.ImageFilter = filter;
+                                        canvas.DrawBitmap(resizedBitmap, SKRect.Create(width, height), paint);
+                                    }
+                                }
+                            }
+                            else
+                            {
+                                // draw resized bitmap onto canvas
+                                canvas.DrawBitmap(resizedBitmap, SKRect.Create(width, height));
+                            }
+
+                            // If foreground layer present then draw
+                            if (hasForegroundColor)
+                            {
+                                Double opacity;
+                                if (!Double.TryParse(options.ForegroundLayer, out opacity)) opacity = .4;
+
+                                canvas.DrawColor(new SKColor(0, 0, 0, (Byte)((1 - opacity) * 0xFF)), SKBlendMode.SrcOver);
+                            }
+
+                            if (hasIndicator)
+                            {
+                                DrawIndicator(canvas, width, height, options);
+                            }
+
+                            using (var outputStream = new SKFileWStream(outputPath))
+                            {
+                                saveBitmap.Encode(outputStream, skiaOutputFormat, quality);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        public void CreateImageCollage(ImageCollageOptions options)
+        {
+            double ratio = options.Width;
+            ratio /= options.Height;
+
+            if (ratio >= 1.4)
+            {
+                new StripCollageBuilder(_appPaths, _fileSystem).BuildThumbCollage(options.InputPaths, options.OutputPath, options.Width, options.Height);
+            }
+            else if (ratio >= .9)
+            {
+                new StripCollageBuilder(_appPaths, _fileSystem).BuildSquareCollage(options.InputPaths, options.OutputPath, options.Width, options.Height);
+            }
+            else
+            {
+                // @todo create Poster collage capability
+                new StripCollageBuilder(_appPaths, _fileSystem).BuildSquareCollage(options.InputPaths, options.OutputPath, options.Width, options.Height);
+            }
+        }
+
+        private void DrawIndicator(SKCanvas canvas, int imageWidth, int imageHeight, ImageProcessingOptions options)
+        {
+            try
+            {
+                var currentImageSize = new ImageSize(imageWidth, imageHeight);
+
+                if (options.AddPlayedIndicator)
+                {
+                    var task = new PlayedIndicatorDrawer(_appPaths, _httpClientFactory(), _fileSystem).DrawPlayedIndicator(canvas, currentImageSize);
+                    Task.WaitAll(task);
+                }
+                else if (options.UnplayedCount.HasValue)
+                {
+                    new UnplayedCountIndicator(_appPaths, _httpClientFactory(), _fileSystem).DrawUnplayedCountIndicator(canvas, currentImageSize, options.UnplayedCount.Value);
+                }
+
+                if (options.PercentPlayed > 0)
+                {
+                    new PercentPlayedDrawer().Process(canvas, currentImageSize, options.PercentPlayed);
+                }
+            }
+            catch (Exception ex)
+            {
+                _logger.ErrorException("Error drawing indicator overlay", ex);
+            }
+        }
+
+        public string Name
+        {
+            get { return "Skia"; }
+        }
+
+        public void Dispose()
+        {
+        }
+
+        public bool SupportsImageCollageCreation
+        {
+            get { return true; }
+        }
+
+        public bool SupportsImageEncoding
+        {
+            get { return true; }
+        }
+    }
+}

+ 190 - 0
Emby.Drawing.Skia/StripCollageBuilder.cs

@@ -0,0 +1,190 @@
+using SkiaSharp;
+using MediaBrowser.Common.Configuration;
+using System;
+using System.IO;
+using MediaBrowser.Model.IO;
+
+namespace Emby.Drawing.Skia
+{
+    public class StripCollageBuilder
+    {
+        private readonly IApplicationPaths _appPaths;
+        private readonly IFileSystem _fileSystem;
+
+        public StripCollageBuilder(IApplicationPaths appPaths, IFileSystem fileSystem)
+        {
+            _appPaths = appPaths;
+            _fileSystem = fileSystem;
+        }
+
+        public static SKEncodedImageFormat GetEncodedFormat(string outputPath)
+        {
+            var ext = Path.GetExtension(outputPath).ToLower();
+
+            if (ext == ".jpg" || ext == ".jpeg")
+                return SKEncodedImageFormat.Jpeg;
+
+            if (ext == ".webp")
+                return SKEncodedImageFormat.Webp;
+
+            if (ext == ".gif")
+                return SKEncodedImageFormat.Gif;
+
+            if (ext == ".bmp")
+                return SKEncodedImageFormat.Bmp;
+
+            // default to png
+            return SKEncodedImageFormat.Png;
+        }
+
+        public void BuildPosterCollage(string[] paths, string outputPath, int width, int height)
+        {
+            // @todo
+        }
+
+        public void BuildSquareCollage(string[] paths, string outputPath, int width, int height)
+        {
+            using (var bitmap = BuildSquareCollageBitmap(paths, width, height))
+            {
+                using (var outputStream = new SKFileWStream(outputPath))
+                {
+                    bitmap.Encode(outputStream, GetEncodedFormat(outputPath), 90);
+                }
+            }
+        }
+
+        public void BuildThumbCollage(string[] paths, string outputPath, int width, int height)
+        {
+            using (var bitmap = BuildThumbCollageBitmap(paths, width, height))
+            {
+                using (var outputStream = new SKFileWStream(outputPath))
+                {
+                    bitmap.Encode(outputStream, GetEncodedFormat(outputPath), 90);
+                }
+            }
+        }
+
+        private SKBitmap BuildThumbCollageBitmap(string[] paths, int width, int height)
+        {
+            var bitmap = new SKBitmap(width, height);
+
+            using (var canvas = new SKCanvas(bitmap))
+            {
+                canvas.Clear(SKColors.Black);
+
+                // determine sizes for each image that will composited into the final image
+                var iSlice = Convert.ToInt32(width * 0.23475);
+                int iTrans = Convert.ToInt32(height * .25);
+                int iHeight = Convert.ToInt32(height * .70);
+                var horizontalImagePadding = Convert.ToInt32(width * 0.0125);
+                var verticalSpacing = Convert.ToInt32(height * 0.01111111111111111111111111111111);
+                int imageIndex = 0;
+
+                for (int i = 0; i < 4; i++)
+                {
+                    using (var currentBitmap = SKBitmap.Decode(paths[imageIndex]))
+                    {
+                        // resize to the same aspect as the original
+                        int iWidth = (int)Math.Abs(iHeight * currentBitmap.Width / currentBitmap.Height);
+                        using (var resizeBitmap = new SKBitmap(iWidth, iHeight, currentBitmap.ColorType, currentBitmap.AlphaType))
+                        {
+                            currentBitmap.Resize(resizeBitmap, SKBitmapResizeMethod.Lanczos3);
+                            // determine how much to crop
+                            int ix = (int)Math.Abs((iWidth - iSlice) / 2);
+                            using (var image = SKImage.FromBitmap(resizeBitmap))
+                            {
+                                // crop image
+                                using (var subset = image.Subset(SKRectI.Create(ix, 0, iSlice, iHeight)))
+                                {
+                                    // draw image onto canvas
+                                    canvas.DrawImage(subset, (horizontalImagePadding * (i + 1)) + (iSlice * i), verticalSpacing);
+
+                                    using (var croppedBitmap = SKBitmap.FromImage(subset))
+                                    {
+                                        // create reflection of image below the drawn image
+                                        using (var reflectionBitmap = new SKBitmap(croppedBitmap.Width, croppedBitmap.Height / 2, croppedBitmap.ColorType, croppedBitmap.AlphaType))
+                                        {
+                                            // resize to half height
+                                            croppedBitmap.Resize(reflectionBitmap, SKBitmapResizeMethod.Lanczos3);
+
+                                            using (var flippedBitmap = new SKBitmap(reflectionBitmap.Width, reflectionBitmap.Height, reflectionBitmap.ColorType, reflectionBitmap.AlphaType))
+                                            {
+                                                using (var flippedCanvas = new SKCanvas(flippedBitmap))
+                                                {
+                                                    // flip image vertically
+                                                    var matrix = SKMatrix.MakeScale(1, -1);
+                                                    matrix.SetScaleTranslate(1, -1, 0, flippedBitmap.Height);
+                                                    flippedCanvas.SetMatrix(matrix);
+                                                    flippedCanvas.DrawBitmap(reflectionBitmap, 0, 0);
+                                                    flippedCanvas.ResetMatrix();
+
+                                                    // create gradient to make image appear as a reflection
+                                                    var remainingHeight = height - (iHeight + (2 * verticalSpacing));
+                                                    flippedCanvas.ClipRect(SKRect.Create(reflectionBitmap.Width, remainingHeight));
+                                                    using (var gradient = new SKPaint())
+                                                    {
+                                                        gradient.IsAntialias = true;
+                                                        gradient.BlendMode = SKBlendMode.SrcOver;
+                                                        gradient.Shader = SKShader.CreateLinearGradient(new SKPoint(0, 0), new SKPoint(0, remainingHeight), new[] { new SKColor(0, 0, 0, 128), new SKColor(0, 0, 0, 208), new SKColor(0, 0, 0, 240), new SKColor(0, 0, 0, 255) }, null, SKShaderTileMode.Clamp);
+                                                        flippedCanvas.DrawPaint(gradient);
+                                                    }
+
+                                                    // finally draw reflection onto canvas
+                                                    canvas.DrawBitmap(flippedBitmap, (horizontalImagePadding * (i + 1)) + (iSlice * i), iHeight + (2 * verticalSpacing));
+                                                }
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+
+                    imageIndex++;
+
+                    if (imageIndex >= paths.Length)
+                        imageIndex = 0;
+                }
+            }
+
+            return bitmap;
+        }
+
+        private SKBitmap BuildSquareCollageBitmap(string[] paths, int width, int height)
+        {
+            var bitmap = new SKBitmap(width, height);
+            var imageIndex = 0;
+            var cellWidth = width / 2;
+            var cellHeight = height / 2;
+
+            using (var canvas = new SKCanvas(bitmap))
+            {
+                for (var x = 0; x < 2; x++)
+                {
+                    for (var y = 0; y < 2; y++)
+                    {
+                        using (var currentBitmap = SKBitmap.Decode(paths[imageIndex]))
+                        {
+                            using (var resizedBitmap = new SKBitmap(cellWidth, cellHeight, currentBitmap.ColorType, currentBitmap.AlphaType))
+                            {
+                                // scale image
+                                currentBitmap.Resize(resizedBitmap, SKBitmapResizeMethod.Lanczos3);
+
+                                // draw this image into the strip at the next position
+                                var xPos = x * cellWidth;
+                                var yPos = y * cellHeight;
+                                canvas.DrawBitmap(resizedBitmap, xPos, yPos);
+                            }
+                        }
+                        imageIndex++;
+
+                        if (imageIndex >= paths.Length)
+                            imageIndex = 0;
+                    }
+                }
+            }
+
+            return bitmap;
+        }
+    }
+}

+ 68 - 0
Emby.Drawing.Skia/UnplayedCountIndicator.cs

@@ -0,0 +1,68 @@
+using SkiaSharp;
+using MediaBrowser.Common.Configuration;
+using MediaBrowser.Common.Net;
+using MediaBrowser.Model.Drawing;
+using System.Globalization;
+using System.Threading.Tasks;
+using MediaBrowser.Common.IO;
+using MediaBrowser.Controller.IO;
+using MediaBrowser.Model.IO;
+
+namespace Emby.Drawing.Skia
+{
+    public class UnplayedCountIndicator
+    {
+        private const int OffsetFromTopRightCorner = 38;
+
+        private readonly IApplicationPaths _appPaths;
+        private readonly IHttpClient _iHttpClient;
+        private readonly IFileSystem _fileSystem;
+
+        public UnplayedCountIndicator(IApplicationPaths appPaths, IHttpClient iHttpClient, IFileSystem fileSystem)
+        {
+            _appPaths = appPaths;
+            _iHttpClient = iHttpClient;
+            _fileSystem = fileSystem;
+        }
+
+        public void DrawUnplayedCountIndicator(SKCanvas canvas, ImageSize imageSize, int count)
+        {
+            var x = imageSize.Width - OffsetFromTopRightCorner;
+            var text = count.ToString(CultureInfo.InvariantCulture);
+
+            using (var paint = new SKPaint())
+            {
+                paint.Color = SKColor.Parse("#CC52B54B");
+                paint.Style = SKPaintStyle.Fill;
+                canvas.DrawCircle((float)x, OffsetFromTopRightCorner, 20, paint);
+            }
+            using (var paint = new SKPaint())
+            {
+                paint.Color = new SKColor(255, 255, 255, 255);
+                paint.Style = SKPaintStyle.Fill;
+                paint.Typeface = SKTypeface.FromFile(PlayedIndicatorDrawer.ExtractFont("robotoregular.ttf", _appPaths, _fileSystem));
+                paint.TextSize = 24;
+                paint.IsAntialias = true;
+
+                var y = OffsetFromTopRightCorner + 9;
+
+                if (text.Length == 1)
+                {
+                    x -= 7;
+                }
+                if (text.Length == 2)
+                {
+                    x -= 13;
+                }
+                else if (text.Length >= 3)
+                {
+                    x -= 15;
+                    y -= 2;
+                    paint.TextSize = 18;
+                }
+
+                canvas.DrawText(text, (float)x, y, paint);
+            }
+        }
+    }
+}

+ 4 - 0
Emby.Drawing.Skia/packages.config

@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+  <package id="SkiaSharp" version="1.57.1" targetFramework="portable45-net45+win8" />
+</packages>

+ 52 - 81
Emby.Drawing/ImageProcessor.cs

@@ -56,7 +56,7 @@ namespace Emby.Drawing
         private readonly IFileSystem _fileSystem;
         private readonly IFileSystem _fileSystem;
         private readonly IJsonSerializer _jsonSerializer;
         private readonly IJsonSerializer _jsonSerializer;
         private readonly IServerApplicationPaths _appPaths;
         private readonly IServerApplicationPaths _appPaths;
-        private readonly IImageEncoder _imageEncoder;
+        private IImageEncoder _imageEncoder;
         private readonly Func<ILibraryManager> _libraryManager;
         private readonly Func<ILibraryManager> _libraryManager;
 
 
         public ImageProcessor(ILogger logger,
         public ImageProcessor(ILogger logger,
@@ -64,7 +64,7 @@ namespace Emby.Drawing
             IFileSystem fileSystem,
             IFileSystem fileSystem,
             IJsonSerializer jsonSerializer,
             IJsonSerializer jsonSerializer,
             IImageEncoder imageEncoder,
             IImageEncoder imageEncoder,
-            int maxConcurrentImageProcesses, Func<ILibraryManager> libraryManager, ITimerFactory timerFactory)
+            Func<ILibraryManager> libraryManager, ITimerFactory timerFactory)
         {
         {
             _logger = logger;
             _logger = logger;
             _fileSystem = fileSystem;
             _fileSystem = fileSystem;
@@ -103,6 +103,20 @@ namespace Emby.Drawing
             _cachedImagedSizes = new ConcurrentDictionary<Guid, ImageSize>(sizeDictionary);
             _cachedImagedSizes = new ConcurrentDictionary<Guid, ImageSize>(sizeDictionary);
         }
         }
 
 
+        public IImageEncoder ImageEncoder
+        {
+            get { return _imageEncoder; }
+            set
+            {
+                if (value == null)
+                {
+                    throw new ArgumentNullException("value");
+                }
+
+                _imageEncoder = value;
+            }
+        }
+
         public string[] SupportedInputFormats
         public string[] SupportedInputFormats
         {
         {
             get
             get
@@ -136,14 +150,6 @@ namespace Emby.Drawing
             }
             }
         }
         }
 
 
-        private string CroppedWhitespaceImageCachePath
-        {
-            get
-            {
-                return Path.Combine(_appPaths.ImageCachePath, "cropped-images");
-            }
-        }
-
         public void AddParts(IEnumerable<IImageEnhancer> enhancers)
         public void AddParts(IEnumerable<IImageEnhancer> enhancers)
         {
         {
             ImageEnhancers = enhancers.ToArray();
             ImageEnhancers = enhancers.ToArray();
@@ -186,14 +192,6 @@ namespace Emby.Drawing
                 return new Tuple<string, string, DateTime>(originalImagePath, MimeTypes.GetMimeType(originalImagePath), dateModified);
                 return new Tuple<string, string, DateTime>(originalImagePath, MimeTypes.GetMimeType(originalImagePath), dateModified);
             }
             }
 
 
-            if (options.CropWhiteSpace && _imageEncoder.SupportsImageEncoding)
-            {
-                var tuple = await GetWhitespaceCroppedImage(originalImagePath, dateModified).ConfigureAwait(false);
-
-                originalImagePath = tuple.Item1;
-                dateModified = tuple.Item2;
-            }
-
             if (options.Enhancers.Count > 0)
             if (options.Enhancers.Count > 0)
             {
             {
                 var tuple = await GetEnhancedImage(new ItemImageInfo
                 var tuple = await GetEnhancedImage(new ItemImageInfo
@@ -214,7 +212,7 @@ namespace Emby.Drawing
                 return new Tuple<string, string, DateTime>(originalImagePath, MimeTypes.GetMimeType(originalImagePath), dateModified);
                 return new Tuple<string, string, DateTime>(originalImagePath, MimeTypes.GetMimeType(originalImagePath), dateModified);
             }
             }
 
 
-            ImageSize? originalImageSize;
+            ImageSize? originalImageSize = null;
             try
             try
             {
             {
                 originalImageSize = GetImageSize(originalImagePath, dateModified, true);
                 originalImageSize = GetImageSize(originalImagePath, dateModified, true);
@@ -241,8 +239,8 @@ namespace Emby.Drawing
 
 
                 if (!_fileSystem.FileExists(cacheFilePath))
                 if (!_fileSystem.FileExists(cacheFilePath))
                 {
                 {
-                    var newWidth = Convert.ToInt32(newSize.Width);
-                    var newHeight = Convert.ToInt32(newSize.Height);
+                    var newWidth = Convert.ToInt32(Math.Round(newSize.Width));
+                    var newHeight = Convert.ToInt32(Math.Round(newSize.Height));
 
 
                     _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(cacheFilePath));
                     _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(cacheFilePath));
                     var tmpPath = Path.ChangeExtension(Path.Combine(_appPaths.TempDirectory, Guid.NewGuid().ToString("N")), Path.GetExtension(cacheFilePath));
                     var tmpPath = Path.ChangeExtension(Path.Combine(_appPaths.TempDirectory, Guid.NewGuid().ToString("N")), Path.GetExtension(cacheFilePath));
@@ -349,22 +347,22 @@ namespace Emby.Drawing
                 return new ImageSize(options.Width.Value, options.Height.Value);
                 return new ImageSize(options.Width.Value, options.Height.Value);
             }
             }
 
 
-            var aspect = GetEstimatedAspectRatio(options.Image.Type);
+            var aspect = GetEstimatedAspectRatio(options.Image.Type, options.Item);
 
 
             var width = options.Width ?? options.MaxWidth;
             var width = options.Width ?? options.MaxWidth;
 
 
             if (width.HasValue)
             if (width.HasValue)
             {
             {
-                var heightValue = aspect / width.Value;
-                return new ImageSize(width.Value, Convert.ToInt32(heightValue));
+                var heightValue = width.Value / aspect;
+                return new ImageSize(width.Value, heightValue);
             }
             }
 
 
             var height = options.Height ?? options.MaxHeight ?? 200;
             var height = options.Height ?? options.MaxHeight ?? 200;
             var widthValue = aspect * height;
             var widthValue = aspect * height;
-            return new ImageSize(Convert.ToInt32(widthValue), height);
+            return new ImageSize(widthValue, height);
         }
         }
 
 
-        private double GetEstimatedAspectRatio(ImageType type)
+        private double GetEstimatedAspectRatio(ImageType type, IHasImages item)
         {
         {
             switch (type)
             switch (type)
             {
             {
@@ -384,7 +382,7 @@ namespace Emby.Drawing
                 case ImageType.Logo:
                 case ImageType.Logo:
                     return 2.58;
                     return 2.58;
                 case ImageType.Primary:
                 case ImageType.Primary:
-                    return .667;
+                    return item.GetDefaultPrimaryImageAspectRatio() ?? .667;
                 default:
                 default:
                     return 1;
                     return 1;
             }
             }
@@ -400,46 +398,6 @@ namespace Emby.Drawing
             return requestedFormat;
             return requestedFormat;
         }
         }
 
 
-        /// <summary>
-        /// Crops whitespace from an image, caches the result, and returns the cached path
-        /// </summary>
-        private async Task<Tuple<string, DateTime>> GetWhitespaceCroppedImage(string originalImagePath, DateTime dateModified)
-        {
-            var name = originalImagePath;
-            name += "datemodified=" + dateModified.Ticks;
-
-            var croppedImagePath = GetCachePath(CroppedWhitespaceImageCachePath, name, Path.GetExtension(originalImagePath));
-
-            // Check again in case of contention
-            if (_fileSystem.FileExists(croppedImagePath))
-            {
-                return GetResult(croppedImagePath);
-            }
-
-            try
-            {
-                _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(croppedImagePath));
-                var tmpPath = Path.ChangeExtension(Path.Combine(_appPaths.TempDirectory, Guid.NewGuid().ToString("N")), Path.GetExtension(croppedImagePath));
-                _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(tmpPath));
-
-                _imageEncoder.CropWhiteSpace(originalImagePath, tmpPath);
-                CopyFile(tmpPath, croppedImagePath);
-                return GetResult(tmpPath);
-            }
-            catch (NotImplementedException)
-            {
-                // No need to spam the log with an error message
-                return new Tuple<string, DateTime>(originalImagePath, dateModified);
-            }
-            catch (Exception ex)
-            {
-                // We have to have a catch-all here because some of the .net image methods throw a plain old Exception
-                _logger.ErrorException("Error cropping image {0}", ex, originalImagePath);
-
-                return new Tuple<string, DateTime>(originalImagePath, dateModified);
-            }
-        }
-
         private Tuple<string, DateTime> GetResult(string path)
         private Tuple<string, DateTime> GetResult(string path)
         {
         {
             return new Tuple<string, DateTime>(path, _fileSystem.GetLastWriteTimeUtc(path));
             return new Tuple<string, DateTime>(path, _fileSystem.GetLastWriteTimeUtc(path));
@@ -555,26 +513,39 @@ namespace Emby.Drawing
         /// <returns>ImageSize.</returns>
         /// <returns>ImageSize.</returns>
         private ImageSize GetImageSizeInternal(string path, bool allowSlowMethod)
         private ImageSize GetImageSizeInternal(string path, bool allowSlowMethod)
         {
         {
+            // Can't use taglib because it keeps a lock on the file
+            //try
+            //{
+            //    using (var file = TagLib.File.Create(new StreamFileAbstraction(Path.GetFileName(path), _fileSystem.OpenRead(path), null)))
+            //    {
+            //        var image = file as TagLib.Image.File;
+
+            //        var properties = image.Properties;
+
+            //        return new ImageSize
+            //        {
+            //            Height = properties.PhotoHeight,
+            //            Width = properties.PhotoWidth
+            //        };
+            //    }
+            //}
+            //catch
+            //{
+            //}
+
             try
             try
             {
             {
-                using (var file = TagLib.File.Create(new StreamFileAbstraction(Path.GetFileName(path), _fileSystem.OpenRead(path), null)))
-                {
-                    var image = file as TagLib.Image.File;
-
-                    var properties = image.Properties;
-
-                    return new ImageSize
-                    {
-                        Height = properties.PhotoHeight,
-                        Width = properties.PhotoWidth
-                    };
-                }
+                return ImageHeader.GetDimensions(path, _logger, _fileSystem);
             }
             }
             catch
             catch
             {
             {
-            }
+                if (allowSlowMethod)
+                {
+                    return _imageEncoder.GetImageSize(path);
+                }
 
 
-            return ImageHeader.GetDimensions(path, _logger, _fileSystem);
+                throw;
+            }
         }
         }
 
 
         private readonly ITimer _saveImageSizeTimer;
         private readonly ITimer _saveImageSizeTimer;

+ 5 - 0
Emby.Drawing/NullImageEncoder.cs

@@ -57,6 +57,11 @@ namespace Emby.Drawing
             get { return false; }
             get { return false; }
         }
         }
 
 
+        public ImageSize GetImageSize(string path)
+        {
+            throw new NotImplementedException();
+        }
+
         public void Dispose()
         public void Dispose()
         {
         {
         }
         }

+ 8 - 11
Emby.Server.Core/ApplicationHost.cs

@@ -187,7 +187,7 @@ namespace Emby.Server.Core
         /// <value>The HTTP server.</value>
         /// <value>The HTTP server.</value>
         private IHttpServer HttpServer { get; set; }
         private IHttpServer HttpServer { get; set; }
         private IDtoService DtoService { get; set; }
         private IDtoService DtoService { get; set; }
-        private IImageProcessor ImageProcessor { get; set; }
+        public IImageProcessor ImageProcessor { get; set; }
 
 
         /// <summary>
         /// <summary>
         /// Gets or sets the media encoder.
         /// Gets or sets the media encoder.
@@ -761,7 +761,10 @@ namespace Emby.Server.Core
                     return null;
                     return null;
                 }
                 }
 
 
-                X509Certificate2 localCert = new X509Certificate2(certificateLocation, info.Password);
+                // Don't use an empty string password
+                var password = string.IsNullOrWhiteSpace(info.Password) ? null : info.Password;
+
+                X509Certificate2 localCert = new X509Certificate2(certificateLocation, password);
                 //localCert.PrivateKey = PrivateKey.CreateFromFile(pvk_file).RSA;
                 //localCert.PrivateKey = PrivateKey.CreateFromFile(pvk_file).RSA;
                 if (!localCert.HasPrivateKey)
                 if (!localCert.HasPrivateKey)
                 {
                 {
@@ -780,14 +783,7 @@ namespace Emby.Server.Core
 
 
         private IImageProcessor GetImageProcessor()
         private IImageProcessor GetImageProcessor()
         {
         {
-            var maxConcurrentImageProcesses = Math.Max(Environment.ProcessorCount, 4);
-
-            if (StartupOptions.ContainsOption("-imagethreads"))
-            {
-                int.TryParse(StartupOptions.GetOption("-imagethreads"), NumberStyles.Any, CultureInfo.InvariantCulture, out maxConcurrentImageProcesses);
-            }
-
-            return new ImageProcessor(LogManager.GetLogger("ImageProcessor"), ServerConfigurationManager.ApplicationPaths, FileSystemManager, JsonSerializer, ImageEncoder, maxConcurrentImageProcesses, () => LibraryManager, TimerFactory);
+            return new ImageProcessor(LogManager.GetLogger("ImageProcessor"), ServerConfigurationManager.ApplicationPaths, FileSystemManager, JsonSerializer, ImageEncoder, () => LibraryManager, TimerFactory);
         }
         }
 
 
         protected virtual FFMpegInstallInfo GetFfmpegInstallInfo()
         protected virtual FFMpegInstallInfo GetFfmpegInstallInfo()
@@ -1132,7 +1128,8 @@ namespace Emby.Server.Core
                 // Custom cert
                 // Custom cert
                 return new CertificateInfo
                 return new CertificateInfo
                 {
                 {
-                    Path = ServerConfigurationManager.Configuration.CertificatePath
+                    Path = ServerConfigurationManager.Configuration.CertificatePath,
+                    Password = ServerConfigurationManager.Configuration.CertificatePassword
                 };
                 };
             }
             }
 
 

+ 1 - 1
Emby.Server.Core/IO/LibraryMonitor.cs

@@ -537,7 +537,7 @@ namespace Emby.Server.Core.IO
                     }
                     }
                 }
                 }
 
 
-                var newRefresher = new FileRefresher(path, _fileSystem, ConfigurationManager, LibraryManager, TaskManager, Logger, _timerFactory, _environmentInfo);
+                var newRefresher = new FileRefresher(path, _fileSystem, ConfigurationManager, LibraryManager, TaskManager, Logger, _timerFactory, _environmentInfo, LibraryManager);
                 newRefresher.Completed += NewRefresher_Completed;
                 newRefresher.Completed += NewRefresher_Completed;
                 _activeRefreshers.Add(newRefresher);
                 _activeRefreshers.Add(newRefresher);
             }
             }

+ 1 - 1
Emby.Server.Core/project.json

@@ -68,7 +68,7 @@
         "System.AppDomain": "2.0.11",
         "System.AppDomain": "2.0.11",
         "System.Globalization.Extensions": "4.3.0",
         "System.Globalization.Extensions": "4.3.0",
         "System.IO.FileSystem.Watcher": "4.3.0",
         "System.IO.FileSystem.Watcher": "4.3.0",
-        "System.Net.Security": "4.3.0",
+        "System.Net.Security": "4.3.1",
         "System.Security.Cryptography.X509Certificates": "4.3.0",
         "System.Security.Cryptography.X509Certificates": "4.3.0",
         "System.Runtime.Extensions": "4.3.0",
         "System.Runtime.Extensions": "4.3.0",
         "MediaBrowser.Model": {
         "MediaBrowser.Model": {

+ 2 - 2
Emby.Server.Implementations/Activity/ActivityRepository.cs

@@ -60,7 +60,7 @@ namespace Emby.Server.Implementations.Activity
                     {
                     {
                         using (var statement = db.PrepareStatement("replace into ActivityLogEntries (Id, Name, Overview, ShortOverview, Type, ItemId, UserId, DateCreated, LogSeverity) values (@Id, @Name, @Overview, @ShortOverview, @Type, @ItemId, @UserId, @DateCreated, @LogSeverity)"))
                         using (var statement = db.PrepareStatement("replace into ActivityLogEntries (Id, Name, Overview, ShortOverview, Type, ItemId, UserId, DateCreated, LogSeverity) values (@Id, @Name, @Overview, @ShortOverview, @Type, @ItemId, @UserId, @DateCreated, @LogSeverity)"))
                         {
                         {
-                            statement.TryBind("@Id", entry.Id.ToGuidParamValue());
+                            statement.TryBind("@Id", entry.Id.ToGuidBlob());
                             statement.TryBind("@Name", entry.Name);
                             statement.TryBind("@Name", entry.Name);
 
 
                             statement.TryBind("@Overview", entry.Overview);
                             statement.TryBind("@Overview", entry.Overview);
@@ -168,7 +168,7 @@ namespace Emby.Server.Implementations.Activity
 
 
             var info = new ActivityLogEntry
             var info = new ActivityLogEntry
             {
             {
-                Id = reader[index].ReadGuid().ToString("N")
+                Id = reader[index].ReadGuidFromBlob().ToString("N")
             };
             };
 
 
             index++;
             index++;

+ 2 - 2
Emby.Server.Implementations/AppBase/BaseConfigurationManager.cs

@@ -126,7 +126,7 @@ namespace Emby.Server.Implementations.AppBase
             Logger.Info("Saving system configuration");
             Logger.Info("Saving system configuration");
             var path = CommonApplicationPaths.SystemConfigurationFilePath;
             var path = CommonApplicationPaths.SystemConfigurationFilePath;
 
 
-            FileSystem.CreateDirectory(Path.GetDirectoryName(path));
+            FileSystem.CreateDirectory(FileSystem.GetDirectoryName(path));
 
 
             lock (_configurationSyncLock)
             lock (_configurationSyncLock)
             {
             {
@@ -293,7 +293,7 @@ namespace Emby.Server.Implementations.AppBase
             _configurations.AddOrUpdate(key, configuration, (k, v) => configuration);
             _configurations.AddOrUpdate(key, configuration, (k, v) => configuration);
 
 
             var path = GetConfigurationFile(key);
             var path = GetConfigurationFile(key);
-            FileSystem.CreateDirectory(Path.GetDirectoryName(path));
+            FileSystem.CreateDirectory(FileSystem.GetDirectoryName(path));
 
 
             lock (_configurationSyncLock)
             lock (_configurationSyncLock)
             {
             {

+ 1 - 1
Emby.Server.Implementations/AppBase/ConfigurationHelper.cs

@@ -47,7 +47,7 @@ namespace Emby.Server.Implementations.AppBase
                 // If the file didn't exist before, or if something has changed, re-save
                 // If the file didn't exist before, or if something has changed, re-save
                 if (buffer == null || !buffer.SequenceEqual(newBytes))
                 if (buffer == null || !buffer.SequenceEqual(newBytes))
                 {
                 {
-                    fileSystem.CreateDirectory(Path.GetDirectoryName(path));
+                    fileSystem.CreateDirectory(fileSystem.GetDirectoryName(path));
 
 
                     // Save it after load in case we got new items
                     // Save it after load in case we got new items
                     fileSystem.WriteAllBytes(path, newBytes);
                     fileSystem.WriteAllBytes(path, newBytes);

+ 5 - 5
Emby.Server.Implementations/Data/SqliteDisplayPreferencesRepository.cs

@@ -106,8 +106,8 @@ namespace Emby.Server.Implementations.Data
 
 
             using (var statement = connection.PrepareStatement("replace into userdisplaypreferences (id, userid, client, data) values (@id, @userId, @client, @data)"))
             using (var statement = connection.PrepareStatement("replace into userdisplaypreferences (id, userid, client, data) values (@id, @userId, @client, @data)"))
             {
             {
-                statement.TryBind("@id", displayPreferences.Id.ToGuidParamValue());
-                statement.TryBind("@userId", userId.ToGuidParamValue());
+                statement.TryBind("@id", displayPreferences.Id.ToGuidBlob());
+                statement.TryBind("@userId", userId.ToGuidBlob());
                 statement.TryBind("@client", client);
                 statement.TryBind("@client", client);
                 statement.TryBind("@data", serialized);
                 statement.TryBind("@data", serialized);
 
 
@@ -170,8 +170,8 @@ namespace Emby.Server.Implementations.Data
                 {
                 {
                     using (var statement = connection.PrepareStatement("select data from userdisplaypreferences where id = @id and userId=@userId and client=@client"))
                     using (var statement = connection.PrepareStatement("select data from userdisplaypreferences where id = @id and userId=@userId and client=@client"))
                     {
                     {
-                        statement.TryBind("@id", guidId.ToGuidParamValue());
-                        statement.TryBind("@userId", userId.ToGuidParamValue());
+                        statement.TryBind("@id", guidId.ToGuidBlob());
+                        statement.TryBind("@userId", userId.ToGuidBlob());
                         statement.TryBind("@client", client);
                         statement.TryBind("@client", client);
 
 
                         foreach (var row in statement.ExecuteQuery())
                         foreach (var row in statement.ExecuteQuery())
@@ -204,7 +204,7 @@ namespace Emby.Server.Implementations.Data
                 {
                 {
                     using (var statement = connection.PrepareStatement("select data from userdisplaypreferences where userId=@userId"))
                     using (var statement = connection.PrepareStatement("select data from userdisplaypreferences where userId=@userId"))
                     {
                     {
-                        statement.TryBind("@userId", userId.ToGuidParamValue());
+                        statement.TryBind("@userId", userId.ToGuidBlob());
 
 
                         foreach (var row in statement.ExecuteQuery())
                         foreach (var row in statement.ExecuteQuery())
                         {
                         {

+ 6 - 6
Emby.Server.Implementations/Data/SqliteExtensions.cs

@@ -26,17 +26,17 @@ namespace Emby.Server.Implementations.Data
             });
             });
         }
         }
 
 
-        public static byte[] ToGuidParamValue(this string str)
+        public static byte[] ToGuidBlob(this string str)
         {
         {
-            return ToGuidParamValue(new Guid(str));
+            return ToGuidBlob(new Guid(str));
         }
         }
 
 
-        public static byte[] ToGuidParamValue(this Guid guid)
+        public static byte[] ToGuidBlob(this Guid guid)
         {
         {
             return guid.ToByteArray();
             return guid.ToByteArray();
         }
         }
 
 
-        public static Guid ReadGuid(this IResultSetValue result)
+        public static Guid ReadGuidFromBlob(this IResultSetValue result)
         {
         {
             return new Guid(result.ToBlob());
             return new Guid(result.ToBlob());
         }
         }
@@ -172,7 +172,7 @@ namespace Emby.Server.Implementations.Data
 
 
         public static Guid GetGuid(this IReadOnlyList<IResultSetValue> result, int index)
         public static Guid GetGuid(this IReadOnlyList<IResultSetValue> result, int index)
         {
         {
-            return result[index].ReadGuid();
+            return result[index].ReadGuidFromBlob();
         }
         }
 
 
         private static void CheckName(string name)
         private static void CheckName(string name)
@@ -262,7 +262,7 @@ namespace Emby.Server.Implementations.Data
             IBindParameter bindParam;
             IBindParameter bindParam;
             if (statement.BindParameters.TryGetValue(name, out bindParam))
             if (statement.BindParameters.TryGetValue(name, out bindParam))
             {
             {
-                bindParam.Bind(value.ToGuidParamValue());
+                bindParam.Bind(value.ToGuidBlob());
             }
             }
             else
             else
             {
             {

+ 4 - 4
Emby.Server.Implementations/Data/SqliteFileOrganizationRepository.cs

@@ -62,7 +62,7 @@ namespace Emby.Server.Implementations.Data
 
 
                         using (var statement = db.PrepareStatement(commandText))
                         using (var statement = db.PrepareStatement(commandText))
                         {
                         {
-                            statement.TryBind("@ResultId", result.Id.ToGuidParamValue());
+                            statement.TryBind("@ResultId", result.Id.ToGuidBlob());
                             statement.TryBind("@OriginalPath", result.OriginalPath);
                             statement.TryBind("@OriginalPath", result.OriginalPath);
 
 
                             statement.TryBind("@TargetPath", result.TargetPath);
                             statement.TryBind("@TargetPath", result.TargetPath);
@@ -100,7 +100,7 @@ namespace Emby.Server.Implementations.Data
                     {
                     {
                         using (var statement = db.PrepareStatement("delete from FileOrganizerResults where ResultId = @ResultId"))
                         using (var statement = db.PrepareStatement("delete from FileOrganizerResults where ResultId = @ResultId"))
                         {
                         {
-                            statement.TryBind("@ResultId", id.ToGuidParamValue());
+                            statement.TryBind("@ResultId", id.ToGuidBlob());
                             statement.MoveNext();
                             statement.MoveNext();
                         }
                         }
                     }, TransactionMode);
                     }, TransactionMode);
@@ -188,7 +188,7 @@ namespace Emby.Server.Implementations.Data
                 {
                 {
                     using (var statement = connection.PrepareStatement("select ResultId, OriginalPath, TargetPath, FileLength, OrganizationDate, Status, OrganizationType, StatusMessage, ExtractedName, ExtractedYear, ExtractedSeasonNumber, ExtractedEpisodeNumber, ExtractedEndingEpisodeNumber, DuplicatePaths from FileOrganizerResults where ResultId=@ResultId"))
                     using (var statement = connection.PrepareStatement("select ResultId, OriginalPath, TargetPath, FileLength, OrganizationDate, Status, OrganizationType, StatusMessage, ExtractedName, ExtractedYear, ExtractedSeasonNumber, ExtractedEpisodeNumber, ExtractedEndingEpisodeNumber, DuplicatePaths from FileOrganizerResults where ResultId=@ResultId"))
                     {
                     {
-                        statement.TryBind("@ResultId", id.ToGuidParamValue());
+                        statement.TryBind("@ResultId", id.ToGuidBlob());
 
 
                         foreach (var row in statement.ExecuteQuery())
                         foreach (var row in statement.ExecuteQuery())
                         {
                         {
@@ -207,7 +207,7 @@ namespace Emby.Server.Implementations.Data
 
 
             var result = new FileOrganizationResult
             var result = new FileOrganizationResult
             {
             {
-                Id = reader[0].ReadGuid().ToString("N")
+                Id = reader[0].ReadGuidFromBlob().ToString("N")
             };
             };
 
 
             index++;
             index++;

+ 28 - 28
Emby.Server.Implementations/Data/SqliteItemRepository.cs

@@ -2128,7 +2128,7 @@ namespace Emby.Server.Implementations.Data
                     connection.RunInTransaction(db =>
                     connection.RunInTransaction(db =>
                     {
                     {
                         // First delete chapters
                         // First delete chapters
-                        db.Execute("delete from " + ChaptersTableName + " where ItemId=@ItemId", id.ToGuidParamValue());
+                        db.Execute("delete from " + ChaptersTableName + " where ItemId=@ItemId", id.ToGuidBlob());
 
 
                         using (var saveChapterStatement = PrepareStatement(db, "replace into " + ChaptersTableName + " (ItemId, ChapterIndex, StartPositionTicks, Name, ImagePath, ImageDateModified) values (@ItemId, @ChapterIndex, @StartPositionTicks, @Name, @ImagePath, @ImageDateModified)"))
                         using (var saveChapterStatement = PrepareStatement(db, "replace into " + ChaptersTableName + " (ItemId, ChapterIndex, StartPositionTicks, Name, ImagePath, ImageDateModified) values (@ItemId, @ChapterIndex, @StartPositionTicks, @Name, @ImagePath, @ImageDateModified)"))
                         {
                         {
@@ -2139,7 +2139,7 @@ namespace Emby.Server.Implementations.Data
                                     saveChapterStatement.Reset();
                                     saveChapterStatement.Reset();
                                 }
                                 }
 
 
-                                saveChapterStatement.TryBind("@ItemId", id.ToGuidParamValue());
+                                saveChapterStatement.TryBind("@ItemId", id.ToGuidBlob());
                                 saveChapterStatement.TryBind("@ChapterIndex", index);
                                 saveChapterStatement.TryBind("@ChapterIndex", index);
                                 saveChapterStatement.TryBind("@StartPositionTicks", chapter.StartPositionTicks);
                                 saveChapterStatement.TryBind("@StartPositionTicks", chapter.StartPositionTicks);
                                 saveChapterStatement.TryBind("@Name", chapter.Name);
                                 saveChapterStatement.TryBind("@Name", chapter.Name);
@@ -2919,7 +2919,7 @@ namespace Emby.Server.Implementations.Data
 
 
                         foreach (var row in statement.ExecuteQuery())
                         foreach (var row in statement.ExecuteQuery())
                         {
                         {
-                            list.Add(row[0].ReadGuid());
+                            list.Add(row[0].ReadGuidFromBlob());
                         }
                         }
                     }
                     }
 
 
@@ -3113,7 +3113,7 @@ namespace Emby.Server.Implementations.Data
 
 
                                 foreach (var row in statement.ExecuteQuery())
                                 foreach (var row in statement.ExecuteQuery())
                                 {
                                 {
-                                    list.Add(row[0].ReadGuid());
+                                    list.Add(row[0].ReadGuidFromBlob());
                                 }
                                 }
                             }
                             }
                         }
                         }
@@ -3643,7 +3643,7 @@ namespace Emby.Server.Implementations.Data
                     clauses.Add("(select Name from TypedBaseItems where guid=" + paramName + ") in (select Name from People where ItemId=Guid)");
                     clauses.Add("(select Name from TypedBaseItems where guid=" + paramName + ") in (select Name from People where ItemId=Guid)");
                     if (statement != null)
                     if (statement != null)
                     {
                     {
-                        statement.TryBind(paramName, personId.ToGuidParamValue());
+                        statement.TryBind(paramName, personId.ToGuidBlob());
                     }
                     }
                     index++;
                     index++;
                 }
                 }
@@ -3843,7 +3843,7 @@ namespace Emby.Server.Implementations.Data
                     clauses.Add("(select CleanName from TypedBaseItems where guid=" + paramName + ") in (select CleanValue from itemvalues where ItemId=Guid and Type<=1)");
                     clauses.Add("(select CleanName from TypedBaseItems where guid=" + paramName + ") in (select CleanValue from itemvalues where ItemId=Guid and Type<=1)");
                     if (statement != null)
                     if (statement != null)
                     {
                     {
-                        statement.TryBind(paramName, artistId.ToGuidParamValue());
+                        statement.TryBind(paramName, artistId.ToGuidBlob());
                     }
                     }
                     index++;
                     index++;
                 }
                 }
@@ -3862,7 +3862,7 @@ namespace Emby.Server.Implementations.Data
                     clauses.Add("Album in (select Name from typedbaseitems where guid=" + paramName + ")");
                     clauses.Add("Album in (select Name from typedbaseitems where guid=" + paramName + ")");
                     if (statement != null)
                     if (statement != null)
                     {
                     {
-                        statement.TryBind(paramName, albumId.ToGuidParamValue());
+                        statement.TryBind(paramName, albumId.ToGuidBlob());
                     }
                     }
                     index++;
                     index++;
                 }
                 }
@@ -3881,7 +3881,7 @@ namespace Emby.Server.Implementations.Data
                     clauses.Add("(select CleanName from TypedBaseItems where guid=" + paramName + ") not in (select CleanValue from itemvalues where ItemId=Guid and Type<=1)");
                     clauses.Add("(select CleanName from TypedBaseItems where guid=" + paramName + ") not in (select CleanValue from itemvalues where ItemId=Guid and Type<=1)");
                     if (statement != null)
                     if (statement != null)
                     {
                     {
-                        statement.TryBind(paramName, artistId.ToGuidParamValue());
+                        statement.TryBind(paramName, artistId.ToGuidBlob());
                     }
                     }
                     index++;
                     index++;
                 }
                 }
@@ -3900,7 +3900,7 @@ namespace Emby.Server.Implementations.Data
                     clauses.Add("(select CleanName from TypedBaseItems where guid=" + paramName + ") in (select CleanValue from itemvalues where ItemId=Guid and Type=2)");
                     clauses.Add("(select CleanName from TypedBaseItems where guid=" + paramName + ") in (select CleanValue from itemvalues where ItemId=Guid and Type=2)");
                     if (statement != null)
                     if (statement != null)
                     {
                     {
-                        statement.TryBind(paramName, genreId.ToGuidParamValue());
+                        statement.TryBind(paramName, genreId.ToGuidBlob());
                     }
                     }
                     index++;
                     index++;
                 }
                 }
@@ -3953,7 +3953,7 @@ namespace Emby.Server.Implementations.Data
                     clauses.Add("(select CleanName from TypedBaseItems where guid=" + paramName + ") in (select CleanValue from itemvalues where ItemId=Guid and Type=3)");
                     clauses.Add("(select CleanName from TypedBaseItems where guid=" + paramName + ") in (select CleanValue from itemvalues where ItemId=Guid and Type=3)");
                     if (statement != null)
                     if (statement != null)
                     {
                     {
-                        statement.TryBind(paramName, studioId.ToGuidParamValue());
+                        statement.TryBind(paramName, studioId.ToGuidBlob());
                     }
                     }
                     index++;
                     index++;
                 }
                 }
@@ -4521,22 +4521,22 @@ namespace Emby.Server.Implementations.Data
                     connection.RunInTransaction(db =>
                     connection.RunInTransaction(db =>
                     {
                     {
                         // Delete people
                         // Delete people
-                        ExecuteWithSingleParam(db, "delete from People where ItemId=@Id", id.ToGuidParamValue());
+                        ExecuteWithSingleParam(db, "delete from People where ItemId=@Id", id.ToGuidBlob());
 
 
                         // Delete chapters
                         // Delete chapters
-                        ExecuteWithSingleParam(db, "delete from " + ChaptersTableName + " where ItemId=@Id", id.ToGuidParamValue());
+                        ExecuteWithSingleParam(db, "delete from " + ChaptersTableName + " where ItemId=@Id", id.ToGuidBlob());
 
 
                         // Delete media streams
                         // Delete media streams
-                        ExecuteWithSingleParam(db, "delete from mediastreams where ItemId=@Id", id.ToGuidParamValue());
+                        ExecuteWithSingleParam(db, "delete from mediastreams where ItemId=@Id", id.ToGuidBlob());
 
 
                         // Delete ancestors
                         // Delete ancestors
-                        ExecuteWithSingleParam(db, "delete from AncestorIds where ItemId=@Id", id.ToGuidParamValue());
+                        ExecuteWithSingleParam(db, "delete from AncestorIds where ItemId=@Id", id.ToGuidBlob());
 
 
                         // Delete item values
                         // Delete item values
-                        ExecuteWithSingleParam(db, "delete from ItemValues where ItemId=@Id", id.ToGuidParamValue());
+                        ExecuteWithSingleParam(db, "delete from ItemValues where ItemId=@Id", id.ToGuidBlob());
 
 
                         // Delete the item
                         // Delete the item
-                        ExecuteWithSingleParam(db, "delete from TypedBaseItems where guid=@Id", id.ToGuidParamValue());
+                        ExecuteWithSingleParam(db, "delete from TypedBaseItems where guid=@Id", id.ToGuidBlob());
                     }, TransactionMode);
                     }, TransactionMode);
                 }
                 }
             }
             }
@@ -4643,7 +4643,7 @@ namespace Emby.Server.Implementations.Data
                 whereClauses.Add("ItemId=@ItemId");
                 whereClauses.Add("ItemId=@ItemId");
                 if (statement != null)
                 if (statement != null)
                 {
                 {
-                    statement.TryBind("@ItemId", query.ItemId.ToGuidParamValue());
+                    statement.TryBind("@ItemId", query.ItemId.ToGuidBlob());
                 }
                 }
             }
             }
             if (query.AppearsInItemId != Guid.Empty)
             if (query.AppearsInItemId != Guid.Empty)
@@ -4651,7 +4651,7 @@ namespace Emby.Server.Implementations.Data
                 whereClauses.Add("Name in (Select Name from People where ItemId=@AppearsInItemId)");
                 whereClauses.Add("Name in (Select Name from People where ItemId=@AppearsInItemId)");
                 if (statement != null)
                 if (statement != null)
                 {
                 {
-                    statement.TryBind("@AppearsInItemId", query.AppearsInItemId.ToGuidParamValue());
+                    statement.TryBind("@AppearsInItemId", query.AppearsInItemId.ToGuidBlob());
                 }
                 }
             }
             }
             var queryPersonTypes = query.PersonTypes.Where(IsValidPersonType).ToList();
             var queryPersonTypes = query.PersonTypes.Where(IsValidPersonType).ToList();
@@ -4730,14 +4730,14 @@ namespace Emby.Server.Implementations.Data
 
 
             // First delete 
             // First delete 
             deleteAncestorsStatement.Reset();
             deleteAncestorsStatement.Reset();
-            deleteAncestorsStatement.TryBind("@ItemId", itemId.ToGuidParamValue());
+            deleteAncestorsStatement.TryBind("@ItemId", itemId.ToGuidBlob());
             deleteAncestorsStatement.MoveNext();
             deleteAncestorsStatement.MoveNext();
 
 
             foreach (var ancestorId in ancestorIds)
             foreach (var ancestorId in ancestorIds)
             {
             {
                 updateAncestorsStatement.Reset();
                 updateAncestorsStatement.Reset();
-                updateAncestorsStatement.TryBind("@ItemId", itemId.ToGuidParamValue());
-                updateAncestorsStatement.TryBind("@AncestorId", ancestorId.ToGuidParamValue());
+                updateAncestorsStatement.TryBind("@ItemId", itemId.ToGuidBlob());
+                updateAncestorsStatement.TryBind("@AncestorId", ancestorId.ToGuidBlob());
                 updateAncestorsStatement.TryBind("@AncestorIdText", ancestorId.ToString("N"));
                 updateAncestorsStatement.TryBind("@AncestorIdText", ancestorId.ToString("N"));
                 updateAncestorsStatement.MoveNext();
                 updateAncestorsStatement.MoveNext();
             }
             }
@@ -5198,7 +5198,7 @@ namespace Emby.Server.Implementations.Data
             CheckDisposed();
             CheckDisposed();
 
 
             // First delete 
             // First delete 
-            db.Execute("delete from ItemValues where ItemId=@Id", itemId.ToGuidParamValue());
+            db.Execute("delete from ItemValues where ItemId=@Id", itemId.ToGuidBlob());
 
 
             using (var statement = PrepareStatement(db, "insert into ItemValues (ItemId, Type, Value, CleanValue) values (@ItemId, @Type, @Value, @CleanValue)"))
             using (var statement = PrepareStatement(db, "insert into ItemValues (ItemId, Type, Value, CleanValue) values (@ItemId, @Type, @Value, @CleanValue)"))
             {
             {
@@ -5214,7 +5214,7 @@ namespace Emby.Server.Implementations.Data
 
 
                     statement.Reset();
                     statement.Reset();
 
 
-                    statement.TryBind("@ItemId", itemId.ToGuidParamValue());
+                    statement.TryBind("@ItemId", itemId.ToGuidBlob());
                     statement.TryBind("@Type", pair.Item1);
                     statement.TryBind("@Type", pair.Item1);
                     statement.TryBind("@Value", itemValue);
                     statement.TryBind("@Value", itemValue);
 
 
@@ -5252,7 +5252,7 @@ namespace Emby.Server.Implementations.Data
                 {
                 {
                     // First delete 
                     // First delete 
                     // "delete from People where ItemId=?"
                     // "delete from People where ItemId=?"
-                    connection.Execute("delete from People where ItemId=?", itemId.ToGuidParamValue());
+                    connection.Execute("delete from People where ItemId=?", itemId.ToGuidBlob());
 
 
                     var listIndex = 0;
                     var listIndex = 0;
 
 
@@ -5266,7 +5266,7 @@ namespace Emby.Server.Implementations.Data
                                 statement.Reset();
                                 statement.Reset();
                             }
                             }
 
 
-                            statement.TryBind("@ItemId", itemId.ToGuidParamValue());
+                            statement.TryBind("@ItemId", itemId.ToGuidBlob());
                             statement.TryBind("@Name", person.Name);
                             statement.TryBind("@Name", person.Name);
                             statement.TryBind("@Role", person.Role);
                             statement.TryBind("@Role", person.Role);
                             statement.TryBind("@PersonType", person.Type);
                             statement.TryBind("@PersonType", person.Type);
@@ -5339,7 +5339,7 @@ namespace Emby.Server.Implementations.Data
 
 
                     using (var statement = PrepareStatementSafe(connection, cmdText))
                     using (var statement = PrepareStatementSafe(connection, cmdText))
                     {
                     {
-                        statement.TryBind("@ItemId", query.ItemId.ToGuidParamValue());
+                        statement.TryBind("@ItemId", query.ItemId.ToGuidBlob());
 
 
                         if (query.Type.HasValue)
                         if (query.Type.HasValue)
                         {
                         {
@@ -5383,7 +5383,7 @@ namespace Emby.Server.Implementations.Data
                 using (var connection = CreateConnection())
                 using (var connection = CreateConnection())
                 {
                 {
                     // First delete chapters
                     // First delete chapters
-                    connection.Execute("delete from mediastreams where ItemId=@ItemId", id.ToGuidParamValue());
+                    connection.Execute("delete from mediastreams where ItemId=@ItemId", id.ToGuidBlob());
 
 
                     using (var statement = PrepareStatement(connection, string.Format("replace into mediastreams ({0}) values ({1})",
                     using (var statement = PrepareStatement(connection, string.Format("replace into mediastreams ({0}) values ({1})",
                                 string.Join(",", _mediaStreamSaveColumns),
                                 string.Join(",", _mediaStreamSaveColumns),
@@ -5393,7 +5393,7 @@ namespace Emby.Server.Implementations.Data
                         {
                         {
                             var paramList = new List<object>();
                             var paramList = new List<object>();
 
 
-                            paramList.Add(id.ToGuidParamValue());
+                            paramList.Add(id.ToGuidBlob());
                             paramList.Add(stream.Index);
                             paramList.Add(stream.Index);
                             paramList.Add(stream.Type.ToString());
                             paramList.Add(stream.Type.ToString());
                             paramList.Add(stream.Codec);
                             paramList.Add(stream.Codec);

+ 4 - 4
Emby.Server.Implementations/Data/SqliteUserDataRepository.cs

@@ -213,7 +213,7 @@ namespace Emby.Server.Implementations.Data
         {
         {
             using (var statement = db.PrepareStatement("replace into userdata (key, userId, rating,played,playCount,isFavorite,playbackPositionTicks,lastPlayedDate,AudioStreamIndex,SubtitleStreamIndex) values (@key, @userId, @rating,@played,@playCount,@isFavorite,@playbackPositionTicks,@lastPlayedDate,@AudioStreamIndex,@SubtitleStreamIndex)"))
             using (var statement = db.PrepareStatement("replace into userdata (key, userId, rating,played,playCount,isFavorite,playbackPositionTicks,lastPlayedDate,AudioStreamIndex,SubtitleStreamIndex) values (@key, @userId, @rating,@played,@playCount,@isFavorite,@playbackPositionTicks,@lastPlayedDate,@AudioStreamIndex,@SubtitleStreamIndex)"))
             {
             {
-                statement.TryBind("@userId", userId.ToGuidParamValue());
+                statement.TryBind("@userId", userId.ToGuidBlob());
                 statement.TryBind("@key", key);
                 statement.TryBind("@key", key);
 
 
                 if (userData.Rating.HasValue)
                 if (userData.Rating.HasValue)
@@ -311,7 +311,7 @@ namespace Emby.Server.Implementations.Data
                 {
                 {
                     using (var statement = connection.PrepareStatement("select key,userid,rating,played,playCount,isFavorite,playbackPositionTicks,lastPlayedDate,AudioStreamIndex,SubtitleStreamIndex from userdata where key =@Key and userId=@UserId"))
                     using (var statement = connection.PrepareStatement("select key,userid,rating,played,playCount,isFavorite,playbackPositionTicks,lastPlayedDate,AudioStreamIndex,SubtitleStreamIndex from userdata where key =@Key and userId=@UserId"))
                     {
                     {
-                        statement.TryBind("@UserId", userId.ToGuidParamValue());
+                        statement.TryBind("@UserId", userId.ToGuidBlob());
                         statement.TryBind("@Key", key);
                         statement.TryBind("@Key", key);
 
 
                         foreach (var row in statement.ExecuteQuery())
                         foreach (var row in statement.ExecuteQuery())
@@ -364,7 +364,7 @@ namespace Emby.Server.Implementations.Data
                 {
                 {
                     using (var statement = connection.PrepareStatement("select key,userid,rating,played,playCount,isFavorite,playbackPositionTicks,lastPlayedDate,AudioStreamIndex,SubtitleStreamIndex from userdata where userId=@UserId"))
                     using (var statement = connection.PrepareStatement("select key,userid,rating,played,playCount,isFavorite,playbackPositionTicks,lastPlayedDate,AudioStreamIndex,SubtitleStreamIndex from userdata where userId=@UserId"))
                     {
                     {
-                        statement.TryBind("@UserId", userId.ToGuidParamValue());
+                        statement.TryBind("@UserId", userId.ToGuidBlob());
 
 
                         foreach (var row in statement.ExecuteQuery())
                         foreach (var row in statement.ExecuteQuery())
                         {
                         {
@@ -386,7 +386,7 @@ namespace Emby.Server.Implementations.Data
             var userData = new UserItemData();
             var userData = new UserItemData();
 
 
             userData.Key = reader[0].ToString();
             userData.Key = reader[0].ToString();
-            userData.UserId = reader[1].ReadGuid();
+            userData.UserId = reader[1].ReadGuidFromBlob();
 
 
             if (reader[2].SQLiteType != SQLiteType.Null)
             if (reader[2].SQLiteType != SQLiteType.Null)
             {
             {

+ 3 - 3
Emby.Server.Implementations/Data/SqliteUserRepository.cs

@@ -93,7 +93,7 @@ namespace Emby.Server.Implementations.Data
                     {
                     {
                         using (var statement = db.PrepareStatement("replace into users (guid, data) values (@guid, @data)"))
                         using (var statement = db.PrepareStatement("replace into users (guid, data) values (@guid, @data)"))
                         {
                         {
-                            statement.TryBind("@guid", user.Id.ToGuidParamValue());
+                            statement.TryBind("@guid", user.Id.ToGuidBlob());
                             statement.TryBind("@data", serialized);
                             statement.TryBind("@data", serialized);
                             statement.MoveNext();
                             statement.MoveNext();
                         }
                         }
@@ -116,7 +116,7 @@ namespace Emby.Server.Implementations.Data
                 {
                 {
                     foreach (var row in connection.Query("select guid,data from users"))
                     foreach (var row in connection.Query("select guid,data from users"))
                     {
                     {
-                        var id = row[0].ReadGuid();
+                        var id = row[0].ReadGuidFromBlob();
 
 
                         using (var stream = _memoryStreamProvider.CreateNew(row[1].ToBlob()))
                         using (var stream = _memoryStreamProvider.CreateNew(row[1].ToBlob()))
                         {
                         {
@@ -156,7 +156,7 @@ namespace Emby.Server.Implementations.Data
                     {
                     {
                         using (var statement = db.PrepareStatement("delete from users where guid=@id"))
                         using (var statement = db.PrepareStatement("delete from users where guid=@id"))
                         {
                         {
-                            statement.TryBind("@id", user.Id.ToGuidParamValue());
+                            statement.TryBind("@id", user.Id.ToGuidBlob());
                             statement.MoveNext();
                             statement.MoveNext();
                         }
                         }
                     }, TransactionMode);
                     }, TransactionMode);

+ 1 - 1
Emby.Server.Implementations/Devices/DeviceManager.cs

@@ -158,7 +158,7 @@ namespace Emby.Server.Implementations.Devices
 
 
             _libraryMonitor.ReportFileSystemChangeBeginning(path);
             _libraryMonitor.ReportFileSystemChangeBeginning(path);
 
 
-            _fileSystem.CreateDirectory(Path.GetDirectoryName(path));
+            _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(path));
 
 
             try
             try
             {
             {

+ 2 - 2
Emby.Server.Implementations/Devices/DeviceRepository.cs

@@ -46,7 +46,7 @@ namespace Emby.Server.Implementations.Devices
         public Task SaveDevice(DeviceInfo device)
         public Task SaveDevice(DeviceInfo device)
         {
         {
             var path = Path.Combine(GetDevicePath(device.Id), "device.json");
             var path = Path.Combine(GetDevicePath(device.Id), "device.json");
-            _fileSystem.CreateDirectory(Path.GetDirectoryName(path));
+            _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(path));
 
 
             lock (_syncLock)
             lock (_syncLock)
             {
             {
@@ -180,7 +180,7 @@ namespace Emby.Server.Implementations.Devices
         public void AddCameraUpload(string deviceId, LocalFileInfo file)
         public void AddCameraUpload(string deviceId, LocalFileInfo file)
         {
         {
             var path = Path.Combine(GetDevicePath(deviceId), "camerauploads.json");
             var path = Path.Combine(GetDevicePath(deviceId), "camerauploads.json");
-            _fileSystem.CreateDirectory(Path.GetDirectoryName(path));
+            _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(path));
 
 
             lock (_syncLock)
             lock (_syncLock)
             {
             {

+ 1 - 1
Emby.Server.Implementations/Emby.Server.Implementations.csproj

@@ -308,7 +308,7 @@
       <Private>True</Private>
       <Private>True</Private>
     </Reference>
     </Reference>
     <Reference Include="SQLitePCLRaw.core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1488e028ca7ab535, processorArchitecture=MSIL">
     <Reference Include="SQLitePCLRaw.core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1488e028ca7ab535, processorArchitecture=MSIL">
-      <HintPath>..\packages\SQLitePCLRaw.core.1.1.2\lib\portable-net45+netcore45+wpa81+MonoAndroid10+MonoTouch10+Xamarin.iOS10\SQLitePCLRaw.core.dll</HintPath>
+      <HintPath>..\packages\SQLitePCLRaw.core.1.1.5\lib\portable-net45+netcore45+wpa81+MonoAndroid10+MonoTouch10+Xamarin.iOS10\SQLitePCLRaw.core.dll</HintPath>
       <Private>True</Private>
       <Private>True</Private>
     </Reference>
     </Reference>
   </ItemGroup>
   </ItemGroup>

+ 2 - 2
Emby.Server.Implementations/FFMpeg/FFMpegLoader.cs

@@ -97,7 +97,7 @@ namespace Emby.Server.Implementations.FFMpeg
                 else
                 else
                 {
                 {
                     info = existingVersion;
                     info = existingVersion;
-                    versionedDirectoryPath = Path.GetDirectoryName(info.EncoderPath);
+                    versionedDirectoryPath = _fileSystem.GetDirectoryName(info.EncoderPath);
                     excludeFromDeletions.Add(versionedDirectoryPath);
                     excludeFromDeletions.Add(versionedDirectoryPath);
                 }
                 }
             }
             }
@@ -135,7 +135,7 @@ namespace Emby.Server.Implementations.FFMpeg
                     {
                     {
                         EncoderPath = encoder,
                         EncoderPath = encoder,
                         ProbePath = probe,
                         ProbePath = probe,
-                        Version = Path.GetFileName(Path.GetDirectoryName(probe))
+                        Version = Path.GetFileName(_fileSystem.GetDirectoryName(probe))
                     };
                     };
                 }
                 }
             }
             }

+ 6 - 3
Emby.Server.Implementations/HttpServer/HttpListenerHost.cs

@@ -228,7 +228,8 @@ namespace Emby.Server.Implementations.HttpServer
                 _streamFactory,
                 _streamFactory,
                 _enableDualModeSockets,
                 _enableDualModeSockets,
                 GetRequest,
                 GetRequest,
-                _fileSystem);
+                _fileSystem,
+                _environment);
         }
         }
 
 
         private IHttpRequest GetRequest(HttpListenerContext httpContext)
         private IHttpRequest GetRequest(HttpListenerContext httpContext)
@@ -452,6 +453,7 @@ namespace Emby.Server.Implementations.HttpServer
             var date = DateTime.Now;
             var date = DateTime.Now;
             var httpRes = httpReq.Response;
             var httpRes = httpReq.Response;
             bool enableLog = false;
             bool enableLog = false;
+            bool logHeaders = false;
             string urlToLog = null;
             string urlToLog = null;
             string remoteIp = null;
             string remoteIp = null;
 
 
@@ -490,13 +492,14 @@ namespace Emby.Server.Implementations.HttpServer
                 var urlString = url.OriginalString;
                 var urlString = url.OriginalString;
                 enableLog = EnableLogging(urlString, localPath);
                 enableLog = EnableLogging(urlString, localPath);
                 urlToLog = urlString;
                 urlToLog = urlString;
+                 logHeaders = enableLog && urlToLog.IndexOf("/videos/", StringComparison.OrdinalIgnoreCase) != -1;
 
 
                 if (enableLog)
                 if (enableLog)
                 {
                 {
                     urlToLog = GetUrlToLog(urlString);
                     urlToLog = GetUrlToLog(urlString);
                     remoteIp = httpReq.RemoteIp;
                     remoteIp = httpReq.RemoteIp;
 
 
-                    LoggerUtils.LogRequest(_logger, urlToLog, httpReq.HttpMethod, httpReq.UserAgent);
+                    LoggerUtils.LogRequest(_logger, urlToLog, httpReq.HttpMethod, httpReq.UserAgent, logHeaders ? httpReq.Headers : null);
                 }
                 }
 
 
                 if (string.Equals(localPath, "/emby/", StringComparison.OrdinalIgnoreCase) ||
                 if (string.Equals(localPath, "/emby/", StringComparison.OrdinalIgnoreCase) ||
@@ -611,7 +614,7 @@ namespace Emby.Server.Implementations.HttpServer
 
 
                     var duration = DateTime.Now - date;
                     var duration = DateTime.Now - date;
 
 
-                    LoggerUtils.LogResponse(_logger, statusCode, urlToLog, remoteIp, duration);
+                    LoggerUtils.LogResponse(_logger, statusCode, urlToLog, remoteIp, duration, logHeaders ? httpRes.Headers : null);
                 }
                 }
             }
             }
         }
         }

+ 18 - 28
Emby.Server.Implementations/HttpServer/HttpResultFactory.cs

@@ -353,31 +353,28 @@ namespace Emby.Server.Implementations.HttpServer
         /// <summary>
         /// <summary>
         /// Pres the process optimized result.
         /// Pres the process optimized result.
         /// </summary>
         /// </summary>
-        /// <param name="requestContext">The request context.</param>
-        /// <param name="responseHeaders">The responseHeaders.</param>
-        /// <param name="cacheKey">The cache key.</param>
-        /// <param name="cacheKeyString">The cache key string.</param>
-        /// <param name="lastDateModified">The last date modified.</param>
-        /// <param name="cacheDuration">Duration of the cache.</param>
-        /// <param name="contentType">Type of the content.</param>
-        /// <returns>System.Object.</returns>
         private object GetCachedResult(IRequest requestContext, IDictionary<string, string> responseHeaders, Guid cacheKey, string cacheKeyString, DateTime? lastDateModified, TimeSpan? cacheDuration, string contentType)
         private object GetCachedResult(IRequest requestContext, IDictionary<string, string> responseHeaders, Guid cacheKey, string cacheKeyString, DateTime? lastDateModified, TimeSpan? cacheDuration, string contentType)
         {
         {
             responseHeaders["ETag"] = string.Format("\"{0}\"", cacheKeyString);
             responseHeaders["ETag"] = string.Format("\"{0}\"", cacheKeyString);
 
 
-            if (IsNotModified(requestContext, cacheKey, lastDateModified, cacheDuration))
+            var noCache = (requestContext.Headers.Get("Cache-Control") ?? string.Empty).IndexOf("no-cache", StringComparison.OrdinalIgnoreCase) != -1;
+
+            if (!noCache)
             {
             {
-                AddAgeHeader(responseHeaders, lastDateModified);
-                AddExpiresHeader(responseHeaders, cacheKeyString, cacheDuration);
+                if (IsNotModified(requestContext, cacheKey, lastDateModified, cacheDuration))
+                {
+                    AddAgeHeader(responseHeaders, lastDateModified);
+                    AddExpiresHeader(responseHeaders, cacheKeyString, cacheDuration, noCache);
 
 
-                var result = new HttpResult(new byte[] { }, contentType ?? "text/html", HttpStatusCode.NotModified);
+                    var result = new HttpResult(new byte[] { }, contentType ?? "text/html", HttpStatusCode.NotModified);
 
 
-                AddResponseHeaders(result, responseHeaders);
+                    AddResponseHeaders(result, responseHeaders);
 
 
-                return result;
+                    return result;
+                }
             }
             }
 
 
-            AddCachingHeaders(responseHeaders, cacheKeyString, lastDateModified, cacheDuration);
+            AddCachingHeaders(responseHeaders, cacheKeyString, lastDateModified, cacheDuration, noCache);
 
 
             return null;
             return null;
         }
         }
@@ -673,11 +670,7 @@ namespace Emby.Server.Implementations.HttpServer
         /// <summary>
         /// <summary>
         /// Adds the caching responseHeaders.
         /// Adds the caching responseHeaders.
         /// </summary>
         /// </summary>
-        /// <param name="responseHeaders">The responseHeaders.</param>
-        /// <param name="cacheKey">The cache key.</param>
-        /// <param name="lastDateModified">The last date modified.</param>
-        /// <param name="cacheDuration">Duration of the cache.</param>
-        private void AddCachingHeaders(IDictionary<string, string> responseHeaders, string cacheKey, DateTime? lastDateModified, TimeSpan? cacheDuration)
+        private void AddCachingHeaders(IDictionary<string, string> responseHeaders, string cacheKey, DateTime? lastDateModified, TimeSpan? cacheDuration, bool noCache)
         {
         {
             // Don't specify both last modified and Etag, unless caching unconditionally. They are redundant
             // Don't specify both last modified and Etag, unless caching unconditionally. They are redundant
             // https://developers.google.com/speed/docs/best-practices/caching#LeverageBrowserCaching
             // https://developers.google.com/speed/docs/best-practices/caching#LeverageBrowserCaching
@@ -687,11 +680,11 @@ namespace Emby.Server.Implementations.HttpServer
                 responseHeaders["Last-Modified"] = lastDateModified.Value.ToString("r");
                 responseHeaders["Last-Modified"] = lastDateModified.Value.ToString("r");
             }
             }
 
 
-            if (cacheDuration.HasValue)
+            if (!noCache && cacheDuration.HasValue)
             {
             {
                 responseHeaders["Cache-Control"] = "public, max-age=" + Convert.ToInt32(cacheDuration.Value.TotalSeconds);
                 responseHeaders["Cache-Control"] = "public, max-age=" + Convert.ToInt32(cacheDuration.Value.TotalSeconds);
             }
             }
-            else if (!string.IsNullOrEmpty(cacheKey))
+            else if (!noCache && !string.IsNullOrEmpty(cacheKey))
             {
             {
                 responseHeaders["Cache-Control"] = "public";
                 responseHeaders["Cache-Control"] = "public";
             }
             }
@@ -701,18 +694,15 @@ namespace Emby.Server.Implementations.HttpServer
                 responseHeaders["pragma"] = "no-cache, no-store, must-revalidate";
                 responseHeaders["pragma"] = "no-cache, no-store, must-revalidate";
             }
             }
 
 
-            AddExpiresHeader(responseHeaders, cacheKey, cacheDuration);
+            AddExpiresHeader(responseHeaders, cacheKey, cacheDuration, noCache);
         }
         }
 
 
         /// <summary>
         /// <summary>
         /// Adds the expires header.
         /// Adds the expires header.
         /// </summary>
         /// </summary>
-        /// <param name="responseHeaders">The responseHeaders.</param>
-        /// <param name="cacheKey">The cache key.</param>
-        /// <param name="cacheDuration">Duration of the cache.</param>
-        private void AddExpiresHeader(IDictionary<string, string> responseHeaders, string cacheKey, TimeSpan? cacheDuration)
+        private void AddExpiresHeader(IDictionary<string, string> responseHeaders, string cacheKey, TimeSpan? cacheDuration, bool noCache)
         {
         {
-            if (cacheDuration.HasValue)
+            if (!noCache && cacheDuration.HasValue)
             {
             {
                 responseHeaders["Expires"] = DateTime.UtcNow.Add(cacheDuration.Value).ToString("r");
                 responseHeaders["Expires"] = DateTime.UtcNow.Add(cacheDuration.Value).ToString("r");
             }
             }

+ 16 - 4
Emby.Server.Implementations/HttpServer/LoggerUtils.cs

@@ -1,6 +1,8 @@
 using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.Logging;
 using System;
 using System;
 using System.Globalization;
 using System.Globalization;
+using System.Linq;
+using MediaBrowser.Model.Services;
 using SocketHttpListener.Net;
 using SocketHttpListener.Net;
 
 
 namespace Emby.Server.Implementations.HttpServer
 namespace Emby.Server.Implementations.HttpServer
@@ -19,9 +21,18 @@ namespace Emby.Server.Implementations.HttpServer
             logger.Info("{0} {1}. UserAgent: {2}", request.IsWebSocketRequest ? "WS" : "HTTP " + request.HttpMethod, url, request.UserAgent ?? string.Empty);
             logger.Info("{0} {1}. UserAgent: {2}", request.IsWebSocketRequest ? "WS" : "HTTP " + request.HttpMethod, url, request.UserAgent ?? string.Empty);
         }
         }
 
 
-        public static void LogRequest(ILogger logger, string url, string method, string userAgent)
+        public static void LogRequest(ILogger logger, string url, string method, string userAgent, QueryParamCollection headers)
         {
         {
-            logger.Info("{0} {1}. UserAgent: {2}", "HTTP " + method, url, userAgent ?? string.Empty);
+            if (headers == null)
+            {
+                logger.Info("{0} {1}. UserAgent: {2}", "HTTP " + method, url, userAgent ?? string.Empty);
+            }
+            else
+            {
+                var headerText = string.Join(", ", headers.Select(i => i.Name + "=" + i.Value).ToArray());
+
+                logger.Info("HTTP {0} {1}. {2}", method, url, headerText);
+            }
         }
         }
 
 
         /// <summary>
         /// <summary>
@@ -32,12 +43,13 @@ namespace Emby.Server.Implementations.HttpServer
         /// <param name="url">The URL.</param>
         /// <param name="url">The URL.</param>
         /// <param name="endPoint">The end point.</param>
         /// <param name="endPoint">The end point.</param>
         /// <param name="duration">The duration.</param>
         /// <param name="duration">The duration.</param>
-        public static void LogResponse(ILogger logger, int statusCode, string url, string endPoint, TimeSpan duration)
+        public static void LogResponse(ILogger logger, int statusCode, string url, string endPoint, TimeSpan duration, QueryParamCollection headers)
         {
         {
             var durationMs = duration.TotalMilliseconds;
             var durationMs = duration.TotalMilliseconds;
             var logSuffix = durationMs >= 1000 && durationMs < 60000 ? "ms (slow)" : "ms";
             var logSuffix = durationMs >= 1000 && durationMs < 60000 ? "ms (slow)" : "ms";
 
 
-            logger.Info("HTTP Response {0} to {1}. Time: {2}{3}. {4}", statusCode, endPoint, Convert.ToInt32(durationMs).ToString(CultureInfo.InvariantCulture), logSuffix, url);
+            var headerText = headers == null ? string.Empty : "Headers: " + string.Join(", ", headers.Where(i => i.Name.IndexOf("Access-", StringComparison.OrdinalIgnoreCase) == -1).Select(i => i.Name + "=" + i.Value).ToArray());
+            logger.Info("HTTP Response {0} to {1}. Time: {2}{3}. {4} {5}", statusCode, endPoint, Convert.ToInt32(durationMs).ToString(CultureInfo.InvariantCulture), logSuffix, url, headerText);
         }
         }
     }
     }
 }
 }

+ 5 - 2
Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs

@@ -10,6 +10,7 @@ using MediaBrowser.Model.Cryptography;
 using MediaBrowser.Model.IO;
 using MediaBrowser.Model.IO;
 using MediaBrowser.Model.Net;
 using MediaBrowser.Model.Net;
 using MediaBrowser.Model.Services;
 using MediaBrowser.Model.Services;
+using MediaBrowser.Model.System;
 using MediaBrowser.Model.Text;
 using MediaBrowser.Model.Text;
 using SocketHttpListener.Primitives;
 using SocketHttpListener.Primitives;
 
 
@@ -30,8 +31,9 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp
         private readonly IFileSystem _fileSystem;
         private readonly IFileSystem _fileSystem;
         private readonly Func<HttpListenerContext, IHttpRequest> _httpRequestFactory;
         private readonly Func<HttpListenerContext, IHttpRequest> _httpRequestFactory;
         private readonly bool _enableDualMode;
         private readonly bool _enableDualMode;
+        private readonly IEnvironmentInfo _environment;
 
 
-        public WebSocketSharpListener(ILogger logger, ICertificate certificate, IMemoryStreamFactory memoryStreamProvider, ITextEncoding textEncoding, INetworkManager networkManager, ISocketFactory socketFactory, ICryptoProvider cryptoProvider, IStreamFactory streamFactory, bool enableDualMode, Func<HttpListenerContext, IHttpRequest> httpRequestFactory, IFileSystem fileSystem)
+        public WebSocketSharpListener(ILogger logger, ICertificate certificate, IMemoryStreamFactory memoryStreamProvider, ITextEncoding textEncoding, INetworkManager networkManager, ISocketFactory socketFactory, ICryptoProvider cryptoProvider, IStreamFactory streamFactory, bool enableDualMode, Func<HttpListenerContext, IHttpRequest> httpRequestFactory, IFileSystem fileSystem, IEnvironmentInfo environment)
         {
         {
             _logger = logger;
             _logger = logger;
             _certificate = certificate;
             _certificate = certificate;
@@ -44,6 +46,7 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp
             _enableDualMode = enableDualMode;
             _enableDualMode = enableDualMode;
             _httpRequestFactory = httpRequestFactory;
             _httpRequestFactory = httpRequestFactory;
             _fileSystem = fileSystem;
             _fileSystem = fileSystem;
+            _environment = environment;
         }
         }
 
 
         public Action<Exception, IRequest, bool> ErrorHandler { get; set; }
         public Action<Exception, IRequest, bool> ErrorHandler { get; set; }
@@ -56,7 +59,7 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp
         public void Start(IEnumerable<string> urlPrefixes)
         public void Start(IEnumerable<string> urlPrefixes)
         {
         {
             if (_listener == null)
             if (_listener == null)
-                _listener = new HttpListener(_logger, _cryptoProvider, _streamFactory, _socketFactory, _networkManager, _textEncoding, _memoryStreamProvider, _fileSystem);
+                _listener = new HttpListener(_logger, _cryptoProvider, _streamFactory, _socketFactory, _networkManager, _textEncoding, _memoryStreamProvider, _fileSystem, _environment);
 
 
             _listener.EnableDualMode = _enableDualMode;
             _listener.EnableDualMode = _enableDualMode;
 
 

+ 9 - 0
Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpResponse.cs

@@ -7,6 +7,7 @@ using System.Threading;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
 using MediaBrowser.Model.IO;
 using MediaBrowser.Model.IO;
 using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.Logging;
+using MediaBrowser.Model.Services;
 using SocketHttpListener.Net;
 using SocketHttpListener.Net;
 using HttpListenerResponse = SocketHttpListener.Net.HttpListenerResponse;
 using HttpListenerResponse = SocketHttpListener.Net.HttpListenerResponse;
 using IHttpResponse = MediaBrowser.Model.Services.IHttpResponse;
 using IHttpResponse = MediaBrowser.Model.Services.IHttpResponse;
@@ -66,6 +67,14 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp
             _response.AddHeader(name, value);
             _response.AddHeader(name, value);
         }
         }
 
 
+        public QueryParamCollection Headers
+        {
+            get
+            {
+                return _response.Headers;
+            }
+        }
+
         public string GetHeader(string name)
         public string GetHeader(string name)
         {
         {
             return _response.Headers[name];
             return _response.Headers[name];

+ 9 - 1
Emby.Server.Implementations/IO/FileRefresher.cs

@@ -34,8 +34,9 @@ namespace Emby.Server.Implementations.IO
 
 
         public event EventHandler<EventArgs> Completed;
         public event EventHandler<EventArgs> Completed;
         private readonly IEnvironmentInfo _environmentInfo;
         private readonly IEnvironmentInfo _environmentInfo;
+        private readonly ILibraryManager _libraryManager;
 
 
-        public FileRefresher(string path, IFileSystem fileSystem, IServerConfigurationManager configurationManager, ILibraryManager libraryManager, ITaskManager taskManager, ILogger logger, ITimerFactory timerFactory, IEnvironmentInfo environmentInfo)
+        public FileRefresher(string path, IFileSystem fileSystem, IServerConfigurationManager configurationManager, ILibraryManager libraryManager, ITaskManager taskManager, ILogger logger, ITimerFactory timerFactory, IEnvironmentInfo environmentInfo, ILibraryManager libraryManager1)
         {
         {
             logger.Debug("New file refresher created for {0}", path);
             logger.Debug("New file refresher created for {0}", path);
             Path = path;
             Path = path;
@@ -47,6 +48,7 @@ namespace Emby.Server.Implementations.IO
             Logger = logger;
             Logger = logger;
             _timerFactory = timerFactory;
             _timerFactory = timerFactory;
             _environmentInfo = environmentInfo;
             _environmentInfo = environmentInfo;
+            _libraryManager = libraryManager1;
             AddPath(path);
             AddPath(path);
         }
         }
 
 
@@ -235,6 +237,12 @@ namespace Emby.Server.Implementations.IO
                 return false;
                 return false;
             }
             }
 
 
+            // Only try to open video files
+            if (!_libraryManager.IsVideoFile(path))
+            {
+                return false;
+            }
+
             try
             try
             {
             {
                 var data = _fileSystem.GetFileSystemInfo(path);
                 var data = _fileSystem.GetFileSystemInfo(path);

+ 1 - 1
Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs

@@ -258,7 +258,7 @@ namespace Emby.Server.Implementations.Images
                 {
                 {
                     return await CreateSquareCollage(item, itemsWithImages, outputPath).ConfigureAwait(false);
                     return await CreateSquareCollage(item, itemsWithImages, outputPath).ConfigureAwait(false);
                 }
                 }
-                if (item is Playlist || item is MusicGenre || item is Genre || item is GameGenre)
+                if (item is Playlist || item is MusicGenre || item is Genre || item is GameGenre || item is PhotoAlbum)
                 {
                 {
                     return await CreateSquareCollage(item, itemsWithImages, outputPath).ConfigureAwait(false);
                     return await CreateSquareCollage(item, itemsWithImages, outputPath).ConfigureAwait(false);
                 }
                 }

+ 1 - 0
Emby.Server.Implementations/Library/LibraryManager.cs

@@ -1197,6 +1197,7 @@ namespace Emby.Server.Implementations.Library
                 catch (OperationCanceledException)
                 catch (OperationCanceledException)
                 {
                 {
                     _logger.Info("Post-scan task cancelled: {0}", task.GetType().Name);
                     _logger.Info("Post-scan task cancelled: {0}", task.GetType().Name);
+                    throw;
                 }
                 }
                 catch (Exception ex)
                 catch (Exception ex)
                 {
                 {

+ 1 - 1
Emby.Server.Implementations/Library/Validators/ArtistsValidator.cs

@@ -63,7 +63,7 @@ namespace Emby.Server.Implementations.Library.Validators
                 catch (OperationCanceledException)
                 catch (OperationCanceledException)
                 {
                 {
                     // Don't clutter the log
                     // Don't clutter the log
-                    break;
+                    throw;
                 }
                 }
                 catch (Exception ex)
                 catch (Exception ex)
                 {
                 {

+ 1 - 1
Emby.Server.Implementations/Library/Validators/GameGenresValidator.cs

@@ -53,7 +53,7 @@ namespace Emby.Server.Implementations.Library.Validators
                 catch (OperationCanceledException)
                 catch (OperationCanceledException)
                 {
                 {
                     // Don't clutter the log
                     // Don't clutter the log
-                    break;
+                    throw;
                 }
                 }
                 catch (Exception ex)
                 catch (Exception ex)
                 {
                 {

+ 1 - 1
Emby.Server.Implementations/Library/Validators/GenresValidator.cs

@@ -54,7 +54,7 @@ namespace Emby.Server.Implementations.Library.Validators
                 catch (OperationCanceledException)
                 catch (OperationCanceledException)
                 {
                 {
                     // Don't clutter the log
                     // Don't clutter the log
-                    break;
+                    throw;
                 }
                 }
                 catch (Exception ex)
                 catch (Exception ex)
                 {
                 {

+ 1 - 1
Emby.Server.Implementations/Library/Validators/MusicGenresValidator.cs

@@ -54,7 +54,7 @@ namespace Emby.Server.Implementations.Library.Validators
                 catch (OperationCanceledException)
                 catch (OperationCanceledException)
                 {
                 {
                     // Don't clutter the log
                     // Don't clutter the log
-                    break;
+                    throw;
                 }
                 }
                 catch (Exception ex)
                 catch (Exception ex)
                 {
                 {

+ 1 - 1
Emby.Server.Implementations/Library/Validators/StudiosValidator.cs

@@ -53,7 +53,7 @@ namespace Emby.Server.Implementations.Library.Validators
                 catch (OperationCanceledException)
                 catch (OperationCanceledException)
                 {
                 {
                     // Don't clutter the log
                     // Don't clutter the log
-                    break;
+                    throw;
                 }
                 }
                 catch (Exception ex)
                 catch (Exception ex)
                 {
                 {

+ 3 - 1
Emby.Server.Implementations/Library/Validators/YearsPostScanTask.cs

@@ -26,6 +26,8 @@ namespace Emby.Server.Implementations.Library.Validators
 
 
             while (yearNumber < maxYear)
             while (yearNumber < maxYear)
             {
             {
+                cancellationToken.ThrowIfCancellationRequested();
+
                 try
                 try
                 {
                 {
                     var year = _libraryManager.GetYear(yearNumber);
                     var year = _libraryManager.GetYear(yearNumber);
@@ -35,7 +37,7 @@ namespace Emby.Server.Implementations.Library.Validators
                 catch (OperationCanceledException)
                 catch (OperationCanceledException)
                 {
                 {
                     // Don't clutter the log
                     // Don't clutter the log
-                    break;
+                    throw;
                 }
                 }
                 catch (Exception ex)
                 catch (Exception ex)
                 {
                 {

+ 9 - 9
Emby.Server.Implementations/Notifications/SqliteNotificationsRepository.cs

@@ -81,7 +81,7 @@ namespace Emby.Server.Implementations.Notifications
             }
             }
 
 
             clauses.Add("UserId=?");
             clauses.Add("UserId=?");
-            paramList.Add(query.UserId.ToGuidParamValue());
+            paramList.Add(query.UserId.ToGuidBlob());
 
 
             var whereClause = " where " + string.Join(" And ", clauses.ToArray());
             var whereClause = " where " + string.Join(" And ", clauses.ToArray());
 
 
@@ -133,7 +133,7 @@ namespace Emby.Server.Implementations.Notifications
                     using (var statement = connection.PrepareStatement("select Level from Notifications where UserId=@UserId and IsRead=@IsRead"))
                     using (var statement = connection.PrepareStatement("select Level from Notifications where UserId=@UserId and IsRead=@IsRead"))
                     {
                     {
                         statement.TryBind("@IsRead", false);
                         statement.TryBind("@IsRead", false);
-                        statement.TryBind("@UserId", userId.ToGuidParamValue());
+                        statement.TryBind("@UserId", userId.ToGuidBlob());
 
 
                         var levels = new List<NotificationLevel>();
                         var levels = new List<NotificationLevel>();
 
 
@@ -159,8 +159,8 @@ namespace Emby.Server.Implementations.Notifications
         {
         {
             var notification = new Notification
             var notification = new Notification
             {
             {
-                Id = reader[0].ReadGuid().ToString("N"),
-                UserId = reader[1].ReadGuid().ToString("N"),
+                Id = reader[0].ReadGuidFromBlob().ToString("N"),
+                UserId = reader[1].ReadGuidFromBlob().ToString("N"),
                 Date = reader[2].ReadDateTime(),
                 Date = reader[2].ReadDateTime(),
                 Name = reader[3].ToString()
                 Name = reader[3].ToString()
             };
             };
@@ -251,8 +251,8 @@ namespace Emby.Server.Implementations.Notifications
                     {
                     {
                         using (var statement = conn.PrepareStatement("replace into Notifications (Id, UserId, Date, Name, Description, Url, Level, IsRead, Category, RelatedId) values (@Id, @UserId, @Date, @Name, @Description, @Url, @Level, @IsRead, @Category, @RelatedId)"))
                         using (var statement = conn.PrepareStatement("replace into Notifications (Id, UserId, Date, Name, Description, Url, Level, IsRead, Category, RelatedId) values (@Id, @UserId, @Date, @Name, @Description, @Url, @Level, @IsRead, @Category, @RelatedId)"))
                         {
                         {
-                            statement.TryBind("@Id", notification.Id.ToGuidParamValue());
-                            statement.TryBind("@UserId", notification.UserId.ToGuidParamValue());
+                            statement.TryBind("@Id", notification.Id.ToGuidBlob());
+                            statement.TryBind("@UserId", notification.UserId.ToGuidBlob());
                             statement.TryBind("@Date", notification.Date.ToDateTimeParamValue());
                             statement.TryBind("@Date", notification.Date.ToDateTimeParamValue());
                             statement.TryBind("@Name", notification.Name);
                             statement.TryBind("@Name", notification.Name);
                             statement.TryBind("@Description", notification.Description);
                             statement.TryBind("@Description", notification.Description);
@@ -315,7 +315,7 @@ namespace Emby.Server.Implementations.Notifications
                         using (var statement = conn.PrepareStatement("update Notifications set IsRead=@IsRead where UserId=@UserId"))
                         using (var statement = conn.PrepareStatement("update Notifications set IsRead=@IsRead where UserId=@UserId"))
                         {
                         {
                             statement.TryBind("@IsRead", isRead);
                             statement.TryBind("@IsRead", isRead);
-                            statement.TryBind("@UserId", userId.ToGuidParamValue());
+                            statement.TryBind("@UserId", userId.ToGuidBlob());
 
 
                             statement.MoveNext();
                             statement.MoveNext();
                         }
                         }
@@ -337,13 +337,13 @@ namespace Emby.Server.Implementations.Notifications
                         using (var statement = conn.PrepareStatement("update Notifications set IsRead=@IsRead where UserId=@UserId and Id=@Id"))
                         using (var statement = conn.PrepareStatement("update Notifications set IsRead=@IsRead where UserId=@UserId and Id=@Id"))
                         {
                         {
                             statement.TryBind("@IsRead", isRead);
                             statement.TryBind("@IsRead", isRead);
-                            statement.TryBind("@UserId", userId.ToGuidParamValue());
+                            statement.TryBind("@UserId", userId.ToGuidBlob());
 
 
                             foreach (var id in notificationIdList)
                             foreach (var id in notificationIdList)
                             {
                             {
                                 statement.Reset();
                                 statement.Reset();
 
 
-                                statement.TryBind("@Id", id.ToGuidParamValue());
+                                statement.TryBind("@Id", id.ToGuidBlob());
 
 
                                 statement.MoveNext();
                                 statement.MoveNext();
                             }
                             }

+ 3 - 3
Emby.Server.Implementations/Security/AuthenticationRepository.cs

@@ -74,7 +74,7 @@ namespace Emby.Server.Implementations.Security
                     {
                     {
                         using (var statement = db.PrepareStatement("replace into AccessTokens (Id, AccessToken, DeviceId, AppName, AppVersion, DeviceName, UserId, IsActive, DateCreated, DateRevoked) values (@Id, @AccessToken, @DeviceId, @AppName, @AppVersion, @DeviceName, @UserId, @IsActive, @DateCreated, @DateRevoked)"))
                         using (var statement = db.PrepareStatement("replace into AccessTokens (Id, AccessToken, DeviceId, AppName, AppVersion, DeviceName, UserId, IsActive, DateCreated, DateRevoked) values (@Id, @AccessToken, @DeviceId, @AppName, @AppVersion, @DeviceName, @UserId, @IsActive, @DateCreated, @DateRevoked)"))
                         {
                         {
-                            statement.TryBind("@Id", info.Id.ToGuidParamValue());
+                            statement.TryBind("@Id", info.Id.ToGuidBlob());
                             statement.TryBind("@AccessToken", info.AccessToken);
                             statement.TryBind("@AccessToken", info.AccessToken);
 
 
                             statement.TryBind("@DeviceId", info.DeviceId);
                             statement.TryBind("@DeviceId", info.DeviceId);
@@ -259,7 +259,7 @@ namespace Emby.Server.Implementations.Security
 
 
                     using (var statement = connection.PrepareStatement(commandText))
                     using (var statement = connection.PrepareStatement(commandText))
                     {
                     {
-                        statement.BindParameters["@Id"].Bind(id.ToGuidParamValue());
+                        statement.BindParameters["@Id"].Bind(id.ToGuidBlob());
 
 
                         foreach (var row in statement.ExecuteQuery())
                         foreach (var row in statement.ExecuteQuery())
                         {
                         {
@@ -275,7 +275,7 @@ namespace Emby.Server.Implementations.Security
         {
         {
             var info = new AuthenticationInfo
             var info = new AuthenticationInfo
             {
             {
-                Id = reader[0].ReadGuid().ToString("N"),
+                Id = reader[0].ReadGuidFromBlob().ToString("N"),
                 AccessToken = reader[1].ToString()
                 AccessToken = reader[1].ToString()
             };
             };
 
 

+ 3 - 3
Emby.Server.Implementations/Social/SharingRepository.cs

@@ -61,7 +61,7 @@ namespace Emby.Server.Implementations.Social
                         var commandText = "replace into Shares (Id, ItemId, UserId, ExpirationDate) values (?, ?, ?, ?)";
                         var commandText = "replace into Shares (Id, ItemId, UserId, ExpirationDate) values (?, ?, ?, ?)";
 
 
                         db.Execute(commandText,
                         db.Execute(commandText,
-                            info.Id.ToGuidParamValue(),
+                            info.Id.ToGuidBlob(),
                             info.ItemId,
                             info.ItemId,
                             info.UserId,
                             info.UserId,
                             info.ExpirationDate.ToDateTimeParamValue());
                             info.ExpirationDate.ToDateTimeParamValue());
@@ -84,7 +84,7 @@ namespace Emby.Server.Implementations.Social
                     var commandText = "select Id, ItemId, UserId, ExpirationDate from Shares where id = ?";
                     var commandText = "select Id, ItemId, UserId, ExpirationDate from Shares where id = ?";
 
 
                     var paramList = new List<object>();
                     var paramList = new List<object>();
-                    paramList.Add(id.ToGuidParamValue());
+                    paramList.Add(id.ToGuidBlob());
 
 
                     foreach (var row in connection.Query(commandText, paramList.ToArray()))
                     foreach (var row in connection.Query(commandText, paramList.ToArray()))
                     {
                     {
@@ -100,7 +100,7 @@ namespace Emby.Server.Implementations.Social
         {
         {
             var info = new SocialShareInfo();
             var info = new SocialShareInfo();
 
 
-            info.Id = reader[0].ReadGuid().ToString("N");
+            info.Id = reader[0].ReadGuidFromBlob().ToString("N");
             info.ItemId = reader[1].ToString();
             info.ItemId = reader[1].ToString();
             info.UserId = reader[2].ToString();
             info.UserId = reader[2].ToString();
             info.ExpirationDate = reader[3].ReadDateTime();
             info.ExpirationDate = reader[3].ReadDateTime();

+ 12 - 2
Emby.Server.Implementations/Updates/InstallationManager.cs

@@ -664,9 +664,19 @@ namespace Emby.Server.Implementations.Updates
             // Remove it the quick way for now
             // Remove it the quick way for now
             _applicationHost.RemovePlugin(plugin);
             _applicationHost.RemovePlugin(plugin);
 
 
-            _logger.Info("Deleting plugin file {0}", plugin.AssemblyFilePath);
+            var path = plugin.AssemblyFilePath;
+            _logger.Info("Deleting plugin file {0}", path);
 
 
-            _fileSystem.DeleteFile(plugin.AssemblyFilePath);
+            // Make this case-insensitive to account for possible incorrect assembly naming
+            var file = _fileSystem.GetFilePaths(path)
+                .FirstOrDefault(i => string.Equals(i, path, StringComparison.OrdinalIgnoreCase));
+
+            if (!string.IsNullOrWhiteSpace(file))
+            {
+                path = file;
+            }
+
+            _fileSystem.DeleteFile(path);
 
 
             OnPluginUninstalled(plugin);
             OnPluginUninstalled(plugin);
 
 

+ 1 - 1
Emby.Server.Implementations/packages.config

@@ -3,5 +3,5 @@
   <package id="Emby.XmlTv" version="1.0.8" targetFramework="portable45-net45+win8" />
   <package id="Emby.XmlTv" version="1.0.8" targetFramework="portable45-net45+win8" />
   <package id="MediaBrowser.Naming" version="1.0.5" targetFramework="portable45-net45+win8" />
   <package id="MediaBrowser.Naming" version="1.0.5" targetFramework="portable45-net45+win8" />
   <package id="SQLitePCL.pretty" version="1.1.0" targetFramework="portable45-net45+win8" />
   <package id="SQLitePCL.pretty" version="1.1.0" targetFramework="portable45-net45+win8" />
-  <package id="SQLitePCLRaw.core" version="1.1.2" targetFramework="portable45-net45+win8" />
+  <package id="SQLitePCLRaw.core" version="1.1.5" targetFramework="portable45-net45+win8" />
 </packages>
 </packages>

+ 0 - 2
Emby.Server.sln

@@ -54,8 +54,6 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Emby.Server.Core", "Emby.Se
 EndProject
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Emby.Drawing", "Emby.Drawing\Emby.Drawing.csproj", "{08FFF49B-F175-4807-A2B5-73B0EBD9F716}"
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Emby.Drawing", "Emby.Drawing\Emby.Drawing.csproj", "{08FFF49B-F175-4807-A2B5-73B0EBD9F716}"
 EndProject
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ServiceStack", "ServiceStack\ServiceStack.csproj", "{680A1709-25EB-4D52-A87F-EE03FFD94BAA}"
-EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SocketHttpListener.Portable", "SocketHttpListener.Portable\SocketHttpListener.Portable.csproj", "{4F26D5D8-A7B0-42B3-BA42-7CB7D245934E}"
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SocketHttpListener.Portable", "SocketHttpListener.Portable\SocketHttpListener.Portable.csproj", "{4F26D5D8-A7B0-42B3-BA42-7CB7D245934E}"
 EndProject
 EndProject
 Global
 Global

+ 0 - 4
MediaBrowser.Api/MediaBrowser.Api.csproj

@@ -82,10 +82,6 @@
     <Compile Include="Reports\Model\ReportRow.cs" />
     <Compile Include="Reports\Model\ReportRow.cs" />
     <Compile Include="Reports\ReportRequests.cs" />
     <Compile Include="Reports\ReportRequests.cs" />
     <Compile Include="Reports\ReportsService.cs" />
     <Compile Include="Reports\ReportsService.cs" />
-    <Compile Include="Reports\Stat\ReportStatBuilder.cs" />
-    <Compile Include="Reports\Stat\ReportStatGroup.cs" />
-    <Compile Include="Reports\Stat\ReportStatItem.cs" />
-    <Compile Include="Reports\Stat\ReportStatResult.cs" />
     <Compile Include="Social\SharingService.cs" />
     <Compile Include="Social\SharingService.cs" />
     <Compile Include="StartupWizardService.cs" />
     <Compile Include="StartupWizardService.cs" />
     <Compile Include="Subtitles\SubtitleService.cs" />
     <Compile Include="Subtitles\SubtitleService.cs" />

+ 4 - 1
MediaBrowser.Api/Playback/BaseStreamingService.cs

@@ -671,12 +671,15 @@ namespace MediaBrowser.Api.Playback
                 request.AudioCodec = EncodingHelper.InferAudioCodec(url);
                 request.AudioCodec = EncodingHelper.InferAudioCodec(url);
             }
             }
 
 
+            var enableDlnaHeaders = !string.IsNullOrWhiteSpace(request.Params) /*||
+                                    string.Equals(Request.Headers.Get("GetContentFeatures.DLNA.ORG"), "1", StringComparison.OrdinalIgnoreCase)*/;
+
             var state = new StreamState(MediaSourceManager, Logger, TranscodingJobType)
             var state = new StreamState(MediaSourceManager, Logger, TranscodingJobType)
             {
             {
                 Request = request,
                 Request = request,
                 RequestedUrl = url,
                 RequestedUrl = url,
                 UserAgent = Request.UserAgent,
                 UserAgent = Request.UserAgent,
-                EnableDlnaHeaders = !string.IsNullOrWhiteSpace(request.Params)
+                EnableDlnaHeaders = enableDlnaHeaders
             };
             };
 
 
             var auth = AuthorizationContext.GetAuthorizationInfo(Request);
             var auth = AuthorizationContext.GetAuthorizationInfo(Request);

+ 4 - 8
MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs

@@ -879,7 +879,7 @@ namespace MediaBrowser.Api.Playback.Hls
                 // Add resolution params, if specified
                 // Add resolution params, if specified
                 if (!hasGraphicalSubs)
                 if (!hasGraphicalSubs)
                 {
                 {
-                    args += EncodingHelper.GetOutputSizeParam(state, codec, EnableCopyTs(state));
+                    args += EncodingHelper.GetOutputSizeParam(state, codec, true);
                 }
                 }
 
 
                 // This is for internal graphical subs
                 // This is for internal graphical subs
@@ -891,7 +891,7 @@ namespace MediaBrowser.Api.Playback.Hls
                 //args += " -flags -global_header";
                 //args += " -flags -global_header";
             }
             }
 
 
-            if (EnableCopyTs(state) && args.IndexOf("-copyts", StringComparison.OrdinalIgnoreCase) == -1)
+            if (args.IndexOf("-copyts", StringComparison.OrdinalIgnoreCase) == -1)
             {
             {
                 args += " -copyts";
                 args += " -copyts";
             }
             }
@@ -901,13 +901,9 @@ namespace MediaBrowser.Api.Playback.Hls
                 args += " -vsync " + state.OutputVideoSync;
                 args += " -vsync " + state.OutputVideoSync;
             }
             }
 
 
-            return args;
-        }
+            args += EncodingHelper.GetOutputFFlags(state);
 
 
-        private bool EnableCopyTs(StreamState state)
-        {
-            //return state.SubtitleStream != null && state.SubtitleStream.IsTextSubtitleStream && state.VideoRequest.SubtitleMethod == SubtitleDeliveryMethod.Encode;
-            return true;
+            return args;
         }
         }
 
 
         protected override string GetCommandLineArguments(string outputPath, StreamState state, bool isEncoding)
         protected override string GetCommandLineArguments(string outputPath, StreamState state, bool isEncoding)

+ 2 - 0
MediaBrowser.Api/Playback/Hls/VideoHlsService.cs

@@ -124,6 +124,8 @@ namespace MediaBrowser.Api.Playback.Hls
                 args += " -vsync " + state.OutputVideoSync;
                 args += " -vsync " + state.OutputVideoSync;
             }
             }
 
 
+            args += EncodingHelper.GetOutputFFlags(state);
+
             return args;
             return args;
         }
         }
 
 

+ 2 - 1
MediaBrowser.Api/Reports/Common/HeaderMetadata.cs

@@ -35,7 +35,8 @@ namespace MediaBrowser.Api.Reports
 		Tracks,
 		Tracks,
 		EpisodeSeries,
 		EpisodeSeries,
 		EpisodeSeason,
 		EpisodeSeason,
-		AudioAlbumArtist,
+        EpisodeNumber,
+        AudioAlbumArtist,
 		MusicArtist,
 		MusicArtist,
 		AudioAlbum,
 		AudioAlbum,
         Locked,
         Locked,

+ 5 - 0
MediaBrowser.Api/Reports/Common/ReportBuilderBase.cs

@@ -148,6 +148,11 @@ namespace MediaBrowser.Api.Reports
         /// <returns> The localized header. </returns>
         /// <returns> The localized header. </returns>
         protected static string GetLocalizedHeader(HeaderMetadata internalHeader)
         protected static string GetLocalizedHeader(HeaderMetadata internalHeader)
         {
         {
+            if (internalHeader == HeaderMetadata.EpisodeNumber)
+            {
+                return "Episode";
+            }
+
             string headerName = "";
             string headerName = "";
             if (internalHeader != HeaderMetadata.None)
             if (internalHeader != HeaderMetadata.None)
             {
             {

+ 10 - 3
MediaBrowser.Api/Reports/Data/ReportBuilder.cs

@@ -102,7 +102,7 @@ namespace MediaBrowser.Api.Reports
 						HeaderMetadata.Series,
 						HeaderMetadata.Series,
 						HeaderMetadata.Season,
 						HeaderMetadata.Season,
 						HeaderMetadata.SeasonNumber,
 						HeaderMetadata.SeasonNumber,
-						HeaderMetadata.DateAdded,
+                        HeaderMetadata.DateAdded,
 						HeaderMetadata.Year,
 						HeaderMetadata.Year,
 						HeaderMetadata.Genres
 						HeaderMetadata.Genres
 					};
 					};
@@ -269,10 +269,11 @@ namespace MediaBrowser.Api.Reports
                         HeaderMetadata.ImagePrimary,
                         HeaderMetadata.ImagePrimary,
                         HeaderMetadata.ImageBackdrop,
                         HeaderMetadata.ImageBackdrop,
                         HeaderMetadata.ImageLogo,
                         HeaderMetadata.ImageLogo,
-						HeaderMetadata.Name,
+                        HeaderMetadata.Name,
 						HeaderMetadata.EpisodeSeries,
 						HeaderMetadata.EpisodeSeries,
 						HeaderMetadata.Season,
 						HeaderMetadata.Season,
-						HeaderMetadata.DateAdded,
+                        HeaderMetadata.EpisodeNumber,
+                        HeaderMetadata.DateAdded,
 						HeaderMetadata.ReleaseDate,
 						HeaderMetadata.ReleaseDate,
 						HeaderMetadata.Year,
 						HeaderMetadata.Year,
 						HeaderMetadata.Genres,
 						HeaderMetadata.Genres,
@@ -450,6 +451,12 @@ namespace MediaBrowser.Api.Reports
                     internalHeader = HeaderMetadata.Season;
                     internalHeader = HeaderMetadata.Season;
                     break;
                     break;
 
 
+                case HeaderMetadata.EpisodeNumber:
+                    option.Column = (i, r) => this.GetObject<BaseItem, string>(i, (x) => x.IndexNumber == null ? "" : x.IndexNumber.ToString());
+                    //option.Header.SortField = "IndexNumber";
+                    //option.Header.HeaderFieldType = ReportFieldType.Int;
+                    break;
+
                 case HeaderMetadata.Network:
                 case HeaderMetadata.Network:
                     option.Column = (i, r) => this.GetListAsString(i.Studios);
                     option.Column = (i, r) => this.GetListAsString(i.Studios);
                     option.ItemID = (i) => this.GetStudioID(i.Studios.FirstOrDefault());
                     option.ItemID = (i) => this.GetStudioID(i.Studios.FirstOrDefault());

+ 0 - 256
MediaBrowser.Api/Reports/Stat/ReportStatBuilder.cs

@@ -1,256 +0,0 @@
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Library;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-
-namespace MediaBrowser.Api.Reports
-{
-    /// <summary> A report stat builder. </summary>
-    /// <seealso cref="T:MediaBrowser.Api.Reports.ReportBuilderBase"/>
-    public class ReportStatBuilder : ReportBuilderBase
-    {
-        #region [Constructors]
-
-        /// <summary>
-        /// Initializes a new instance of the MediaBrowser.Api.Reports.ReportStatBuilder class. </summary>
-        /// <param name="libraryManager"> Manager for library. </param>
-        public ReportStatBuilder(ILibraryManager libraryManager)
-            : base(libraryManager)
-        {
-        }
-
-        #endregion
-
-        #region [Public Methods]
-
-        /// <summary> Gets report stat result. </summary>
-        /// <param name="items"> The items. </param>
-        /// <param name="reportIncludeItemTypes"> List of types of the report include items. </param>
-        /// <param name="topItem"> The top item. </param>
-        /// <returns> The report stat result. </returns>
-        public ReportStatResult GetResult(BaseItem[] items, ReportIncludeItemTypes reportIncludeItemTypes, int topItem = 5)
-        {
-            ReportStatResult result = new ReportStatResult();
-            result = this.GetResultGenres(result, items, topItem);
-            result = this.GetResultStudios(result, items, topItem);
-            result = this.GetResultPersons(result, items, topItem);
-            result = this.GetResultProductionYears(result, items, topItem);
-            result = this.GetResultCommunityRatings(result, items, topItem);
-            result = this.GetResultParentalRatings(result, items, topItem);
-
-            switch (reportIncludeItemTypes)
-            {
-                case ReportIncludeItemTypes.Season:
-                case ReportIncludeItemTypes.Series:
-                case ReportIncludeItemTypes.MusicAlbum:
-                case ReportIncludeItemTypes.MusicArtist:
-                case ReportIncludeItemTypes.Game:
-                    break;
-                case ReportIncludeItemTypes.Movie:
-                case ReportIncludeItemTypes.BoxSet:
-
-                    break;
-                case ReportIncludeItemTypes.Book:
-                case ReportIncludeItemTypes.Episode:
-                case ReportIncludeItemTypes.Video:
-                case ReportIncludeItemTypes.MusicVideo:
-                case ReportIncludeItemTypes.Trailer:
-                case ReportIncludeItemTypes.Audio:
-                case ReportIncludeItemTypes.BaseItem:
-                default:
-                    break;
-            }
-
-            result.Groups = result.Groups.OrderByDescending(n => n.Items.Count()).ToList();
-
-            return result;
-        }
-
-        #endregion
-
-        #region [Protected Internal Methods]
-        /// <summary> Gets the headers. </summary>
-        /// <typeparam name="H"> Type of the header. </typeparam>
-        /// <param name="request"> The request. </param>
-        /// <returns> The headers. </returns>
-        /// <seealso cref="M:MediaBrowser.Api.Reports.ReportBuilderBase.GetHeaders{H}(H)"/>
-        protected internal override List<ReportHeader> GetHeaders<H>(H request)
-        {
-            throw new NotImplementedException();
-        }
-
-        #endregion
-
-        #region [Private Methods]
-
-        /// <summary> Gets the groups. </summary>
-        /// <param name="result"> The result. </param>
-        /// <param name="header"> The header. </param>
-        /// <param name="topItem"> The top item. </param>
-        /// <param name="top"> The top. </param>
-        private void GetGroups(ReportStatResult result, string header, int topItem, IEnumerable<ReportStatItem> top)
-        {
-            if (top != null && top.Count() > 0)
-            {
-                var group = new ReportStatGroup { Header = ReportStatGroup.FormatedHeader(header, topItem) };
-                group.Items.AddRange(top);
-                result.Groups.Add(group);
-            }
-        }
-
-        /// <summary> Gets result community ratings. </summary>
-        /// <param name="result"> The result. </param>
-        /// <param name="items"> The items. </param>
-        /// <param name="topItem"> The top item. </param>
-        /// <returns> The result community ratings. </returns>
-        private ReportStatResult GetResultCommunityRatings(ReportStatResult result, BaseItem[] items, int topItem = 5)
-        {
-            this.GetGroups(result, GetLocalizedHeader(HeaderMetadata.CommunityRating), topItem,
-                       items.Where(x => x.CommunityRating != null && x.CommunityRating > 0)
-                           .GroupBy(x => x.CommunityRating)
-                           .OrderByDescending(x => x.Count())
-                           .Take(topItem)
-                           .Select(x => new ReportStatItem
-                           {
-                               Name = x.Key.ToString(),
-                               Value = x.Count().ToString()
-                           })
-               );
-
-            return result;
-        }
-
-        /// <summary> Gets result genres. </summary>
-        /// <param name="result"> The result. </param>
-        /// <param name="items"> The items. </param>
-        /// <param name="topItem"> The top item. </param>
-        /// <returns> The result genres. </returns>
-        private ReportStatResult GetResultGenres(ReportStatResult result, BaseItem[] items, int topItem = 5)
-        {
-            this.GetGroups(result, GetLocalizedHeader(HeaderMetadata.Genres), topItem,
-                            items.SelectMany(x => x.Genres)
-                                .GroupBy(x => x)
-                                .OrderByDescending(x => x.Count())
-                                .Take(topItem)
-                                .Select(x => new ReportStatItem
-                                {
-                                    Name = x.Key,
-                                    Value = x.Count().ToString(),
-                                    Id = GetGenreID(x.Key)
-                                }));
-            return result;
-
-        }
-
-        /// <summary> Gets result parental ratings. </summary>
-        /// <param name="result"> The result. </param>
-        /// <param name="items"> The items. </param>
-        /// <param name="topItem"> The top item. </param>
-        /// <returns> The result parental ratings. </returns>
-        private ReportStatResult GetResultParentalRatings(ReportStatResult result, BaseItem[] items, int topItem = 5)
-        {
-            this.GetGroups(result, GetLocalizedHeader(HeaderMetadata.ParentalRatings), topItem,
-                       items.Where(x => x.OfficialRating != null)
-                           .GroupBy(x => x.OfficialRating)
-                           .OrderByDescending(x => x.Count())
-                           .Take(topItem)
-                           .Select(x => new ReportStatItem
-                           {
-                               Name = x.Key.ToString(),
-                               Value = x.Count().ToString()
-                           })
-               );
-
-            return result;
-        }
-
-        /// <summary> Gets result persons. </summary>
-        /// <param name="result"> The result. </param>
-        /// <param name="items"> The items. </param>
-        /// <param name="topItem"> The top item. </param>
-        /// <returns> The result persons. </returns>
-        private ReportStatResult GetResultPersons(ReportStatResult result, BaseItem[] items, int topItem = 5)
-        {
-            List<HeaderMetadata> t = new List<HeaderMetadata> 
-            { 
-                HeaderMetadata.Actor, 
-                HeaderMetadata.Composer, 
-                HeaderMetadata.Director, 
-                HeaderMetadata.GuestStar, 
-                HeaderMetadata.Producer,
-                HeaderMetadata.Writer, 
-                HeaderMetadata.Artist, 
-                HeaderMetadata.AlbumArtist
-            };
-            foreach (var item in t)
-            {
-                var ps = items.SelectMany(x => _libraryManager.GetPeople(x))
-                                .Where(n => n.Type == item.ToString())
-                                .GroupBy(x => x.Name)
-                                .OrderByDescending(x => x.Count())
-                                .Take(topItem);
-                if (ps != null && ps.Count() > 0)
-                    this.GetGroups(result, GetLocalizedHeader(item), topItem,
-                            ps.Select(x => new ReportStatItem
-                                    {
-                                        Name = x.Key,
-                                        Value = x.Count().ToString(),
-                                        Id = GetPersonID(x.Key)
-                                    })
-                    );
-            }
-
-            return result;
-        }
-
-        /// <summary> Gets result production years. </summary>
-        /// <param name="result"> The result. </param>
-        /// <param name="items"> The items. </param>
-        /// <param name="topItem"> The top item. </param>
-        /// <returns> The result production years. </returns>
-        private ReportStatResult GetResultProductionYears(ReportStatResult result, BaseItem[] items, int topItem = 5)
-        {
-            this.GetGroups(result, GetLocalizedHeader(HeaderMetadata.Year), topItem,
-                    items.Where(x => x.ProductionYear != null && x.ProductionYear > 0)
-                        .GroupBy(x => x.ProductionYear)
-                        .OrderByDescending(x => x.Count())
-                        .Take(topItem)
-                        .Select(x => new ReportStatItem
-                        {
-                            Name = x.Key.ToString(),
-                            Value = x.Count().ToString()
-                        })
-            );
-
-            return result;
-        }
-
-        /// <summary> Gets result studios. </summary>
-        /// <param name="result"> The result. </param>
-        /// <param name="items"> The items. </param>
-        /// <param name="topItem"> The top item. </param>
-        /// <returns> The result studios. </returns>
-        private ReportStatResult GetResultStudios(ReportStatResult result, BaseItem[] items, int topItem = 5)
-        {
-            this.GetGroups(result, GetLocalizedHeader(HeaderMetadata.Studios), topItem,
-                                    items.SelectMany(x => x.Studios)
-                                        .GroupBy(x => x)
-                                        .OrderByDescending(x => x.Count())
-                                        .Take(topItem)
-                                        .Select(x => new ReportStatItem
-                                        {
-                                            Name = x.Key,
-                                            Value = x.Count().ToString(),
-                                            Id = GetStudioID(x.Key)
-                                        })
-                    );
-
-            return result;
-
-        }
-
-        #endregion
-
-    }
-}

+ 0 - 33
MediaBrowser.Api/Reports/Stat/ReportStatGroup.cs

@@ -1,33 +0,0 @@
-using System.Collections.Generic;
-
-namespace MediaBrowser.Api.Reports
-{
-	/// <summary> A report stat group. </summary>
-	public class ReportStatGroup
-	{
-		/// <summary>
-		/// Initializes a new instance of the MediaBrowser.Api.Reports.ReportStatGroup class. </summary>
-		public ReportStatGroup()
-		{
-			Items = new List<ReportStatItem>();
-			TotalRecordCount = 0;
-		}
-
-		/// <summary> Gets or sets the header. </summary>
-		/// <value> The header. </value>
-		public string Header { get; set; }
-
-		/// <summary> Gets or sets the items. </summary>
-		/// <value> The items. </value>
-		public List<ReportStatItem> Items { get; set; }
-
-		/// <summary> Gets or sets the number of total records. </summary>
-		/// <value> The total number of record count. </value>
-		public int TotalRecordCount { get; set; }
-
-		internal static string FormatedHeader(string header, int topItem)
-		{
-			return string.Format("Top {0} {1}", topItem, header);
-		}
-	}
-}

+ 0 - 23
MediaBrowser.Api/Reports/Stat/ReportStatItem.cs

@@ -1,23 +0,0 @@
-namespace MediaBrowser.Api.Reports
-{
-	/// <summary> A report stat item. </summary>
-	public class ReportStatItem
-	{
-		/// <summary> Gets or sets the name. </summary>
-		/// <value> The name. </value>
-		public string Name { get; set; }
-
-		/// <summary> Gets or sets the image. </summary>
-		/// <value> The image. </value>
-		public string Image { get; set; }
-
-		/// <summary> Gets or sets the value. </summary>
-		/// <value> The value. </value>
-		public string Value { get; set; }
-
-		/// <summary> Gets or sets the identifier. </summary>
-		/// <value> The identifier. </value>
-		public string Id { get; set; }
-
-	}
-}

+ 0 - 24
MediaBrowser.Api/Reports/Stat/ReportStatResult.cs

@@ -1,24 +0,0 @@
-using System.Collections.Generic;
-
-namespace MediaBrowser.Api.Reports
-{
-	/// <summary> Encapsulates the result of a report stat. </summary>
-	public class ReportStatResult 
-	{
-		/// <summary>
-		/// Initializes a new instance of the MediaBrowser.Api.Reports.ReportStatResult class. </summary>
-		public ReportStatResult()
-		{
-			Groups = new List<ReportStatGroup>();
-			TotalRecordCount = 0;
-		}
-
-		/// <summary> Gets or sets the groups. </summary>
-		/// <value> The groups. </value>
-		public List<ReportStatGroup> Groups { get; set; }
-
-		/// <summary> Gets or sets the number of total records. </summary>
-		/// <value> The total number of record count. </value>
-		public int TotalRecordCount { get; set; }	
-	}
-}

+ 2 - 6
MediaBrowser.Controller/Drawing/IImageEncoder.cs

@@ -16,12 +16,6 @@ namespace MediaBrowser.Controller.Drawing
         /// <value>The supported output formats.</value>
         /// <value>The supported output formats.</value>
         ImageFormat[] SupportedOutputFormats { get; }
         ImageFormat[] SupportedOutputFormats { get; }
         /// <summary>
         /// <summary>
-        /// Crops the white space.
-        /// </summary>
-        /// <param name="inputPath">The input path.</param>
-        /// <param name="outputPath">The output path.</param>
-        void CropWhiteSpace(string inputPath, string outputPath);
-        /// <summary>
         /// Encodes the image.
         /// Encodes the image.
         /// </summary>
         /// </summary>
         /// <param name="inputPath">The input path.</param>
         /// <param name="inputPath">The input path.</param>
@@ -56,5 +50,7 @@ namespace MediaBrowser.Controller.Drawing
         /// </summary>
         /// </summary>
         /// <value><c>true</c> if [supports image encoding]; otherwise, <c>false</c>.</value>
         /// <value><c>true</c> if [supports image encoding]; otherwise, <c>false</c>.</value>
         bool SupportsImageEncoding { get; }
         bool SupportsImageEncoding { get; }
+
+        ImageSize GetImageSize(string path);
     }
     }
 }
 }

+ 2 - 0
MediaBrowser.Controller/Drawing/IImageProcessor.cs

@@ -112,5 +112,7 @@ namespace MediaBrowser.Controller.Drawing
         /// </summary>
         /// </summary>
         /// <value><c>true</c> if [supports image collage creation]; otherwise, <c>false</c>.</value>
         /// <value><c>true</c> if [supports image collage creation]; otherwise, <c>false</c>.</value>
         bool SupportsImageCollageCreation { get; }
         bool SupportsImageCollageCreation { get; }
+
+        IImageEncoder ImageEncoder { get; set; }
     }
     }
 }
 }

Unele fișiere nu au fost afișate deoarece prea multe fișiere au fost modificate în acest diff