Bläddra i källkod

consolidate emby.server.core into emby.server.implementations

Luke Pulverenti 7 år sedan
förälder
incheckning
40442f887b
100 ändrade filer med 609 tillägg och 2559 borttagningar
  1. 3 5
      Emby.Common.Implementations/Emby.Common.Implementations.csproj
  2. 12 2
      Emby.Common.Implementations/Logging/NlogManager.cs
  3. 1 1
      Emby.Common.Implementations/Networking/NetworkManager.cs
  4. 4 2
      Emby.Common.Implementations/ScheduledTasks/ScheduledTaskWorker.cs
  5. 2 2
      Emby.Common.Implementations/packages.config
  6. 18 18
      Emby.Dlna/ContentDirectory/ControlHandler.cs
  7. 3 7
      Emby.Dlna/DlnaManager.cs
  8. 2 1
      Emby.Dlna/PlayTo/Device.cs
  9. 3 2
      Emby.Dlna/Profiles/DefaultProfile.cs
  10. 1 1
      Emby.Dlna/Server/DescriptionXmlBuilder.cs
  11. 16 12
      Emby.Dlna/Service/BaseControlHandler.cs
  12. 2 4
      Emby.Drawing/ImageProcessor.cs
  13. 1 1
      Emby.Photos/PhotoProvider.cs
  14. 0 176
      Emby.Server.Core/Emby.Server.Core.csproj
  15. 0 34
      Emby.Server.Core/Properties/AssemblyInfo.cs
  16. 0 11
      Emby.Server.Core/app.config
  17. 0 6
      Emby.Server.Core/packages.config
  18. 2 1
      Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs
  19. 5 4
      Emby.Server.Implementations/Activity/ActivityRepository.cs
  20. 70 93
      Emby.Server.Implementations/ApplicationHost.cs
  21. 1 1
      Emby.Server.Implementations/ApplicationPathHelper.cs
  22. 21 18
      Emby.Server.Implementations/Channels/ChannelManager.cs
  23. 3 2
      Emby.Server.Implementations/Configuration/ServerConfigurationManager.cs
  24. 0 0
      Emby.Server.Implementations/Cryptography/ASN1.cs
  25. 0 0
      Emby.Server.Implementations/Cryptography/ASN1Convert.cs
  26. 0 0
      Emby.Server.Implementations/Cryptography/BitConverterLE.cs
  27. 0 0
      Emby.Server.Implementations/Cryptography/CertificateGenerator.cs
  28. 0 0
      Emby.Server.Implementations/Cryptography/CryptoConvert.cs
  29. 0 0
      Emby.Server.Implementations/Cryptography/PKCS1.cs
  30. 0 0
      Emby.Server.Implementations/Cryptography/PKCS12.cs
  31. 0 0
      Emby.Server.Implementations/Cryptography/PKCS7.cs
  32. 0 0
      Emby.Server.Implementations/Cryptography/PKCS8.cs
  33. 0 0
      Emby.Server.Implementations/Cryptography/PfxGenerator.cs
  34. 0 0
      Emby.Server.Implementations/Cryptography/X501Name.cs
  35. 0 0
      Emby.Server.Implementations/Cryptography/X509Builder.cs
  36. 0 0
      Emby.Server.Implementations/Cryptography/X509Certificate.cs
  37. 0 0
      Emby.Server.Implementations/Cryptography/X509CertificateBuilder.cs
  38. 0 0
      Emby.Server.Implementations/Cryptography/X509CertificateCollection.cs
  39. 0 0
      Emby.Server.Implementations/Cryptography/X509Extension.cs
  40. 0 0
      Emby.Server.Implementations/Cryptography/X509Extensions.cs
  41. 0 0
      Emby.Server.Implementations/Cryptography/X520Attributes.cs
  42. 7 18
      Emby.Server.Implementations/Data/BaseSqliteRepository.cs
  43. 61 47
      Emby.Server.Implementations/Data/SqliteItemRepository.cs
  44. 7 7
      Emby.Server.Implementations/Dto/DtoService.cs
  45. 82 2
      Emby.Server.Implementations/Emby.Server.Implementations.csproj
  46. 4 3
      Emby.Server.Implementations/EntryPoints/ExternalPortForwarding.cs
  47. 2 1
      Emby.Server.Implementations/EntryPoints/UsageEntryPoint.cs
  48. 6 11
      Emby.Server.Implementations/HttpServer/HttpListenerHost.cs
  49. 2 1
      Emby.Server.Implementations/HttpServer/LoggerUtils.cs
  50. 2 1
      Emby.Server.Implementations/HttpServer/SocketSharp/HttpUtility.cs
  51. 1 3
      Emby.Server.Implementations/HttpServerFactory.cs
  52. 1 2
      Emby.Server.Implementations/IO/LibraryMonitor.cs
  53. 1 1
      Emby.Server.Implementations/IO/MemoryStreamProvider.cs
  54. 3 7
      Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs
  55. 7 30
      Emby.Server.Implementations/Library/LibraryManager.cs
  56. 3 2
      Emby.Server.Implementations/Library/LocalTrailerPostScanTask.cs
  57. 11 11
      Emby.Server.Implementations/Library/MusicManager.cs
  58. 5 2
      Emby.Server.Implementations/Library/Resolvers/BaseVideoResolver.cs
  59. 5 7
      Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs
  60. 1 1
      Emby.Server.Implementations/Library/Resolvers/PhotoResolver.cs
  61. 5 4
      Emby.Server.Implementations/Library/Resolvers/TV/EpisodeResolver.cs
  62. 6 6
      Emby.Server.Implementations/Library/Resolvers/VideoResolver.cs
  63. 3 2
      Emby.Server.Implementations/Library/SearchEngine.cs
  64. 3 2
      Emby.Server.Implementations/Library/UserViewManager.cs
  65. 5 12
      Emby.Server.Implementations/Library/Validators/PeopleValidator.cs
  66. 1 1
      Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs
  67. 3 3
      Emby.Server.Implementations/LiveTv/LiveTvDtoService.cs
  68. 26 25
      Emby.Server.Implementations/LiveTv/LiveTvManager.cs
  69. 2 1
      Emby.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs
  70. 3 3
      Emby.Server.Implementations/Localization/LocalizationManager.cs
  71. 1 2
      Emby.Server.Implementations/Localization/TextLocalizer.cs
  72. 1 4
      Emby.Server.Implementations/Logging/ConsoleLogger.cs
  73. 7 6
      Emby.Server.Implementations/Notifications/SqliteNotificationsRepository.cs
  74. 2 1
      Emby.Server.Implementations/Notifications/WebSocketNotifier.cs
  75. 1 1
      Emby.Server.Implementations/Photos/PhotoAlbumImageProvider.cs
  76. 3 4
      Emby.Server.Implementations/Playlists/PlaylistImageProvider.cs
  77. 2 1
      Emby.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs
  78. 5 4
      Emby.Server.Implementations/Security/AuthenticationRepository.cs
  79. 3 5
      Emby.Server.Implementations/Services/ServiceController.cs
  80. 2 1
      Emby.Server.Implementations/Services/ServiceExec.cs
  81. 6 5
      Emby.Server.Implementations/Services/ServicePath.cs
  82. 3 2
      Emby.Server.Implementations/Session/SessionManager.cs
  83. 2 1
      Emby.Server.Implementations/Social/SharingRepository.cs
  84. 1 1
      Emby.Server.Implementations/SystemEvents.cs
  85. 2 2
      Emby.Server.Implementations/UserViews/CollectionFolderImageProvider.cs
  86. 4 4
      Emby.Server.Implementations/UserViews/DynamicImageProvider.cs
  87. 4 1
      Emby.Server.Implementations/packages.config
  88. 11 735
      MediaBrowser.Api/ApiEntryPoint.cs
  89. 1 1
      MediaBrowser.Api/FilterService.cs
  90. 5 2
      MediaBrowser.Api/GamesService.cs
  91. 8 5
      MediaBrowser.Api/Images/ImageService.cs
  92. 4 4
      MediaBrowser.Api/ItemUpdateService.cs
  93. 11 9
      MediaBrowser.Api/Library/LibraryService.cs
  94. 7 6
      MediaBrowser.Api/LiveTv/LiveTvService.cs
  95. 39 68
      MediaBrowser.Api/LiveTv/ProgressiveFileCopier.cs
  96. 2 2
      MediaBrowser.Api/LocalizationService.cs
  97. 1 17
      MediaBrowser.Api/MediaBrowser.Api.csproj
  98. 26 18
      MediaBrowser.Api/Movies/MoviesService.cs
  99. 7 3
      MediaBrowser.Api/Music/InstantMixService.cs
  100. 0 1024
      MediaBrowser.Api/Playback/BaseStreamingService.cs

+ 3 - 5
Emby.Common.Implementations/Emby.Common.Implementations.csproj

@@ -32,12 +32,10 @@
   </PropertyGroup>
   </PropertyGroup>
   <ItemGroup>
   <ItemGroup>
     <Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
     <Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
-      <HintPath>..\packages\NLog.4.4.11\lib\net45\NLog.dll</HintPath>
-      <Private>True</Private>
+      <HintPath>..\packages\NLog.4.4.12\lib\net45\NLog.dll</HintPath>
     </Reference>
     </Reference>
-    <Reference Include="ServiceStack.Text, Version=4.5.8.0, Culture=neutral, processorArchitecture=MSIL">
-      <HintPath>..\packages\ServiceStack.Text.4.5.8\lib\net45\ServiceStack.Text.dll</HintPath>
-      <Private>True</Private>
+    <Reference Include="ServiceStack.Text, Version=4.5.12.0, Culture=neutral, processorArchitecture=MSIL">
+      <HintPath>..\packages\ServiceStack.Text.4.5.12\lib\net45\ServiceStack.Text.dll</HintPath>
     </Reference>
     </Reference>
     <Reference Include="SharpCompress, Version=0.14.0.0, Culture=neutral, processorArchitecture=MSIL">
     <Reference Include="SharpCompress, Version=0.14.0.0, Culture=neutral, processorArchitecture=MSIL">
       <HintPath>..\packages\SharpCompress.0.14.0\lib\net45\SharpCompress.dll</HintPath>
       <HintPath>..\packages\SharpCompress.0.14.0\lib\net45\SharpCompress.dll</HintPath>

+ 12 - 2
Emby.Common.Implementations/Logging/NlogManager.cs

@@ -152,13 +152,23 @@ namespace Emby.Common.Implementations.Logging
 
 
             RemoveTarget("ApplicationLogFileWrapper");
             RemoveTarget("ApplicationLogFileWrapper");
 
 
-            var wrapper = new AsyncTargetWrapper();
+            // https://github.com/NLog/NLog/wiki/Performance
+            var wrapper = new AsyncTargetWrapper
+            {
+                OverflowAction = AsyncTargetWrapperOverflowAction.Block,
+                QueueLimit = 10000,
+                BatchSize = 500,
+                TimeToSleepBetweenBatches = 50
+            };
+
             wrapper.Name = "ApplicationLogFileWrapper";
             wrapper.Name = "ApplicationLogFileWrapper";
 
 
             var logFile = new FileTarget
             var logFile = new FileTarget
             {
             {
                 FileName = path,
                 FileName = path,
-                Layout = "${longdate} ${level} ${logger}: ${message}"
+                Layout = "${longdate} ${level} ${logger}: ${message}",
+                KeepFileOpen = true,
+                ConcurrentWrites = false
             };
             };
 
 
             logFile.Name = "ApplicationLogFile";
             logFile.Name = "ApplicationLogFile";

+ 1 - 1
Emby.Common.Implementations/Networking/NetworkManager.cs

@@ -506,7 +506,7 @@ namespace Emby.Common.Implementations.Networking
         public async Task<IpAddressInfo[]> GetHostAddressesAsync(string host)
         public async Task<IpAddressInfo[]> GetHostAddressesAsync(string host)
         {
         {
             var addresses = await Dns.GetHostAddressesAsync(host).ConfigureAwait(false);
             var addresses = await Dns.GetHostAddressesAsync(host).ConfigureAwait(false);
-            return addresses.Select(ToIpAddressInfo).ToArray();
+            return addresses.Select(ToIpAddressInfo).ToArray(addresses.Length);
         }
         }
 
 
         /// <summary>
         /// <summary>

+ 4 - 2
Emby.Common.Implementations/ScheduledTasks/ScheduledTaskWorker.cs

@@ -14,6 +14,7 @@ using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.Serialization;
 using MediaBrowser.Model.Serialization;
 using MediaBrowser.Model.System;
 using MediaBrowser.Model.System;
 using MediaBrowser.Model.Tasks;
 using MediaBrowser.Model.Tasks;
+using MediaBrowser.Model.Extensions;
 
 
 namespace Emby.Common.Implementations.ScheduledTasks
 namespace Emby.Common.Implementations.ScheduledTasks
 {
 {
@@ -274,7 +275,8 @@ namespace Emby.Common.Implementations.ScheduledTasks
         {
         {
             get
             get
             {
             {
-                return InternalTriggers.Select(i => i.Item1).ToArray();
+                var triggers = InternalTriggers;
+                return triggers.Select(i => i.Item1).ToArray(triggers.Length);
             }
             }
             set
             set
             {
             {
@@ -288,7 +290,7 @@ namespace Emby.Common.Implementations.ScheduledTasks
 
 
                 SaveTriggers(triggerList);
                 SaveTriggers(triggerList);
 
 
-                InternalTriggers = triggerList.Select(i => new Tuple<TaskTriggerInfo, ITaskTrigger>(i, GetTrigger(i))).ToArray();
+                InternalTriggers = triggerList.Select(i => new Tuple<TaskTriggerInfo, ITaskTrigger>(i, GetTrigger(i))).ToArray(triggerList.Length);
             }
             }
         }
         }
 
 

+ 2 - 2
Emby.Common.Implementations/packages.config

@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <?xml version="1.0" encoding="utf-8"?>
 <packages>
 <packages>
-  <package id="NLog" version="4.4.11" targetFramework="net46" />
-  <package id="ServiceStack.Text" version="4.5.8" targetFramework="net462" />
+  <package id="NLog" version="4.4.12" targetFramework="net46" />
+  <package id="ServiceStack.Text" version="4.5.12" targetFramework="net46" />
   <package id="SharpCompress" version="0.14.0" targetFramework="net462" />
   <package id="SharpCompress" version="0.14.0" targetFramework="net462" />
   <package id="SimpleInjector" version="4.0.8" targetFramework="net46" />
   <package id="SimpleInjector" version="4.0.8" targetFramework="net46" />
 </packages>
 </packages>

+ 18 - 18
Emby.Dlna/ContentDirectory/ControlHandler.cs

@@ -30,6 +30,7 @@ using MediaBrowser.Controller.Playlists;
 using MediaBrowser.Controller.TV;
 using MediaBrowser.Controller.TV;
 using MediaBrowser.Model.Globalization;
 using MediaBrowser.Model.Globalization;
 using MediaBrowser.Model.Xml;
 using MediaBrowser.Model.Xml;
+using MediaBrowser.Model.Extensions;
 
 
 namespace Emby.Dlna.ContentDirectory
 namespace Emby.Dlna.ContentDirectory
 {
 {
@@ -457,14 +458,14 @@ namespace Emby.Dlna.ContentDirectory
             {
             {
                 Limit = limit,
                 Limit = limit,
                 StartIndex = startIndex,
                 StartIndex = startIndex,
-                SortBy = sortOrders.ToArray(),
+                SortBy = sortOrders.ToArray(sortOrders.Count),
                 SortOrder = sort.SortOrder,
                 SortOrder = sort.SortOrder,
                 User = user,
                 User = user,
                 Recursive = true,
                 Recursive = true,
                 IsMissing = false,
                 IsMissing = false,
                 ExcludeItemTypes = new[] { typeof(Game).Name, typeof(Book).Name },
                 ExcludeItemTypes = new[] { typeof(Game).Name, typeof(Book).Name },
                 IsFolder = isFolder,
                 IsFolder = isFolder,
-                MediaTypes = mediaTypes.ToArray(),
+                MediaTypes = mediaTypes.ToArray(mediaTypes.Count),
                 DtoOptions = GetDtoOptions()
                 DtoOptions = GetDtoOptions()
             });
             });
         }
         }
@@ -508,12 +509,12 @@ namespace Emby.Dlna.ContentDirectory
                     {
                     {
                         ItemId = item.Id
                         ItemId = item.Id
 
 
-                    }).ToArray();
+                    });
 
 
                     var result = new QueryResult<ServerItem>
                     var result = new QueryResult<ServerItem>
                     {
                     {
-                        Items = items.Select(i => new ServerItem(i)).ToArray(),
-                        TotalRecordCount = items.Length
+                        Items = items.Select(i => new ServerItem(i)).ToArray(items.Count),
+                        TotalRecordCount = items.Count
                     };
                     };
 
 
                     return ApplyPaging(result, startIndex, limit);
                     return ApplyPaging(result, startIndex, limit);
@@ -662,7 +663,7 @@ namespace Emby.Dlna.ContentDirectory
 
 
             return new QueryResult<ServerItem>
             return new QueryResult<ServerItem>
             {
             {
-                Items = list.ToArray(),
+                Items = list.ToArray(list.Count),
                 TotalRecordCount = list.Count
                 TotalRecordCount = list.Count
             };
             };
         }
         }
@@ -740,7 +741,7 @@ namespace Emby.Dlna.ContentDirectory
 
 
             return new QueryResult<ServerItem>
             return new QueryResult<ServerItem>
             {
             {
-                Items = list.ToArray(),
+                Items = list.ToArray(list.Count),
                 TotalRecordCount = list.Count
                 TotalRecordCount = list.Count
             };
             };
         }
         }
@@ -828,7 +829,7 @@ namespace Emby.Dlna.ContentDirectory
 
 
             return new QueryResult<ServerItem>
             return new QueryResult<ServerItem>
             {
             {
-                Items = list.ToArray(),
+                Items = list.ToArray(list.Count),
                 TotalRecordCount = list.Count
                 TotalRecordCount = list.Count
             };
             };
         }
         }
@@ -995,7 +996,7 @@ namespace Emby.Dlna.ContentDirectory
             var result = new QueryResult<BaseItem>
             var result = new QueryResult<BaseItem>
             {
             {
                 TotalRecordCount = genresResult.TotalRecordCount,
                 TotalRecordCount = genresResult.TotalRecordCount,
-                Items = genresResult.Items.Select(i => i.Item1).ToArray()
+                Items = genresResult.Items.Select(i => i.Item1).ToArray(genresResult.Items.Length)
             };
             };
 
 
             return ToResult(result);
             return ToResult(result);
@@ -1013,7 +1014,7 @@ namespace Emby.Dlna.ContentDirectory
             var result = new QueryResult<BaseItem>
             var result = new QueryResult<BaseItem>
             {
             {
                 TotalRecordCount = genresResult.TotalRecordCount,
                 TotalRecordCount = genresResult.TotalRecordCount,
-                Items = genresResult.Items.Select(i => i.Item1).ToArray()
+                Items = genresResult.Items.Select(i => i.Item1).ToArray(genresResult.Items.Length)
             };
             };
 
 
             return ToResult(result);
             return ToResult(result);
@@ -1031,7 +1032,7 @@ namespace Emby.Dlna.ContentDirectory
             var result = new QueryResult<BaseItem>
             var result = new QueryResult<BaseItem>
             {
             {
                 TotalRecordCount = artists.TotalRecordCount,
                 TotalRecordCount = artists.TotalRecordCount,
-                Items = artists.Items.Select(i => i.Item1).ToArray()
+                Items = artists.Items.Select(i => i.Item1).ToArray(artists.Items.Length)
             };
             };
 
 
             return ToResult(result);
             return ToResult(result);
@@ -1049,7 +1050,7 @@ namespace Emby.Dlna.ContentDirectory
             var result = new QueryResult<BaseItem>
             var result = new QueryResult<BaseItem>
             {
             {
                 TotalRecordCount = artists.TotalRecordCount,
                 TotalRecordCount = artists.TotalRecordCount,
-                Items = artists.Items.Select(i => i.Item1).ToArray()
+                Items = artists.Items.Select(i => i.Item1).ToArray(artists.Items.Length)
             };
             };
 
 
             return ToResult(result);
             return ToResult(result);
@@ -1068,7 +1069,7 @@ namespace Emby.Dlna.ContentDirectory
             var result = new QueryResult<BaseItem>
             var result = new QueryResult<BaseItem>
             {
             {
                 TotalRecordCount = artists.TotalRecordCount,
                 TotalRecordCount = artists.TotalRecordCount,
-                Items = artists.Items.Select(i => i.Item1).ToArray()
+                Items = artists.Items.Select(i => i.Item1).ToArray(artists.Items.Length)
             };
             };
 
 
             return ToResult(result);
             return ToResult(result);
@@ -1196,7 +1197,7 @@ namespace Emby.Dlna.ContentDirectory
         {
         {
             var serverItems = result
             var serverItems = result
                 .Select(i => new ServerItem(i))
                 .Select(i => new ServerItem(i))
-                .ToArray();
+                .ToArray(result.Count);
 
 
             return new QueryResult<ServerItem>
             return new QueryResult<ServerItem>
             {
             {
@@ -1210,7 +1211,7 @@ namespace Emby.Dlna.ContentDirectory
             var serverItems = result
             var serverItems = result
                 .Items
                 .Items
                 .Select(i => new ServerItem(i))
                 .Select(i => new ServerItem(i))
-                .ToArray();
+                .ToArray(result.Items.Length);
 
 
             return new QueryResult<ServerItem>
             return new QueryResult<ServerItem>
             {
             {
@@ -1227,7 +1228,7 @@ namespace Emby.Dlna.ContentDirectory
                 sortOrders.Add(ItemSortBy.SortName);
                 sortOrders.Add(ItemSortBy.SortName);
             }
             }
 
 
-            query.SortBy = sortOrders.ToArray();
+            query.SortBy = sortOrders.ToArray(sortOrders.Count);
             query.SortOrder = sort.SortOrder;
             query.SortOrder = sort.SortOrder;
         }
         }
 
 
@@ -1243,8 +1244,7 @@ namespace Emby.Dlna.ContentDirectory
                 DtoOptions = GetDtoOptions()
                 DtoOptions = GetDtoOptions()
             });
             });
 
 
-            var serverItems = itemsResult.Items.Select(i => new ServerItem(i))
-            .ToArray();
+            var serverItems = itemsResult.Items.Select(i => new ServerItem(i)).ToArray(itemsResult.Items.Length);
 
 
             return new QueryResult<ServerItem>
             return new QueryResult<ServerItem>
             {
             {

+ 3 - 7
Emby.Dlna/DlnaManager.cs

@@ -18,6 +18,7 @@ using System.Text;
 using System.Text.RegularExpressions;
 using System.Text.RegularExpressions;
 using MediaBrowser.Model.IO;
 using MediaBrowser.Model.IO;
 using MediaBrowser.Model.Reflection;
 using MediaBrowser.Model.Reflection;
+using MediaBrowser.Model.Extensions;
 
 
 namespace Emby.Dlna
 namespace Emby.Dlna
 {
 {
@@ -106,7 +107,6 @@ namespace Emby.Dlna
             }
             }
             else
             else
             {
             {
-                _logger.Debug("No matching device profile found. The default will need to be used.");
                 LogUnmatchedProfile(deviceInfo);
                 LogUnmatchedProfile(deviceInfo);
             }
             }
 
 
@@ -220,12 +220,8 @@ namespace Emby.Dlna
             }
             }
             else
             else
             {
             {
-                var msg = new StringBuilder();
-                foreach (var header in headers)
-                {
-                    msg.AppendLine(header.Key + ": " + header.Value);
-                }
-                _logger.LogMultiline("No matching device profile found. The default will need to be used.", LogSeverity.Info, msg);
+                var headerString = string.Join(", ", headers.Select(i => string.Format("{0}={1}", i.Key, i.Value)).ToArray(headers.Count));
+                _logger.Debug("No matching device profile found. {0}", headerString);
             }
             }
 
 
             return profile;
             return profile;

+ 2 - 1
Emby.Dlna/PlayTo/Device.cs

@@ -15,6 +15,7 @@ using System.Threading.Tasks;
 using System.Xml.Linq;
 using System.Xml.Linq;
 using Emby.Dlna.Server;
 using Emby.Dlna.Server;
 using MediaBrowser.Model.Threading;
 using MediaBrowser.Model.Threading;
+using MediaBrowser.Model.Extensions;
 
 
 namespace Emby.Dlna.PlayTo
 namespace Emby.Dlna.PlayTo
 {
 {
@@ -890,7 +891,7 @@ namespace Emby.Dlna.PlayTo
             if (room != null && !string.IsNullOrWhiteSpace(room.Value))
             if (room != null && !string.IsNullOrWhiteSpace(room.Value))
                 friendlyNames.Add(room.Value);
                 friendlyNames.Add(room.Value);
 
 
-            deviceProperties.Name = string.Join(" ", friendlyNames.ToArray());
+            deviceProperties.Name = string.Join(" ", friendlyNames.ToArray(friendlyNames.Count));
 
 
             var model = document.Descendants(uPnpNamespaces.ud.GetName("modelName")).FirstOrDefault();
             var model = document.Descendants(uPnpNamespaces.ud.GetName("modelName")).FirstOrDefault();
             if (model != null)
             if (model != null)

+ 3 - 2
Emby.Dlna/Profiles/DefaultProfile.cs

@@ -1,6 +1,7 @@
 using MediaBrowser.Model.Dlna;
 using MediaBrowser.Model.Dlna;
 using System.Linq;
 using System.Linq;
 using System.Xml.Serialization;
 using System.Xml.Serialization;
+using MediaBrowser.Model.Extensions;
 
 
 namespace Emby.Dlna.Profiles
 namespace Emby.Dlna.Profiles
 {
 {
@@ -164,7 +165,7 @@ namespace Emby.Dlna.Profiles
         public void AddXmlRootAttribute(string name, string value)
         public void AddXmlRootAttribute(string name, string value)
         {
         {
             var atts = XmlRootAttributes ?? new XmlAttribute[] { };
             var atts = XmlRootAttributes ?? new XmlAttribute[] { };
-            var list = atts.ToList();
+            var list = atts.ToList(atts.Length);
 
 
             list.Add(new XmlAttribute
             list.Add(new XmlAttribute
             {
             {
@@ -172,7 +173,7 @@ namespace Emby.Dlna.Profiles
                 Value = value
                 Value = value
             });
             });
 
 
-            XmlRootAttributes = list.ToArray();
+            XmlRootAttributes = list.ToArray(list.Count);
         }
         }
     }
     }
 }
 }

+ 1 - 1
Emby.Dlna/Server/DescriptionXmlBuilder.cs

@@ -226,7 +226,7 @@ namespace Emby.Dlna.Server
                 }
                 }
             }
             }
 
 
-            var characters = characterList.ToArray();
+            var characters = characterList.ToArray(characterList.Count);
 
 
             var serverName = new string(characters);
             var serverName = new string(characters);
 
 

+ 16 - 12
Emby.Dlna/Service/BaseControlHandler.cs

@@ -11,6 +11,7 @@ using System.Xml;
 using Emby.Dlna.Didl;
 using Emby.Dlna.Didl;
 using MediaBrowser.Controller.Extensions;
 using MediaBrowser.Controller.Extensions;
 using MediaBrowser.Model.Xml;
 using MediaBrowser.Model.Xml;
+using MediaBrowser.Model.Extensions;
 
 
 namespace Emby.Dlna.Service
 namespace Emby.Dlna.Service
 {
 {
@@ -235,26 +236,29 @@ namespace Emby.Dlna.Service
 
 
         private void LogRequest(ControlRequest request)
         private void LogRequest(ControlRequest request)
         {
         {
-            var builder = new StringBuilder();
+            if (!Config.GetDlnaConfiguration().EnableDebugLog)
+            {
+                return;
+            }
 
 
-            var headers = string.Join(", ", request.Headers.Select(i => string.Format("{0}={1}", i.Key, i.Value)).ToArray());
-            builder.AppendFormat("Headers: {0}", headers);
-            builder.AppendLine();
-            //builder.Append(request.InputXml);
+            var originalHeaders = request.Headers;
+            var headers = string.Join(", ", originalHeaders.Select(i => string.Format("{0}={1}", i.Key, i.Value)).ToArray(originalHeaders.Count));
 
 
-            Logger.LogMultiline("Control request", LogSeverity.Debug, builder);
+            Logger.Debug("Control request. Headers: {0}", headers);
         }
         }
 
 
         private void LogResponse(ControlResponse response)
         private void LogResponse(ControlResponse response)
         {
         {
-            var builder = new StringBuilder();
+            if (!Config.GetDlnaConfiguration().EnableDebugLog)
+            {
+                return;
+            }
 
 
-            var headers = string.Join(", ", response.Headers.Select(i => string.Format("{0}={1}", i.Key, i.Value)).ToArray());
-            builder.AppendFormat("Headers: {0}", headers);
-            builder.AppendLine();
-            builder.Append(response.Xml);
+            var originalHeaders = response.Headers;
+            var headers = string.Join(", ", originalHeaders.Select(i => string.Format("{0}={1}", i.Key, i.Value)).ToArray(originalHeaders.Count));
+            //builder.Append(response.Xml);
 
 
-            Logger.LogMultiline("Control response", LogSeverity.Debug, builder);
+            Logger.Debug("Control response. Headers: {0}", headers);
         }
         }
     }
     }
 }
 }

+ 2 - 4
Emby.Drawing/ImageProcessor.cs

@@ -17,12 +17,10 @@ using System.Threading;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
 using MediaBrowser.Model.IO;
 using MediaBrowser.Model.IO;
 using Emby.Drawing.Common;
 using Emby.Drawing.Common;
-
-using MediaBrowser.Controller.IO;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Model.Net;
 using MediaBrowser.Model.Net;
 using MediaBrowser.Model.Threading;
 using MediaBrowser.Model.Threading;
-using TagLib;
+using MediaBrowser.Model.Extensions;
 
 
 namespace Emby.Drawing
 namespace Emby.Drawing
 {
 {
@@ -662,7 +660,7 @@ namespace Emby.Drawing
             var cacheKeys = imageEnhancers.Select(i => i.GetConfigurationCacheKey(item, imageType)).ToList();
             var cacheKeys = imageEnhancers.Select(i => i.GetConfigurationCacheKey(item, imageType)).ToList();
             cacheKeys.Add(originalImagePath + dateModified.Ticks);
             cacheKeys.Add(originalImagePath + dateModified.Ticks);
 
 
-            return string.Join("|", cacheKeys.ToArray()).GetMD5().ToString("N");
+            return string.Join("|", cacheKeys.ToArray(cacheKeys.Count)).GetMD5().ToString("N");
         }
         }
 
 
         /// <summary>
         /// <summary>

+ 1 - 1
Emby.Photos/PhotoProvider.cs

@@ -111,7 +111,7 @@ namespace Emby.Photos
                         }
                         }
 
 
                         item.Genres = image.ImageTag.Genres.ToList();
                         item.Genres = image.ImageTag.Genres.ToList();
-                        item.Tags = image.ImageTag.Keywords.ToList();
+                        item.Tags = image.ImageTag.Keywords;
                         item.Software = image.ImageTag.Software;
                         item.Software = image.ImageTag.Software;
 
 
                         if (image.ImageTag.Orientation == TagLib.Image.ImageOrientation.None)
                         if (image.ImageTag.Orientation == TagLib.Image.ImageOrientation.None)

+ 0 - 176
Emby.Server.Core/Emby.Server.Core.csproj

@@ -1,176 +0,0 @@
-<?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>
-    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
-    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
-    <ProjectGuid>{776B9F0C-5195-45E3-9A36-1CC1F0D8E0B0}</ProjectGuid>
-    <OutputType>Library</OutputType>
-    <AppDesignerFolder>Properties</AppDesignerFolder>
-    <RootNamespace>Emby.Server.Core</RootNamespace>
-    <AssemblyName>Emby.Server.Core</AssemblyName>
-    <TargetFrameworkVersion>v4.6</TargetFrameworkVersion>
-    <FileAlignment>512</FileAlignment>
-    <TargetFrameworkProfile />
-  </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>
-    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
-  </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>
-    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
-  </PropertyGroup>
-  <ItemGroup>
-    <Reference Include="Microsoft.IO.RecyclableMemoryStream, Version=1.2.2.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
-      <HintPath>..\packages\Microsoft.IO.RecyclableMemoryStream.1.2.2\lib\net45\Microsoft.IO.RecyclableMemoryStream.dll</HintPath>
-      <Private>True</Private>
-    </Reference>
-    <Reference Include="ServiceStack.Text, Version=4.5.8.0, Culture=neutral, processorArchitecture=MSIL">
-      <HintPath>..\packages\ServiceStack.Text.4.5.8\lib\net45\ServiceStack.Text.dll</HintPath>
-      <Private>True</Private>
-    </Reference>
-    <Reference Include="SimpleInjector, Version=4.0.8.0, Culture=neutral, PublicKeyToken=984cb50dea722e99, processorArchitecture=MSIL">
-      <HintPath>..\packages\SimpleInjector.4.0.8\lib\net45\SimpleInjector.dll</HintPath>
-    </Reference>
-    <Reference Include="System" />
-    <Reference Include="System.Configuration" />
-    <Reference Include="System.Core" />
-    <Reference Include="System.Xml.Linq" />
-    <Reference Include="System.Data.DataSetExtensions" />
-    <Reference Include="Microsoft.CSharp" />
-    <Reference Include="System.Data" />
-    <Reference Include="System.Net.Http" />
-    <Reference Include="System.Xml" />
-  </ItemGroup>
-  <ItemGroup>
-    <Compile Include="..\SharedVersion.cs">
-      <Link>Properties\SharedVersion.cs</Link>
-    </Compile>
-    <Compile Include="ApplicationHost.cs" />
-    <Compile Include="ApplicationPathHelper.cs" />
-    <Compile Include="Cryptography\ASN1.cs" />
-    <Compile Include="Cryptography\ASN1Convert.cs" />
-    <Compile Include="Cryptography\BitConverterLE.cs" />
-    <Compile Include="Cryptography\CertificateGenerator.cs" />
-    <Compile Include="Cryptography\CryptoConvert.cs" />
-    <Compile Include="Cryptography\PfxGenerator.cs" />
-    <Compile Include="Cryptography\PKCS1.cs" />
-    <Compile Include="Cryptography\PKCS12.cs" />
-    <Compile Include="Cryptography\PKCS7.cs" />
-    <Compile Include="Cryptography\PKCS8.cs" />
-    <Compile Include="Cryptography\X501Name.cs" />
-    <Compile Include="Cryptography\X509Builder.cs" />
-    <Compile Include="Cryptography\X509Certificate.cs" />
-    <Compile Include="Cryptography\X509CertificateBuilder.cs" />
-    <Compile Include="Cryptography\X509CertificateCollection.cs" />
-    <Compile Include="Cryptography\X509Extension.cs" />
-    <Compile Include="Cryptography\X509Extensions.cs" />
-    <Compile Include="Cryptography\X520Attributes.cs" />
-    <Compile Include="EntryPoints\ExternalPortForwarding.cs" />
-    <Compile Include="HttpServerFactory.cs" />
-    <Compile Include="IO\LibraryMonitor.cs" />
-    <Compile Include="IO\MemoryStreamProvider.cs" />
-    <Compile Include="Localization\TextLocalizer.cs" />
-    <Compile Include="Logging\ConsoleLogger.cs" />
-    <Compile Include="Properties\AssemblyInfo.cs" />
-    <Compile Include="SystemEvents.cs" />
-  </ItemGroup>
-  <ItemGroup>
-    <ProjectReference Include="..\Emby.Common.Implementations\Emby.Common.Implementations.csproj">
-      <Project>{1e37a338-9f57-4b70-bd6d-bb9c591e319b}</Project>
-      <Name>Emby.Common.Implementations</Name>
-    </ProjectReference>
-    <ProjectReference Include="..\Emby.Dlna\Emby.Dlna.csproj">
-      <Project>{805844ab-e92f-45e6-9d99-4f6d48d129a5}</Project>
-      <Name>Emby.Dlna</Name>
-    </ProjectReference>
-    <ProjectReference Include="..\Emby.Drawing\Emby.Drawing.csproj">
-      <Project>{08fff49b-f175-4807-a2b5-73b0ebd9f716}</Project>
-      <Name>Emby.Drawing</Name>
-    </ProjectReference>
-    <ProjectReference Include="..\Emby.Photos\Emby.Photos.csproj">
-      <Project>{89ab4548-770d-41fd-a891-8daff44f452c}</Project>
-      <Name>Emby.Photos</Name>
-    </ProjectReference>
-    <ProjectReference Include="..\Emby.Server.Implementations\Emby.Server.Implementations.csproj">
-      <Project>{e383961b-9356-4d5d-8233-9a1079d03055}</Project>
-      <Name>Emby.Server.Implementations</Name>
-    </ProjectReference>
-    <ProjectReference Include="..\MediaBrowser.Api\MediaBrowser.Api.csproj">
-      <Project>{4fd51ac5-2c16-4308-a993-c3a84f3b4582}</Project>
-      <Name>MediaBrowser.Api</Name>
-    </ProjectReference>
-    <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.LocalMetadata\MediaBrowser.LocalMetadata.csproj">
-      <Project>{7ef9f3e0-697d-42f3-a08f-19deb5f84392}</Project>
-      <Name>MediaBrowser.LocalMetadata</Name>
-    </ProjectReference>
-    <ProjectReference Include="..\MediaBrowser.MediaEncoding\MediaBrowser.MediaEncoding.csproj">
-      <Project>{0bd82fa6-eb8a-4452-8af5-74f9c3849451}</Project>
-      <Name>MediaBrowser.MediaEncoding</Name>
-    </ProjectReference>
-    <ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj">
-      <Project>{7eeeb4bb-f3e8-48fc-b4c5-70f0fff8329b}</Project>
-      <Name>MediaBrowser.Model</Name>
-    </ProjectReference>
-    <ProjectReference Include="..\MediaBrowser.Providers\MediaBrowser.Providers.csproj">
-      <Project>{442b5058-dcaf-4263-bb6a-f21e31120a1b}</Project>
-      <Name>MediaBrowser.Providers</Name>
-    </ProjectReference>
-    <ProjectReference Include="..\MediaBrowser.Server.Implementations\MediaBrowser.Server.Implementations.csproj">
-      <Project>{2e781478-814d-4a48-9d80-bff206441a65}</Project>
-      <Name>MediaBrowser.Server.Implementations</Name>
-    </ProjectReference>
-    <ProjectReference Include="..\MediaBrowser.WebDashboard\MediaBrowser.WebDashboard.csproj">
-      <Project>{5624b7b5-b5a7-41d8-9f10-cc5611109619}</Project>
-      <Name>MediaBrowser.WebDashboard</Name>
-    </ProjectReference>
-    <ProjectReference Include="..\MediaBrowser.XbmcMetadata\MediaBrowser.XbmcMetadata.csproj">
-      <Project>{23499896-b135-4527-8574-c26e926ea99e}</Project>
-      <Name>MediaBrowser.XbmcMetadata</Name>
-    </ProjectReference>
-    <ProjectReference Include="..\Mono.Nat\Mono.Nat.csproj">
-      <Project>{cb7f2326-6497-4a3d-ba03-48513b17a7be}</Project>
-      <Name>Mono.Nat</Name>
-    </ProjectReference>
-    <ProjectReference Include="..\OpenSubtitlesHandler\OpenSubtitlesHandler.csproj">
-      <Project>{4a4402d4-e910-443b-b8fc-2c18286a2ca0}</Project>
-      <Name>OpenSubtitlesHandler</Name>
-    </ProjectReference>
-    <ProjectReference Include="..\SocketHttpListener\SocketHttpListener.csproj">
-      <Project>{1d74413b-e7cf-455b-b021-f52bdf881542}</Project>
-      <Name>SocketHttpListener</Name>
-    </ProjectReference>
-  </ItemGroup>
-  <ItemGroup>
-    <None Include="app.config" />
-    <None Include="packages.config" />
-  </ItemGroup>
-  <Import Project="$(MSBuildToolsPath)\Microsoft.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>

+ 0 - 34
Emby.Server.Core/Properties/AssemblyInfo.cs

@@ -1,34 +0,0 @@
-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.Server.Core")]
-[assembly: AssemblyDescription("")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("")]
-[assembly: AssemblyProduct("Emby.Server.Core")]
-[assembly: AssemblyCopyright("Copyright ©  2017")]
-[assembly: AssemblyTrademark("")]
-[assembly: AssemblyCulture("")]
-
-// Setting ComVisible to false makes the types in this assembly not visible 
-// to COM components.  If you need to access a type in this assembly from 
-// COM, set the ComVisible attribute to true on that type.
-[assembly: ComVisible(false)]
-
-// The following GUID is for the ID of the typelib if this project is exposed to COM
-[assembly: Guid("776b9f0c-5195-45e3-9a36-1cc1f0d8e0b0")]
-
-// Version information for an assembly consists of the following four values:
-//
-//      Major Version
-//      Minor Version 
-//      Build Number
-//      Revision
-//
-// You can specify all the values or you can default the Build and Revision Numbers 
-// by using the '*' as shown below:
-// [assembly: AssemblyVersion("1.0.*")]

+ 0 - 11
Emby.Server.Core/app.config

@@ -1,11 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<configuration>
-  <runtime>
-    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
-      <dependentAssembly>
-        <assemblyIdentity name="SimpleInjector" publicKeyToken="984cb50dea722e99" culture="neutral"/>
-        <bindingRedirect oldVersion="0.0.0.0-4.0.7.0" newVersion="4.0.7.0"/>
-      </dependentAssembly>
-    </assemblyBinding>
-  </runtime>
-<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6"/></startup></configuration>

+ 0 - 6
Emby.Server.Core/packages.config

@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<packages>
-  <package id="Microsoft.IO.RecyclableMemoryStream" version="1.2.2" targetFramework="net462" />
-  <package id="ServiceStack.Text" version="4.5.8" targetFramework="net462" />
-  <package id="SimpleInjector" version="4.0.8" targetFramework="net46" />
-</packages>

+ 2 - 1
Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs

@@ -18,6 +18,7 @@ using System.Collections.Generic;
 using System.Linq;
 using System.Linq;
 using System.Text;
 using System.Text;
 using MediaBrowser.Model.Globalization;
 using MediaBrowser.Model.Globalization;
+using MediaBrowser.Model.Extensions;
 
 
 namespace Emby.Server.Implementations.Activity
 namespace Emby.Server.Implementations.Activity
 {
 {
@@ -436,7 +437,7 @@ namespace Emby.Server.Implementations.Activity
                 {
                 {
                     Name = string.Format(_localization.GetLocalizedString("ScheduledTaskFailedWithName"), task.Name),
                     Name = string.Format(_localization.GetLocalizedString("ScheduledTaskFailedWithName"), task.Name),
                     Type = "ScheduledTaskFailed",
                     Type = "ScheduledTaskFailed",
-                    Overview = string.Join(Environment.NewLine, vals.ToArray()),
+                    Overview = string.Join(Environment.NewLine, vals.ToArray(vals.Count)),
                     ShortOverview = runningTime,
                     ShortOverview = runningTime,
                     Severity = LogSeverity.Error
                     Severity = LogSeverity.Error
                 });
                 });

+ 5 - 4
Emby.Server.Implementations/Activity/ActivityRepository.cs

@@ -10,6 +10,7 @@ using MediaBrowser.Model.Activity;
 using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.Querying;
 using MediaBrowser.Model.Querying;
 using SQLitePCL.pretty;
 using SQLitePCL.pretty;
+using MediaBrowser.Model.Extensions;
 
 
 namespace Emby.Server.Implementations.Activity
 namespace Emby.Server.Implementations.Activity
 {
 {
@@ -94,13 +95,13 @@ namespace Emby.Server.Implementations.Activity
 
 
                     var whereTextWithoutPaging = whereClauses.Count == 0 ?
                     var whereTextWithoutPaging = whereClauses.Count == 0 ?
                       string.Empty :
                       string.Empty :
-                      " where " + string.Join(" AND ", whereClauses.ToArray());
+                      " where " + string.Join(" AND ", whereClauses.ToArray(whereClauses.Count));
 
 
                     if (startIndex.HasValue && startIndex.Value > 0)
                     if (startIndex.HasValue && startIndex.Value > 0)
                     {
                     {
                         var pagingWhereText = whereClauses.Count == 0 ?
                         var pagingWhereText = whereClauses.Count == 0 ?
                             string.Empty :
                             string.Empty :
-                            " where " + string.Join(" AND ", whereClauses.ToArray());
+                            " where " + string.Join(" AND ", whereClauses.ToArray(whereClauses.Count));
 
 
                         whereClauses.Add(string.Format("Id NOT IN (SELECT Id FROM ActivityLogEntries {0} ORDER BY DateCreated DESC LIMIT {1})",
                         whereClauses.Add(string.Format("Id NOT IN (SELECT Id FROM ActivityLogEntries {0} ORDER BY DateCreated DESC LIMIT {1})",
                             pagingWhereText,
                             pagingWhereText,
@@ -109,7 +110,7 @@ namespace Emby.Server.Implementations.Activity
 
 
                     var whereText = whereClauses.Count == 0 ?
                     var whereText = whereClauses.Count == 0 ?
                         string.Empty :
                         string.Empty :
-                        " where " + string.Join(" AND ", whereClauses.ToArray());
+                        " where " + string.Join(" AND ", whereClauses.ToArray(whereClauses.Count));
 
 
                     commandText += whereText;
                     commandText += whereText;
 
 
@@ -154,7 +155,7 @@ namespace Emby.Server.Implementations.Activity
                             result.TotalRecordCount = statement.ExecuteQuery().SelectScalarInt().First();
                             result.TotalRecordCount = statement.ExecuteQuery().SelectScalarInt().First();
                         }
                         }
 
 
-                        result.Items = list.ToArray();
+                        result.Items = list.ToArray(list.Count);
                         return result;
                         return result;
 
 
                     }, ReadTransactionMode);
                     }, ReadTransactionMode);

+ 70 - 93
Emby.Server.Core/ApplicationHost.cs → Emby.Server.Implementations/ApplicationHost.cs

@@ -1,11 +1,52 @@
-using MediaBrowser.Api;
+using Emby.Common.Implementations;
+using Emby.Common.Implementations.Archiving;
+using Emby.Common.Implementations.IO;
+using Emby.Common.Implementations.Reflection;
+using Emby.Common.Implementations.ScheduledTasks;
+using Emby.Common.Implementations.Serialization;
+using Emby.Common.Implementations.TextEncoding;
+using Emby.Common.Implementations.Xml;
+using Emby.Dlna;
+using Emby.Dlna.ConnectionManager;
+using Emby.Dlna.ContentDirectory;
+using Emby.Dlna.Main;
+using Emby.Dlna.MediaReceiverRegistrar;
+using Emby.Dlna.Ssdp;
+using Emby.Drawing;
+using Emby.Photos;
+using Emby.Server.Implementations.Activity;
+using Emby.Server.Implementations.Channels;
+using Emby.Server.Implementations.Collections;
+using Emby.Server.Implementations.Configuration;
+using Emby.Server.Implementations.Data;
+using Emby.Server.Implementations.Devices;
+using Emby.Server.Implementations.Dto;
+using Emby.Server.Implementations.FFMpeg;
+using Emby.Server.Implementations.HttpServer;
+using Emby.Server.Implementations.HttpServer.Security;
+using Emby.Server.Implementations.IO;
+using Emby.Server.Implementations.Library;
+using Emby.Server.Implementations.LiveTv;
+using Emby.Server.Implementations.Localization;
+using Emby.Server.Implementations.MediaEncoder;
+using Emby.Server.Implementations.Migrations;
+using Emby.Server.Implementations.Notifications;
+using Emby.Server.Implementations.Playlists;
+using Emby.Server.Implementations.Security;
+using Emby.Server.Implementations.Session;
+using Emby.Server.Implementations.Social;
+using Emby.Server.Implementations.TV;
+using Emby.Server.Implementations.Updates;
+using MediaBrowser.Api;
 using MediaBrowser.Common;
 using MediaBrowser.Common;
 using MediaBrowser.Common.Configuration;
 using MediaBrowser.Common.Configuration;
 using MediaBrowser.Common.Events;
 using MediaBrowser.Common.Events;
 using MediaBrowser.Common.Extensions;
 using MediaBrowser.Common.Extensions;
-using Emby.Common.Implementations.ScheduledTasks;
 using MediaBrowser.Common.Net;
 using MediaBrowser.Common.Net;
+using MediaBrowser.Common.Plugins;
 using MediaBrowser.Common.Progress;
 using MediaBrowser.Common.Progress;
+using MediaBrowser.Common.Security;
+using MediaBrowser.Common.Updates;
 using MediaBrowser.Controller;
 using MediaBrowser.Controller;
 using MediaBrowser.Controller.Channels;
 using MediaBrowser.Controller.Channels;
 using MediaBrowser.Controller.Chapters;
 using MediaBrowser.Controller.Chapters;
@@ -17,6 +58,9 @@ using MediaBrowser.Controller.Dlna;
 using MediaBrowser.Controller.Drawing;
 using MediaBrowser.Controller.Drawing;
 using MediaBrowser.Controller.Dto;
 using MediaBrowser.Controller.Dto;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Entities.Audio;
+using MediaBrowser.Controller.Entities.Movies;
+using MediaBrowser.Controller.Entities.TV;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.LiveTv;
 using MediaBrowser.Controller.LiveTv;
 using MediaBrowser.Controller.MediaEncoding;
 using MediaBrowser.Controller.MediaEncoding;
@@ -34,102 +78,47 @@ using MediaBrowser.Controller.Subtitles;
 using MediaBrowser.Controller.Sync;
 using MediaBrowser.Controller.Sync;
 using MediaBrowser.Controller.TV;
 using MediaBrowser.Controller.TV;
 using MediaBrowser.LocalMetadata.Savers;
 using MediaBrowser.LocalMetadata.Savers;
-using MediaBrowser.MediaEncoding.BdInfo;
-using MediaBrowser.MediaEncoding.Encoder;
-using MediaBrowser.MediaEncoding.Subtitles;
+using MediaBrowser.Model.Activity;
+using MediaBrowser.Model.Configuration;
+using MediaBrowser.Model.Diagnostics;
+using MediaBrowser.Model.Dlna;
+using MediaBrowser.Model.Globalization;
+using MediaBrowser.Model.IO;
 using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.MediaInfo;
 using MediaBrowser.Model.MediaInfo;
+using MediaBrowser.Model.Net;
+using MediaBrowser.Model.News;
+using MediaBrowser.Model.Reflection;
+using MediaBrowser.Model.Serialization;
+using MediaBrowser.Model.Services;
+using MediaBrowser.Model.Social;
 using MediaBrowser.Model.System;
 using MediaBrowser.Model.System;
+using MediaBrowser.Model.Text;
 using MediaBrowser.Model.Updates;
 using MediaBrowser.Model.Updates;
+using MediaBrowser.Model.Xml;
 using MediaBrowser.Providers.Chapters;
 using MediaBrowser.Providers.Chapters;
 using MediaBrowser.Providers.Manager;
 using MediaBrowser.Providers.Manager;
 using MediaBrowser.Providers.Subtitles;
 using MediaBrowser.Providers.Subtitles;
 using MediaBrowser.WebDashboard.Api;
 using MediaBrowser.WebDashboard.Api;
 using MediaBrowser.XbmcMetadata.Providers;
 using MediaBrowser.XbmcMetadata.Providers;
+using OpenSubtitlesHandler;
+using ServiceStack;
+using SocketHttpListener.Primitives;
 using System;
 using System;
 using System.Collections.Concurrent;
 using System.Collections.Concurrent;
 using System.Collections.Generic;
 using System.Collections.Generic;
 using System.Globalization;
 using System.Globalization;
 using System.IO;
 using System.IO;
 using System.Linq;
 using System.Linq;
-using System.Net;
-using System.Net.Sockets;
 using System.Reflection;
 using System.Reflection;
 using System.Security.Cryptography.X509Certificates;
 using System.Security.Cryptography.X509Certificates;
 using System.Threading;
 using System.Threading;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
-using Emby.Common.Implementations;
-using Emby.Common.Implementations.Archiving;
-using Emby.Common.Implementations.IO;
-using Emby.Common.Implementations.Reflection;
-using Emby.Common.Implementations.Serialization;
-using Emby.Common.Implementations.TextEncoding;
-using Emby.Common.Implementations.Xml;
-using Emby.Photos;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Api.Playback;
-using MediaBrowser.Common.Plugins;
-using MediaBrowser.Common.Security;
-using MediaBrowser.Common.Updates;
-using MediaBrowser.Controller.Entities.Audio;
-using MediaBrowser.Controller.Entities.Movies;
-using MediaBrowser.Controller.Entities.TV;
-using Emby.Dlna;
-using Emby.Dlna.ConnectionManager;
-using Emby.Dlna.ContentDirectory;
-using Emby.Dlna.Main;
-using Emby.Dlna.MediaReceiverRegistrar;
-using Emby.Dlna.Ssdp;
-using Emby.Server.Core;
-using Emby.Server.Implementations.Activity;
-using Emby.Server.Implementations.Devices;
-using Emby.Server.Implementations.FFMpeg;
-using Emby.Server.Core.IO;
-using Emby.Server.Core.Localization;
-using Emby.Server.Implementations.Migrations;
-using Emby.Server.Implementations.Security;
-using Emby.Server.Implementations.Social;
-using Emby.Server.Implementations.Channels;
-using Emby.Server.Implementations.Collections;
-using Emby.Server.Implementations.Dto;
-using Emby.Server.Implementations.IO;
-using Emby.Server.Implementations.HttpServer;
-using Emby.Server.Implementations.HttpServer.Security;
-using Emby.Server.Implementations.Library;
-using Emby.Server.Implementations.LiveTv;
-using Emby.Server.Implementations.Localization;
-using Emby.Server.Implementations.MediaEncoder;
-using Emby.Server.Implementations.Notifications;
-using Emby.Server.Implementations.Data;
-using Emby.Server.Implementations.Playlists;
-using Emby.Server.Implementations;
-using Emby.Server.Implementations.ServerManager;
-using Emby.Server.Implementations.Session;
-using Emby.Server.Implementations.TV;
-using Emby.Server.Implementations.Updates;
-using MediaBrowser.Model.Activity;
-using MediaBrowser.Model.Configuration;
-using MediaBrowser.Model.Dlna;
-using MediaBrowser.Model.Globalization;
-using MediaBrowser.Model.Net;
-using MediaBrowser.Model.News;
-using MediaBrowser.Model.Reflection;
-using MediaBrowser.Model.Serialization;
-using MediaBrowser.Model.Services;
-using MediaBrowser.Model.Social;
-using MediaBrowser.Model.Text;
-using MediaBrowser.Model.Xml;
-using OpenSubtitlesHandler;
-using ServiceStack;
-using SocketHttpListener.Primitives;
+using Emby.Server.MediaEncoding.Subtitles;
+using MediaBrowser.MediaEncoding.BdInfo;
 using StringExtensions = MediaBrowser.Controller.Extensions.StringExtensions;
 using StringExtensions = MediaBrowser.Controller.Extensions.StringExtensions;
-using Emby.Drawing;
-using Emby.Server.Implementations.Migrations;
-using MediaBrowser.Model.Diagnostics;
-using Emby.Common.Implementations.Diagnostics;
-using Emby.Server.Implementations.Configuration;
 
 
-namespace Emby.Server.Core
+namespace Emby.Server.Implementations
 {
 {
     /// <summary>
     /// <summary>
     /// Class CompositionRoot
     /// Class CompositionRoot
@@ -357,13 +346,6 @@ namespace Emby.Server.Core
         {
         {
             var builder = GetBaseExceptionMessage(ApplicationPaths);
             var builder = GetBaseExceptionMessage(ApplicationPaths);
 
 
-            // Skip if plugins haven't been loaded yet
-            //if (Plugins != null)
-            //{
-            //    var pluginString = string.Join("|", Plugins.Select(i => i.Name + "-" + i.Version.ToString()).ToArray());
-            //    builder.Insert(0, string.Format("Plugins: {0}{1}", pluginString, Environment.NewLine));
-            //}
-
             builder.Insert(0, string.Format("Version: {0}{1}", ApplicationVersion, Environment.NewLine));
             builder.Insert(0, string.Format("Version: {0}{1}", ApplicationVersion, Environment.NewLine));
             builder.Insert(0, "*** Error Report ***" + Environment.NewLine);
             builder.Insert(0, "*** Error Report ***" + Environment.NewLine);
 
 
@@ -608,7 +590,7 @@ namespace Emby.Server.Core
             RegisterSingleInstance(HttpServer, false);
             RegisterSingleInstance(HttpServer, false);
             progress.Report(10);
             progress.Report(10);
 
 
-            ServerManager = new ServerManager(this, JsonSerializer, LogManager.GetLogger("ServerManager"), ServerConfigurationManager, MemoryStreamFactory, textEncoding);
+            ServerManager = new ServerManager.ServerManager(this, JsonSerializer, LogManager.GetLogger("ServerManager"), ServerConfigurationManager, MemoryStreamFactory, textEncoding);
             RegisterSingleInstance(ServerManager);
             RegisterSingleInstance(ServerManager);
 
 
             var innerProgress = new ActionableProgress<double>();
             var innerProgress = new ActionableProgress<double>();
@@ -884,7 +866,7 @@ namespace Emby.Server.Core
             probePath = info.ProbePath;
             probePath = info.ProbePath;
             var hasExternalEncoder = string.Equals(info.Version, "external", StringComparison.OrdinalIgnoreCase);
             var hasExternalEncoder = string.Equals(info.Version, "external", StringComparison.OrdinalIgnoreCase);
 
 
-            var mediaEncoder = new MediaEncoder(LogManager.GetLogger("MediaEncoder"),
+            var mediaEncoder = new MediaEncoding.Encoder.MediaEncoder(LogManager.GetLogger("MediaEncoder"),
                 JsonSerializer,
                 JsonSerializer,
                 encoderPath,
                 encoderPath,
                 probePath,
                 probePath,
@@ -980,8 +962,6 @@ namespace Emby.Server.Core
             BaseItem.CollectionManager = CollectionManager;
             BaseItem.CollectionManager = CollectionManager;
             BaseItem.MediaSourceManager = MediaSourceManager;
             BaseItem.MediaSourceManager = MediaSourceManager;
             CollectionFolder.XmlSerializer = XmlSerializer;
             CollectionFolder.XmlSerializer = XmlSerializer;
-            BaseStreamingService.AppHost = this;
-            BaseStreamingService.HttpClient = HttpClient;
             Utilities.CryptographyProvider = CryptographyProvider;
             Utilities.CryptographyProvider = CryptographyProvider;
             AuthenticatedAttribute.AuthService = AuthService;
             AuthenticatedAttribute.AuthService = AuthService;
         }
         }
@@ -1254,7 +1234,7 @@ namespace Emby.Server.Core
             list.Add(GetAssembly(typeof(InstallationManager)));
             list.Add(GetAssembly(typeof(InstallationManager)));
 
 
             // MediaEncoding
             // MediaEncoding
-            list.Add(GetAssembly(typeof(MediaEncoder)));
+            list.Add(GetAssembly(typeof(MediaEncoding.Encoder.MediaEncoder)));
 
 
             // Dlna 
             // Dlna 
             list.Add(GetAssembly(typeof(DlnaEntryPoint)));
             list.Add(GetAssembly(typeof(DlnaEntryPoint)));
@@ -1267,10 +1247,7 @@ namespace Emby.Server.Core
 
 
             list.AddRange(GetAssembliesWithPartsInternal());
             list.AddRange(GetAssembliesWithPartsInternal());
 
 
-            // Include composable parts in the running assembly
-            list.Add(GetAssembly(typeof(ApplicationHost)));
-
-            return list;
+            return list.ToList();
         }
         }
 
 
         protected abstract List<Assembly> GetAssembliesWithPartsInternal();
         protected abstract List<Assembly> GetAssembliesWithPartsInternal();

+ 1 - 1
Emby.Server.Core/ApplicationPathHelper.cs → Emby.Server.Implementations/ApplicationPathHelper.cs

@@ -2,7 +2,7 @@
 using System.Configuration;
 using System.Configuration;
 using System.IO;
 using System.IO;
 
 
-namespace Emby.Server.Core
+namespace Emby.Server.Implementations
 {
 {
     public static class ApplicationPathHelper
     public static class ApplicationPathHelper
     {
     {

+ 21 - 18
Emby.Server.Implementations/Channels/ChannelManager.cs

@@ -159,7 +159,7 @@ namespace Emby.Server.Implementations.Channels
                 all = all.Take(query.Limit.Value).ToList();
                 all = all.Take(query.Limit.Value).ToList();
             }
             }
 
 
-            var returnItems = all.ToArray();
+            var returnItems = all.ToArray(all.Count);
 
 
             var result = new QueryResult<Channel>
             var result = new QueryResult<Channel>
             {
             {
@@ -182,8 +182,10 @@ namespace Emby.Server.Implementations.Channels
             {
             {
             };
             };
 
 
-            var returnItems = (await _dtoService.GetBaseItemDtos(internalResult.Items, dtoOptions, user).ConfigureAwait(false))
-                .ToArray();
+            var returnList = (await _dtoService.GetBaseItemDtos(internalResult.Items, dtoOptions, user)
+                .ConfigureAwait(false));
+            var returnItems = returnList
+                .ToArray(returnList.Count);
 
 
             var result = new QueryResult<BaseItemDto>
             var result = new QueryResult<BaseItemDto>
             {
             {
@@ -567,8 +569,9 @@ namespace Emby.Server.Implementations.Channels
                 Fields = query.Fields.ToList()
                 Fields = query.Fields.ToList()
             };
             };
 
 
-            var returnItems = (await _dtoService.GetBaseItemDtos(items, dtoOptions, user).ConfigureAwait(false))
-                .ToArray();
+            var returnList = (await _dtoService.GetBaseItemDtos(items, dtoOptions, user).ConfigureAwait(false));
+            var returnItems = returnList
+                .ToArray(returnList.Count);
 
 
             var result = new QueryResult<BaseItemDto>
             var result = new QueryResult<BaseItemDto>
             {
             {
@@ -676,12 +679,10 @@ namespace Emby.Server.Implementations.Channels
                 internalItems = internalItems.Take(query.Limit.Value).ToArray();
                 internalItems = internalItems.Take(query.Limit.Value).ToArray();
             }
             }
 
 
-            var returnItemArray = internalItems.ToArray();
-
             return new QueryResult<BaseItem>
             return new QueryResult<BaseItem>
             {
             {
                 TotalRecordCount = totalCount,
                 TotalRecordCount = totalCount,
-                Items = returnItemArray
+                Items = internalItems
             };
             };
         }
         }
 
 
@@ -813,12 +814,10 @@ namespace Emby.Server.Implementations.Channels
 
 
             var internalItems = await Task.WhenAll(itemTasks).ConfigureAwait(false);
             var internalItems = await Task.WhenAll(itemTasks).ConfigureAwait(false);
 
 
-            var returnItemArray = internalItems.ToArray();
-
             return new QueryResult<BaseItem>
             return new QueryResult<BaseItem>
             {
             {
                 TotalRecordCount = totalCount,
                 TotalRecordCount = totalCount,
-                Items = returnItemArray
+                Items = internalItems
             };
             };
         }
         }
 
 
@@ -837,8 +836,10 @@ namespace Emby.Server.Implementations.Channels
                 Fields = query.Fields.ToList()
                 Fields = query.Fields.ToList()
             };
             };
 
 
-            var returnItems = (await _dtoService.GetBaseItemDtos(internalResult.Items, dtoOptions, user).ConfigureAwait(false))
-                .ToArray();
+            var returnList = (await _dtoService.GetBaseItemDtos(internalResult.Items, dtoOptions, user)
+                .ConfigureAwait(false));
+            var returnItems = returnList
+                .ToArray(returnList.Count);
 
 
             var result = new QueryResult<BaseItemDto>
             var result = new QueryResult<BaseItemDto>
             {
             {
@@ -989,8 +990,10 @@ namespace Emby.Server.Implementations.Channels
                 Fields = query.Fields.ToList()
                 Fields = query.Fields.ToList()
             };
             };
 
 
-            var returnItems = (await _dtoService.GetBaseItemDtos(internalResult.Items, dtoOptions, user).ConfigureAwait(false))
-                .ToArray();
+            var returnList = (await _dtoService.GetBaseItemDtos(internalResult.Items, dtoOptions, user)
+                .ConfigureAwait(false));
+            var returnItems = returnList
+                .ToArray(returnList.Count);
 
 
             var result = new QueryResult<BaseItemDto>
             var result = new QueryResult<BaseItemDto>
             {
             {
@@ -1191,7 +1194,7 @@ namespace Emby.Server.Implementations.Channels
                 }
                 }
             }
             }
 
 
-            var returnItemArray = all.ToArray();
+            var returnItemArray = all.ToArray(all.Count);
             RefreshIfNeeded(returnItemArray);
             RefreshIfNeeded(returnItemArray);
 
 
             return new QueryResult<BaseItem>
             return new QueryResult<BaseItem>
@@ -1309,7 +1312,7 @@ namespace Emby.Server.Implementations.Channels
             {
             {
                 item.Name = info.Name;
                 item.Name = info.Name;
                 item.Genres = info.Genres;
                 item.Genres = info.Genres;
-                item.Studios = info.Studios;
+                item.Studios = info.Studios.ToArray(info.Studios.Count);
                 item.CommunityRating = info.CommunityRating;
                 item.CommunityRating = info.CommunityRating;
                 item.Overview = info.Overview;
                 item.Overview = info.Overview;
                 item.IndexNumber = info.IndexNumber;
                 item.IndexNumber = info.IndexNumber;
@@ -1319,7 +1322,7 @@ namespace Emby.Server.Implementations.Channels
                 item.ProviderIds = info.ProviderIds;
                 item.ProviderIds = info.ProviderIds;
                 item.OfficialRating = info.OfficialRating;
                 item.OfficialRating = info.OfficialRating;
                 item.DateCreated = info.DateCreated ?? DateTime.UtcNow;
                 item.DateCreated = info.DateCreated ?? DateTime.UtcNow;
-                item.Tags = info.Tags;
+                item.Tags = info.Tags.ToArray(info.Tags.Count);
                 item.HomePageUrl = info.HomePageUrl;
                 item.HomePageUrl = info.HomePageUrl;
             }
             }
             else if (info.Type == ChannelItemType.Folder && info.FolderType == ChannelFolderType.Container)
             else if (info.Type == ChannelItemType.Folder && info.FolderType == ChannelFolderType.Container)

+ 3 - 2
Emby.Server.Implementations/Configuration/ServerConfigurationManager.cs

@@ -16,6 +16,7 @@ using MediaBrowser.Model.Events;
 using MediaBrowser.Model.IO;
 using MediaBrowser.Model.IO;
 using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.Serialization;
 using MediaBrowser.Model.Serialization;
+using MediaBrowser.Model.Extensions;
 
 
 namespace Emby.Server.Implementations.Configuration
 namespace Emby.Server.Implementations.Configuration
 {
 {
@@ -216,7 +217,7 @@ namespace Emby.Server.Implementations.Configuration
 
 
                 list.Add(service);
                 list.Add(service);
 
 
-                options.DisabledMetadataSavers = list.ToArray();
+                options.DisabledMetadataSavers = list.ToArray(list.Count);
             }
             }
         }
         }
 
 
@@ -236,7 +237,7 @@ namespace Emby.Server.Implementations.Configuration
 
 
                 list.Add(options);
                 list.Add(options);
 
 
-                config.MetadataOptions = list.ToArray();
+                config.MetadataOptions = list.ToArray(list.Count);
             }
             }
 
 
             return options;
             return options;

+ 0 - 0
Emby.Server.Core/Cryptography/ASN1.cs → Emby.Server.Implementations/Cryptography/ASN1.cs


+ 0 - 0
Emby.Server.Core/Cryptography/ASN1Convert.cs → Emby.Server.Implementations/Cryptography/ASN1Convert.cs


+ 0 - 0
Emby.Server.Core/Cryptography/BitConverterLE.cs → Emby.Server.Implementations/Cryptography/BitConverterLE.cs


+ 0 - 0
Emby.Server.Core/Cryptography/CertificateGenerator.cs → Emby.Server.Implementations/Cryptography/CertificateGenerator.cs


+ 0 - 0
Emby.Server.Core/Cryptography/CryptoConvert.cs → Emby.Server.Implementations/Cryptography/CryptoConvert.cs


+ 0 - 0
Emby.Server.Core/Cryptography/PKCS1.cs → Emby.Server.Implementations/Cryptography/PKCS1.cs


+ 0 - 0
Emby.Server.Core/Cryptography/PKCS12.cs → Emby.Server.Implementations/Cryptography/PKCS12.cs


+ 0 - 0
Emby.Server.Core/Cryptography/PKCS7.cs → Emby.Server.Implementations/Cryptography/PKCS7.cs


+ 0 - 0
Emby.Server.Core/Cryptography/PKCS8.cs → Emby.Server.Implementations/Cryptography/PKCS8.cs


+ 0 - 0
Emby.Server.Core/Cryptography/PfxGenerator.cs → Emby.Server.Implementations/Cryptography/PfxGenerator.cs


+ 0 - 0
Emby.Server.Core/Cryptography/X501Name.cs → Emby.Server.Implementations/Cryptography/X501Name.cs


+ 0 - 0
Emby.Server.Core/Cryptography/X509Builder.cs → Emby.Server.Implementations/Cryptography/X509Builder.cs


+ 0 - 0
Emby.Server.Core/Cryptography/X509Certificate.cs → Emby.Server.Implementations/Cryptography/X509Certificate.cs


+ 0 - 0
Emby.Server.Core/Cryptography/X509CertificateBuilder.cs → Emby.Server.Implementations/Cryptography/X509CertificateBuilder.cs


+ 0 - 0
Emby.Server.Core/Cryptography/X509CertificateCollection.cs → Emby.Server.Implementations/Cryptography/X509CertificateCollection.cs


+ 0 - 0
Emby.Server.Core/Cryptography/X509Extension.cs → Emby.Server.Implementations/Cryptography/X509Extension.cs


+ 0 - 0
Emby.Server.Core/Cryptography/X509Extensions.cs → Emby.Server.Implementations/Cryptography/X509Extensions.cs


+ 0 - 0
Emby.Server.Core/Cryptography/X520Attributes.cs → Emby.Server.Implementations/Cryptography/X520Attributes.cs


+ 7 - 18
Emby.Server.Implementations/Data/BaseSqliteRepository.cs

@@ -136,24 +136,6 @@ namespace Emby.Server.Implementations.Data
                     queries.Add("PRAGMA temp_store = file");
                     queries.Add("PRAGMA temp_store = file");
                 }
                 }
 
 
-                ////foreach (var query in queries)
-                ////{
-                ////    db.Execute(query);
-                ////}
-
-                //Logger.Info("synchronous: " + db.Query("PRAGMA synchronous").SelectScalarString().First());
-                //Logger.Info("temp_store: " + db.Query("PRAGMA temp_store").SelectScalarString().First());
-
-                /*if (!string.Equals(_defaultWal, "wal", StringComparison.OrdinalIgnoreCase))
-                {
-                    queries.Add("PRAGMA journal_mode=WAL");
-
-                    using (WriteLock.Write())
-                    {
-                        db.ExecuteAll(string.Join(";", queries.ToArray()));
-                    }
-                }
-                else*/
                 foreach (var query in queries)
                 foreach (var query in queries)
                 {
                 {
                     db.Execute(query);
                     db.Execute(query);
@@ -212,6 +194,13 @@ namespace Emby.Server.Implementations.Data
                     "pragma temp_store = memory"
                     "pragma temp_store = memory"
                 });
                 });
             }
             }
+            else
+            {
+                queries.AddRange(new List<string>
+                {
+                    "pragma temp_store = file"
+                });
+            }
 
 
             db.ExecuteAll(string.Join(";", queries.ToArray()));
             db.ExecuteAll(string.Join(";", queries.ToArray()));
             Logger.Info("PRAGMA synchronous=" + db.Query("PRAGMA synchronous").SelectScalarString().First());
             Logger.Info("PRAGMA synchronous=" + db.Query("PRAGMA synchronous").SelectScalarString().First());

+ 61 - 47
Emby.Server.Implementations/Data/SqliteItemRepository.cs

@@ -31,6 +31,7 @@ using MediaBrowser.Model.Reflection;
 using SQLitePCL.pretty;
 using SQLitePCL.pretty;
 using MediaBrowser.Model.System;
 using MediaBrowser.Model.System;
 using MediaBrowser.Model.Threading;
 using MediaBrowser.Model.Threading;
+using MediaBrowser.Model.Extensions;
 
 
 namespace Emby.Server.Implementations.Data
 namespace Emby.Server.Implementations.Data
 {
 {
@@ -836,7 +837,7 @@ namespace Emby.Server.Implementations.Data
 
 
             saveItemStatement.TryBind("@IsInMixedFolder", item.IsInMixedFolder);
             saveItemStatement.TryBind("@IsInMixedFolder", item.IsInMixedFolder);
 
 
-            if (item.LockedFields.Count > 0)
+            if (item.LockedFields.Length > 0)
             {
             {
                 saveItemStatement.TryBind("@LockedFields", string.Join("|", item.LockedFields.Select(i => i.ToString()).ToArray()));
                 saveItemStatement.TryBind("@LockedFields", string.Join("|", item.LockedFields.Select(i => i.ToString()).ToArray()));
             }
             }
@@ -845,7 +846,7 @@ namespace Emby.Server.Implementations.Data
                 saveItemStatement.TryBindNull("@LockedFields");
                 saveItemStatement.TryBindNull("@LockedFields");
             }
             }
 
 
-            if (item.Studios.Count > 0)
+            if (item.Studios.Length > 0)
             {
             {
                 saveItemStatement.TryBind("@Studios", string.Join("|", item.Studios.ToArray()));
                 saveItemStatement.TryBind("@Studios", string.Join("|", item.Studios.ToArray()));
             }
             }
@@ -865,9 +866,9 @@ namespace Emby.Server.Implementations.Data
 
 
             saveItemStatement.TryBind("@ExternalServiceId", item.ServiceName);
             saveItemStatement.TryBind("@ExternalServiceId", item.ServiceName);
 
 
-            if (item.Tags.Count > 0)
+            if (item.Tags.Length > 0)
             {
             {
-                saveItemStatement.TryBind("@Tags", string.Join("|", item.Tags.ToArray()));
+                saveItemStatement.TryBind("@Tags", string.Join("|", item.Tags));
             }
             }
             else
             else
             {
             {
@@ -984,16 +985,16 @@ namespace Emby.Server.Implementations.Data
             saveItemStatement.TryBind("@ProviderIds", SerializeProviderIds(item));
             saveItemStatement.TryBind("@ProviderIds", SerializeProviderIds(item));
             saveItemStatement.TryBind("@Images", SerializeImages(item));
             saveItemStatement.TryBind("@Images", SerializeImages(item));
 
 
-            if (item.ProductionLocations.Count > 0)
+            if (item.ProductionLocations.Length > 0)
             {
             {
-                saveItemStatement.TryBind("@ProductionLocations", string.Join("|", item.ProductionLocations.ToArray()));
+                saveItemStatement.TryBind("@ProductionLocations", string.Join("|", item.ProductionLocations));
             }
             }
             else
             else
             {
             {
                 saveItemStatement.TryBindNull("@ProductionLocations");
                 saveItemStatement.TryBindNull("@ProductionLocations");
             }
             }
 
 
-            if (item.ThemeSongIds.Count > 0)
+            if (item.ThemeSongIds.Length > 0)
             {
             {
                 saveItemStatement.TryBind("@ThemeSongIds", string.Join("|", item.ThemeSongIds.ToArray()));
                 saveItemStatement.TryBind("@ThemeSongIds", string.Join("|", item.ThemeSongIds.ToArray()));
             }
             }
@@ -1002,7 +1003,7 @@ namespace Emby.Server.Implementations.Data
                 saveItemStatement.TryBindNull("@ThemeSongIds");
                 saveItemStatement.TryBindNull("@ThemeSongIds");
             }
             }
 
 
-            if (item.ThemeVideoIds.Count > 0)
+            if (item.ThemeVideoIds.Length > 0)
             {
             {
                 saveItemStatement.TryBind("@ThemeVideoIds", string.Join("|", item.ThemeVideoIds.ToArray()));
                 saveItemStatement.TryBind("@ThemeVideoIds", string.Join("|", item.ThemeVideoIds.ToArray()));
             }
             }
@@ -1089,9 +1090,9 @@ namespace Emby.Server.Implementations.Data
 
 
         private string SerializeImages(BaseItem item)
         private string SerializeImages(BaseItem item)
         {
         {
-            var images = item.ImageInfos.ToList();
+            var images = item.ImageInfos;
 
 
-            if (images.Count == 0)
+            if (images.Length == 0)
             {
             {
                 return null;
                 return null;
             }
             }
@@ -1108,22 +1109,24 @@ namespace Emby.Server.Implementations.Data
                 return;
                 return;
             }
             }
 
 
-            if (item.ImageInfos.Count > 0)
+            if (item.ImageInfos.Length > 0)
             {
             {
                 return;
                 return;
             }
             }
 
 
             var parts = value.Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
             var parts = value.Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
-
+            var list = new List<ItemImageInfo>();
             foreach (var part in parts)
             foreach (var part in parts)
             {
             {
                 var image = ItemImageInfoFromValueString(part);
                 var image = ItemImageInfoFromValueString(part);
 
 
                 if (image != null)
                 if (image != null)
                 {
                 {
-                    item.ImageInfos.Add(image);
+                    list.Add(image);
                 }
                 }
             }
             }
+
+            item.ImageInfos = list.ToArray(list.Count);
         }
         }
 
 
         public string ToValueString(ItemImageInfo image)
         public string ToValueString(ItemImageInfo image)
@@ -1678,7 +1681,7 @@ namespace Emby.Server.Implementations.Data
                                 return parsedValue;
                                 return parsedValue;
                             }
                             }
                             return (MetadataFields?)null;
                             return (MetadataFields?)null;
-                        }).Where(i => i.HasValue).Select(i => i.Value).ToList();
+                        }).Where(i => i.HasValue).Select(i => i.Value).ToArray();
                 }
                 }
                 index++;
                 index++;
             }
             }
@@ -1687,7 +1690,7 @@ namespace Emby.Server.Implementations.Data
             {
             {
                 if (!reader.IsDBNull(index))
                 if (!reader.IsDBNull(index))
                 {
                 {
-                    item.Studios = reader.GetString(index).Split('|').Where(i => !string.IsNullOrWhiteSpace(i)).ToList();
+                    item.Studios = reader.GetString(index).Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
                 }
                 }
                 index++;
                 index++;
             }
             }
@@ -1696,7 +1699,7 @@ namespace Emby.Server.Implementations.Data
             {
             {
                 if (!reader.IsDBNull(index))
                 if (!reader.IsDBNull(index))
                 {
                 {
-                    item.Tags = reader.GetString(index).Split('|').Where(i => !string.IsNullOrWhiteSpace(i)).ToList();
+                    item.Tags = reader.GetString(index).Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
                 }
                 }
                 index++;
                 index++;
             }
             }
@@ -1873,7 +1876,7 @@ namespace Emby.Server.Implementations.Data
             {
             {
                 if (!reader.IsDBNull(index))
                 if (!reader.IsDBNull(index))
                 {
                 {
-                    item.ProductionLocations = reader.GetString(index).Split('|').Where(i => !string.IsNullOrWhiteSpace(i)).ToList();
+                    item.ProductionLocations = reader.GetString(index).Split('|').Where(i => !string.IsNullOrWhiteSpace(i)).ToArray();
                 }
                 }
                 index++;
                 index++;
             }
             }
@@ -1882,7 +1885,7 @@ namespace Emby.Server.Implementations.Data
             {
             {
                 if (!reader.IsDBNull(index))
                 if (!reader.IsDBNull(index))
                 {
                 {
-                    item.ThemeSongIds = reader.GetString(index).Split('|').Where(i => !string.IsNullOrWhiteSpace(i)).Select(i => new Guid(i)).ToList();
+                    item.ThemeSongIds = SplitToGuids(reader.GetString(index));
                 }
                 }
                 index++;
                 index++;
             }
             }
@@ -1891,7 +1894,7 @@ namespace Emby.Server.Implementations.Data
             {
             {
                 if (!reader.IsDBNull(index))
                 if (!reader.IsDBNull(index))
                 {
                 {
-                    item.ThemeVideoIds = reader.GetString(index).Split('|').Where(i => !string.IsNullOrWhiteSpace(i)).Select(i => new Guid(i)).ToList();
+                    item.ThemeVideoIds = SplitToGuids(reader.GetString(index));
                 }
                 }
                 index++;
                 index++;
             }
             }
@@ -1950,12 +1953,26 @@ namespace Emby.Server.Implementations.Data
             return item;
             return item;
         }
         }
 
 
+        private Guid[] SplitToGuids(string value)
+        {
+            var ids = value.Split('|');
+
+            var result = new Guid[ids.Length];
+
+            for (var i = 0; i < result.Length; i++)
+            {
+                result[i] = new Guid(ids[i]);
+            }
+
+            return result;
+        }
+
         /// <summary>
         /// <summary>
         /// Gets the critic reviews.
         /// Gets the critic reviews.
         /// </summary>
         /// </summary>
         /// <param name="itemId">The item id.</param>
         /// <param name="itemId">The item id.</param>
         /// <returns>Task{IEnumerable{ItemReview}}.</returns>
         /// <returns>Task{IEnumerable{ItemReview}}.</returns>
-        public IEnumerable<ItemReview> GetCriticReviews(Guid itemId)
+        public List<ItemReview> GetCriticReviews(Guid itemId)
         {
         {
             return new List<ItemReview>();
             return new List<ItemReview>();
         }
         }
@@ -2206,7 +2223,7 @@ namespace Emby.Server.Implementations.Data
             return false;
             return false;
         }
         }
 
 
-        private List<ItemFields> allFields = Enum.GetNames(typeof(ItemFields))
+        private readonly List<ItemFields> allFields = Enum.GetNames(typeof(ItemFields))
                     .Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true))
                     .Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true))
                     .ToList();
                     .ToList();
 
 
@@ -2548,11 +2565,11 @@ namespace Emby.Server.Implementations.Data
                     }
                     }
                 }
                 }
 
 
-                query.ExcludeItemIds = excludeIds.ToArray();
+                query.ExcludeItemIds = excludeIds.ToArray(excludeIds.Count);
                 query.ExcludeProviderIds = item.ProviderIds;
                 query.ExcludeProviderIds = item.ProviderIds;
             }
             }
 
 
-            return list.ToArray();
+            return list.ToArray(list.Count);
         }
         }
 
 
         private void BindSimilarParams(InternalItemsQuery query, IStatement statement)
         private void BindSimilarParams(InternalItemsQuery query, IStatement statement)
@@ -2595,7 +2612,7 @@ namespace Emby.Server.Implementations.Data
 
 
             if (groups.Count > 0)
             if (groups.Count > 0)
             {
             {
-                return " Group by " + string.Join(",", groups.ToArray());
+                return " Group by " + string.Join(",", groups.ToArray(groups.Count));
             }
             }
 
 
             return string.Empty;
             return string.Empty;
@@ -2632,7 +2649,7 @@ namespace Emby.Server.Implementations.Data
 
 
             var whereText = whereClauses.Count == 0 ?
             var whereText = whereClauses.Count == 0 ?
                 string.Empty :
                 string.Empty :
-                " where " + string.Join(" AND ", whereClauses.ToArray());
+                " where " + string.Join(" AND ", whereClauses.ToArray(whereClauses.Count));
 
 
             commandText += whereText;
             commandText += whereText;
 
 
@@ -2689,7 +2706,7 @@ namespace Emby.Server.Implementations.Data
 
 
             var whereText = whereClauses.Count == 0 ?
             var whereText = whereClauses.Count == 0 ?
                 string.Empty :
                 string.Empty :
-                " where " + string.Join(" AND ", whereClauses.ToArray());
+                " where " + string.Join(" AND ", whereClauses.ToArray(whereClauses.Count));
 
 
             commandText += whereText;
             commandText += whereText;
 
 
@@ -2842,7 +2859,7 @@ namespace Emby.Server.Implementations.Data
                 var returnList = GetItemList(query);
                 var returnList = GetItemList(query);
                 return new QueryResult<BaseItem>
                 return new QueryResult<BaseItem>
                 {
                 {
-                    Items = returnList.ToArray(),
+                    Items = returnList.ToArray(returnList.Count),
                     TotalRecordCount = returnList.Count
                     TotalRecordCount = returnList.Count
                 };
                 };
             }
             }
@@ -2865,7 +2882,7 @@ namespace Emby.Server.Implementations.Data
 
 
             var whereText = whereClauses.Count == 0 ?
             var whereText = whereClauses.Count == 0 ?
                 string.Empty :
                 string.Empty :
-                " where " + string.Join(" AND ", whereClauses.ToArray());
+                " where " + string.Join(" AND ", whereClauses.ToArray(whereClauses.Count));
 
 
             var whereTextWithoutPaging = whereText;
             var whereTextWithoutPaging = whereText;
 
 
@@ -2926,8 +2943,7 @@ namespace Emby.Server.Implementations.Data
                     return connection.RunInTransaction(db =>
                     return connection.RunInTransaction(db =>
                     {
                     {
                         var result = new QueryResult<BaseItem>();
                         var result = new QueryResult<BaseItem>();
-                        var statements = PrepareAllSafe(db, statementTexts)
-                            .ToList();
+                        var statements = PrepareAllSafe(db, statementTexts);
 
 
                         if (!isReturningZeroItems)
                         if (!isReturningZeroItems)
                         {
                         {
@@ -2981,7 +2997,7 @@ namespace Emby.Server.Implementations.Data
 
 
                         LogQueryTime("GetItems", commandText, now);
                         LogQueryTime("GetItems", commandText, now);
 
 
-                        result.Items = list.ToArray();
+                        result.Items = list.ToArray(list.Count);
                         return result;
                         return result;
 
 
                     }, ReadTransactionMode);
                     }, ReadTransactionMode);
@@ -3133,7 +3149,7 @@ namespace Emby.Server.Implementations.Data
 
 
             var whereText = whereClauses.Count == 0 ?
             var whereText = whereClauses.Count == 0 ?
                 string.Empty :
                 string.Empty :
-                " where " + string.Join(" AND ", whereClauses.ToArray());
+                " where " + string.Join(" AND ", whereClauses.ToArray(whereClauses.Count));
 
 
             commandText += whereText;
             commandText += whereText;
 
 
@@ -3204,7 +3220,7 @@ namespace Emby.Server.Implementations.Data
 
 
             var whereText = whereClauses.Count == 0 ?
             var whereText = whereClauses.Count == 0 ?
                 string.Empty :
                 string.Empty :
-                " where " + string.Join(" AND ", whereClauses.ToArray());
+                " where " + string.Join(" AND ", whereClauses.ToArray(whereClauses.Count));
 
 
             commandText += whereText;
             commandText += whereText;
 
 
@@ -3277,7 +3293,7 @@ namespace Emby.Server.Implementations.Data
                 var returnList = GetItemIdsList(query);
                 var returnList = GetItemIdsList(query);
                 return new QueryResult<Guid>
                 return new QueryResult<Guid>
                 {
                 {
-                    Items = returnList.ToArray(),
+                    Items = returnList.ToArray(returnList.Count),
                     TotalRecordCount = returnList.Count
                     TotalRecordCount = returnList.Count
                 };
                 };
             }
             }
@@ -3292,7 +3308,7 @@ namespace Emby.Server.Implementations.Data
 
 
             var whereText = whereClauses.Count == 0 ?
             var whereText = whereClauses.Count == 0 ?
                 string.Empty :
                 string.Empty :
-                " where " + string.Join(" AND ", whereClauses.ToArray());
+                " where " + string.Join(" AND ", whereClauses.ToArray(whereClauses.Count));
 
 
             var whereTextWithoutPaging = whereText;
             var whereTextWithoutPaging = whereText;
 
 
@@ -3355,8 +3371,7 @@ namespace Emby.Server.Implementations.Data
                     {
                     {
                         var result = new QueryResult<Guid>();
                         var result = new QueryResult<Guid>();
 
 
-                        var statements = PrepareAllSafe(db, statementTexts)
-                            .ToList();
+                        var statements = PrepareAllSafe(db, statementTexts);
 
 
                         if (!isReturningZeroItems)
                         if (!isReturningZeroItems)
                         {
                         {
@@ -3399,7 +3414,7 @@ namespace Emby.Server.Implementations.Data
 
 
                         LogQueryTime("GetItemIds", commandText, now);
                         LogQueryTime("GetItemIds", commandText, now);
 
 
-                        result.Items = list.ToArray();
+                        result.Items = list.ToArray(list.Count);
                         return result;
                         return result;
 
 
                     }, ReadTransactionMode);
                     }, ReadTransactionMode);
@@ -3604,7 +3619,7 @@ namespace Emby.Server.Implementations.Data
                 }
                 }
                 if (programAttribtues.Count > 0)
                 if (programAttribtues.Count > 0)
                 {
                 {
-                    whereClauses.Add("(" + string.Join(" OR ", programAttribtues.ToArray()) + ")");
+                    whereClauses.Add("(" + string.Join(" OR ", programAttribtues.ToArray(programAttribtues.Count)) + ")");
                 }
                 }
             }
             }
 
 
@@ -5129,9 +5144,9 @@ namespace Emby.Server.Implementations.Data
 
 
             var itemCountColumns = new List<Tuple<string, string>>();
             var itemCountColumns = new List<Tuple<string, string>>();
 
 
-            var typesToCount = query.IncludeItemTypes.ToList();
+            var typesToCount = query.IncludeItemTypes;
 
 
-            if (typesToCount.Count > 0)
+            if (typesToCount.Length > 0)
             {
             {
                 var itemCountColumnQuery = "select group_concat(type, '|')" + GetFromText("B");
                 var itemCountColumnQuery = "select group_concat(type, '|')" + GetFromText("B");
 
 
@@ -5191,7 +5206,7 @@ namespace Emby.Server.Implementations.Data
 
 
             var whereText = " where Type=@SelectType";
             var whereText = " where Type=@SelectType";
 
 
-            if (typesToCount.Count == 0)
+            if (typesToCount.Length == 0)
             {
             {
                 whereText += " And CleanName In (Select CleanValue from ItemValues where " + typeClause + " AND ItemId in (select guid from TypedBaseItems" + innerWhereText + "))";
                 whereText += " And CleanName In (Select CleanValue from ItemValues where " + typeClause + " AND ItemId in (select guid from TypedBaseItems" + innerWhereText + "))";
             }
             }
@@ -5269,8 +5284,7 @@ namespace Emby.Server.Implementations.Data
                         var list = new List<Tuple<BaseItem, ItemCounts>>();
                         var list = new List<Tuple<BaseItem, ItemCounts>>();
                         var result = new QueryResult<Tuple<BaseItem, ItemCounts>>();
                         var result = new QueryResult<Tuple<BaseItem, ItemCounts>>();
 
 
-                        var statements = PrepareAllSafe(db, statementTexts)
-                            .ToList();
+                        var statements = PrepareAllSafe(db, statementTexts);
 
 
                         if (!isReturningZeroItems)
                         if (!isReturningZeroItems)
                         {
                         {
@@ -5345,7 +5359,7 @@ namespace Emby.Server.Implementations.Data
                         {
                         {
                             result.TotalRecordCount = list.Count;
                             result.TotalRecordCount = list.Count;
                         }
                         }
-                        result.Items = list.ToArray();
+                        result.Items = list.ToArray(list.Count);
 
 
                         return result;
                         return result;
 
 
@@ -5354,11 +5368,11 @@ namespace Emby.Server.Implementations.Data
             }
             }
         }
         }
 
 
-        private ItemCounts GetItemCounts(IReadOnlyList<IResultSetValue> reader, int countStartColumn, List<string> typesToCount)
+        private ItemCounts GetItemCounts(IReadOnlyList<IResultSetValue> reader, int countStartColumn, string[] typesToCount)
         {
         {
             var counts = new ItemCounts();
             var counts = new ItemCounts();
 
 
-            if (typesToCount.Count == 0)
+            if (typesToCount.Length == 0)
             {
             {
                 return counts;
                 return counts;
             }
             }

+ 7 - 7
Emby.Server.Implementations/Dto/DtoService.cs

@@ -649,12 +649,12 @@ namespace Emby.Server.Implementations.Dto
             dto.GameSystem = item.GameSystemName;
             dto.GameSystem = item.GameSystemName;
         }
         }
 
 
-        private List<string> GetImageTags(BaseItem item, List<ItemImageInfo> images)
+        private string[] GetImageTags(BaseItem item, List<ItemImageInfo> images)
         {
         {
             return images
             return images
                 .Select(p => GetImageCacheTag(item, p))
                 .Select(p => GetImageCacheTag(item, p))
                 .Where(i => i != null)
                 .Where(i => i != null)
-                .ToList();
+                .ToArray();
         }
         }
 
 
         private string GetImageCacheTag(BaseItem item, ImageType type)
         private string GetImageCacheTag(BaseItem item, ImageType type)
@@ -766,7 +766,7 @@ namespace Emby.Server.Implementations.Dto
                 }
                 }
             }
             }
 
 
-            dto.People = list.ToArray();
+            dto.People = list.ToArray(list.Count);
         }
         }
 
 
         /// <summary>
         /// <summary>
@@ -1049,12 +1049,12 @@ namespace Emby.Server.Implementations.Dto
             {
             {
                 if (!string.IsNullOrWhiteSpace(item.Tagline))
                 if (!string.IsNullOrWhiteSpace(item.Tagline))
                 {
                 {
-                    dto.Taglines = new List<string> { item.Tagline };
+                    dto.Taglines = new string[] { item.Tagline };
                 }
                 }
 
 
                 if (dto.Taglines == null)
                 if (dto.Taglines == null)
                 {
                 {
-                    dto.Taglines = new List<string>();
+                    dto.Taglines = new string[]{};
                 }
                 }
             }
             }
 
 
@@ -1430,9 +1430,9 @@ namespace Emby.Server.Implementations.Dto
 
 
             if (fields.Contains(ItemFields.ProductionLocations))
             if (fields.Contains(ItemFields.ProductionLocations))
             {
             {
-                if (item.ProductionLocations.Count > 0 || item is Movie)
+                if (item.ProductionLocations.Length > 0 || item is Movie)
                 {
                 {
-                    dto.ProductionLocations = item.ProductionLocations.ToArray();
+                    dto.ProductionLocations = item.ProductionLocations;
                 }
                 }
             }
             }
 
 

+ 82 - 2
Emby.Server.Implementations/Emby.Server.Implementations.csproj

@@ -21,6 +21,7 @@
     <DefineConstants>DEBUG;TRACE</DefineConstants>
     <DefineConstants>DEBUG;TRACE</DefineConstants>
     <ErrorReport>prompt</ErrorReport>
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
     <WarningLevel>4</WarningLevel>
+    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
   </PropertyGroup>
   </PropertyGroup>
   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
     <DebugType>pdbonly</DebugType>
     <DebugType>pdbonly</DebugType>
@@ -40,6 +41,8 @@
     <Compile Include="AppBase\BaseApplicationPaths.cs" />
     <Compile Include="AppBase\BaseApplicationPaths.cs" />
     <Compile Include="AppBase\BaseConfigurationManager.cs" />
     <Compile Include="AppBase\BaseConfigurationManager.cs" />
     <Compile Include="AppBase\ConfigurationHelper.cs" />
     <Compile Include="AppBase\ConfigurationHelper.cs" />
+    <Compile Include="ApplicationHost.cs" />
+    <Compile Include="ApplicationPathHelper.cs" />
     <Compile Include="Branding\BrandingConfigurationFactory.cs" />
     <Compile Include="Branding\BrandingConfigurationFactory.cs" />
     <Compile Include="Browser\BrowserLauncher.cs" />
     <Compile Include="Browser\BrowserLauncher.cs" />
     <Compile Include="Channels\ChannelConfigurations.cs" />
     <Compile Include="Channels\ChannelConfigurations.cs" />
@@ -52,6 +55,24 @@
     <Compile Include="Collections\CollectionManager.cs" />
     <Compile Include="Collections\CollectionManager.cs" />
     <Compile Include="Collections\CollectionsDynamicFolder.cs" />
     <Compile Include="Collections\CollectionsDynamicFolder.cs" />
     <Compile Include="Configuration\ServerConfigurationManager.cs" />
     <Compile Include="Configuration\ServerConfigurationManager.cs" />
+    <Compile Include="Cryptography\ASN1.cs" />
+    <Compile Include="Cryptography\ASN1Convert.cs" />
+    <Compile Include="Cryptography\BitConverterLE.cs" />
+    <Compile Include="Cryptography\CertificateGenerator.cs" />
+    <Compile Include="Cryptography\CryptoConvert.cs" />
+    <Compile Include="Cryptography\PfxGenerator.cs" />
+    <Compile Include="Cryptography\PKCS1.cs" />
+    <Compile Include="Cryptography\PKCS12.cs" />
+    <Compile Include="Cryptography\PKCS7.cs" />
+    <Compile Include="Cryptography\PKCS8.cs" />
+    <Compile Include="Cryptography\X501Name.cs" />
+    <Compile Include="Cryptography\X509Builder.cs" />
+    <Compile Include="Cryptography\X509Certificate.cs" />
+    <Compile Include="Cryptography\X509CertificateBuilder.cs" />
+    <Compile Include="Cryptography\X509CertificateCollection.cs" />
+    <Compile Include="Cryptography\X509Extension.cs" />
+    <Compile Include="Cryptography\X509Extensions.cs" />
+    <Compile Include="Cryptography\X520Attributes.cs" />
     <Compile Include="Data\ManagedConnection.cs" />
     <Compile Include="Data\ManagedConnection.cs" />
     <Compile Include="Data\SqliteDisplayPreferencesRepository.cs" />
     <Compile Include="Data\SqliteDisplayPreferencesRepository.cs" />
     <Compile Include="Data\SqliteItemRepository.cs" />
     <Compile Include="Data\SqliteItemRepository.cs" />
@@ -63,6 +84,7 @@
     <Compile Include="Devices\DeviceRepository.cs" />
     <Compile Include="Devices\DeviceRepository.cs" />
     <Compile Include="Dto\DtoService.cs" />
     <Compile Include="Dto\DtoService.cs" />
     <Compile Include="EntryPoints\AutomaticRestartEntryPoint.cs" />
     <Compile Include="EntryPoints\AutomaticRestartEntryPoint.cs" />
+    <Compile Include="EntryPoints\ExternalPortForwarding.cs" />
     <Compile Include="EntryPoints\KeepServerAwake.cs" />
     <Compile Include="EntryPoints\KeepServerAwake.cs" />
     <Compile Include="EntryPoints\LibraryChangedNotifier.cs" />
     <Compile Include="EntryPoints\LibraryChangedNotifier.cs" />
     <Compile Include="EntryPoints\LoadRegistrations.cs" />
     <Compile Include="EntryPoints\LoadRegistrations.cs" />
@@ -78,6 +100,7 @@
     <Compile Include="FFMpeg\FFMpegInfo.cs" />
     <Compile Include="FFMpeg\FFMpegInfo.cs" />
     <Compile Include="FFMpeg\FFMpegInstallInfo.cs" />
     <Compile Include="FFMpeg\FFMpegInstallInfo.cs" />
     <Compile Include="FFMpeg\FFMpegLoader.cs" />
     <Compile Include="FFMpeg\FFMpegLoader.cs" />
+    <Compile Include="HttpServerFactory.cs" />
     <Compile Include="HttpServer\FileWriter.cs" />
     <Compile Include="HttpServer\FileWriter.cs" />
     <Compile Include="HttpServer\HttpListenerHost.cs" />
     <Compile Include="HttpServer\HttpListenerHost.cs" />
     <Compile Include="HttpServer\HttpResultFactory.cs" />
     <Compile Include="HttpServer\HttpResultFactory.cs" />
@@ -99,7 +122,9 @@
     <Compile Include="Images\BaseDynamicImageProvider.cs" />
     <Compile Include="Images\BaseDynamicImageProvider.cs" />
     <Compile Include="IO\AsyncStreamCopier.cs" />
     <Compile Include="IO\AsyncStreamCopier.cs" />
     <Compile Include="IO\FileRefresher.cs" />
     <Compile Include="IO\FileRefresher.cs" />
+    <Compile Include="IO\LibraryMonitor.cs" />
     <Compile Include="IO\MbLinkShortcutHandler.cs" />
     <Compile Include="IO\MbLinkShortcutHandler.cs" />
+    <Compile Include="IO\MemoryStreamProvider.cs" />
     <Compile Include="IO\ThrottledStream.cs" />
     <Compile Include="IO\ThrottledStream.cs" />
     <Compile Include="Library\CoreResolutionIgnoreRule.cs" />
     <Compile Include="Library\CoreResolutionIgnoreRule.cs" />
     <Compile Include="Library\LibraryManager.cs" />
     <Compile Include="Library\LibraryManager.cs" />
@@ -170,6 +195,8 @@
     <Compile Include="LiveTv\TunerHosts\MulticastStream.cs" />
     <Compile Include="LiveTv\TunerHosts\MulticastStream.cs" />
     <Compile Include="LiveTv\TunerHosts\QueueStream.cs" />
     <Compile Include="LiveTv\TunerHosts\QueueStream.cs" />
     <Compile Include="Localization\LocalizationManager.cs" />
     <Compile Include="Localization\LocalizationManager.cs" />
+    <Compile Include="Localization\TextLocalizer.cs" />
+    <Compile Include="Logging\ConsoleLogger.cs" />
     <Compile Include="Logging\UnhandledExceptionWriter.cs" />
     <Compile Include="Logging\UnhandledExceptionWriter.cs" />
     <Compile Include="MediaEncoder\EncodingManager.cs" />
     <Compile Include="MediaEncoder\EncodingManager.cs" />
     <Compile Include="Migrations\IVersionMigration.cs" />
     <Compile Include="Migrations\IVersionMigration.cs" />
@@ -249,6 +276,7 @@
     <Compile Include="Sorting\StartDateComparer.cs" />
     <Compile Include="Sorting\StartDateComparer.cs" />
     <Compile Include="Sorting\StudioComparer.cs" />
     <Compile Include="Sorting\StudioComparer.cs" />
     <Compile Include="StartupOptions.cs" />
     <Compile Include="StartupOptions.cs" />
+    <Compile Include="SystemEvents.cs" />
     <Compile Include="TV\SeriesPostScanTask.cs" />
     <Compile Include="TV\SeriesPostScanTask.cs" />
     <Compile Include="TV\TVSeriesManager.cs" />
     <Compile Include="TV\TVSeriesManager.cs" />
     <Compile Include="Udp\UdpServer.cs" />
     <Compile Include="Udp\UdpServer.cs" />
@@ -260,6 +288,26 @@
     <EmbeddedResource Include="Localization\iso6392.txt" />
     <EmbeddedResource Include="Localization\iso6392.txt" />
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
+    <ProjectReference Include="..\Emby.Common.Implementations\Emby.Common.Implementations.csproj">
+      <Project>{1e37a338-9f57-4b70-bd6d-bb9c591e319b}</Project>
+      <Name>Emby.Common.Implementations</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\Emby.Dlna\Emby.Dlna.csproj">
+      <Project>{805844ab-e92f-45e6-9d99-4f6d48d129a5}</Project>
+      <Name>Emby.Dlna</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\Emby.Drawing\Emby.Drawing.csproj">
+      <Project>{08fff49b-f175-4807-a2b5-73b0ebd9f716}</Project>
+      <Name>Emby.Drawing</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\Emby.Photos\Emby.Photos.csproj">
+      <Project>{89ab4548-770d-41fd-a891-8daff44f452c}</Project>
+      <Name>Emby.Photos</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\MediaBrowser.Api\MediaBrowser.Api.csproj">
+      <Project>{4fd51ac5-2c16-4308-a993-c3a84f3b4582}</Project>
+      <Name>MediaBrowser.Api</Name>
+    </ProjectReference>
     <ProjectReference Include="..\MediaBrowser.Common\MediaBrowser.Common.csproj">
     <ProjectReference Include="..\MediaBrowser.Common\MediaBrowser.Common.csproj">
       <Project>{9142eefa-7570-41e1-bfcc-468bb571af2f}</Project>
       <Project>{9142eefa-7570-41e1-bfcc-468bb571af2f}</Project>
       <Name>MediaBrowser.Common</Name>
       <Name>MediaBrowser.Common</Name>
@@ -268,6 +316,10 @@
       <Project>{17e1f4e6-8abd-4fe5-9ecf-43d4b6087ba2}</Project>
       <Project>{17e1f4e6-8abd-4fe5-9ecf-43d4b6087ba2}</Project>
       <Name>MediaBrowser.Controller</Name>
       <Name>MediaBrowser.Controller</Name>
     </ProjectReference>
     </ProjectReference>
+    <ProjectReference Include="..\MediaBrowser.LocalMetadata\MediaBrowser.LocalMetadata.csproj">
+      <Project>{7ef9f3e0-697d-42f3-a08f-19deb5f84392}</Project>
+      <Name>MediaBrowser.LocalMetadata</Name>
+    </ProjectReference>
     <ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj">
     <ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj">
       <Project>{7eeeb4bb-f3e8-48fc-b4c5-70f0fff8329b}</Project>
       <Project>{7eeeb4bb-f3e8-48fc-b4c5-70f0fff8329b}</Project>
       <Name>MediaBrowser.Model</Name>
       <Name>MediaBrowser.Model</Name>
@@ -280,10 +332,29 @@
       <Project>{2e781478-814d-4a48-9d80-bff206441a65}</Project>
       <Project>{2e781478-814d-4a48-9d80-bff206441a65}</Project>
       <Name>MediaBrowser.Server.Implementations</Name>
       <Name>MediaBrowser.Server.Implementations</Name>
     </ProjectReference>
     </ProjectReference>
+    <ProjectReference Include="..\MediaBrowser.WebDashboard\MediaBrowser.WebDashboard.csproj">
+      <Project>{5624b7b5-b5a7-41d8-9f10-cc5611109619}</Project>
+      <Name>MediaBrowser.WebDashboard</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\MediaBrowser.XbmcMetadata\MediaBrowser.XbmcMetadata.csproj">
+      <Project>{23499896-b135-4527-8574-c26e926ea99e}</Project>
+      <Name>MediaBrowser.XbmcMetadata</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\Mono.Nat\Mono.Nat.csproj">
+      <Project>{cb7f2326-6497-4a3d-ba03-48513b17a7be}</Project>
+      <Name>Mono.Nat</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\OpenSubtitlesHandler\OpenSubtitlesHandler.csproj">
+      <Project>{4a4402d4-e910-443b-b8fc-2c18286a2ca0}</Project>
+      <Name>OpenSubtitlesHandler</Name>
+    </ProjectReference>
     <ProjectReference Include="..\SocketHttpListener\SocketHttpListener.csproj">
     <ProjectReference Include="..\SocketHttpListener\SocketHttpListener.csproj">
       <Project>{1d74413b-e7cf-455b-b021-f52bdf881542}</Project>
       <Project>{1d74413b-e7cf-455b-b021-f52bdf881542}</Project>
       <Name>SocketHttpListener</Name>
       <Name>SocketHttpListener</Name>
     </ProjectReference>
     </ProjectReference>
+    <Reference Include="Emby.Server.MediaEncoding">
+      <HintPath>..\ThirdParty\emby\Emby.Server.MediaEncoding.dll</HintPath>
+    </Reference>
     <Reference Include="Emby.XmlTv, Version=1.0.6387.29335, Culture=neutral, processorArchitecture=MSIL">
     <Reference Include="Emby.XmlTv, Version=1.0.6387.29335, Culture=neutral, processorArchitecture=MSIL">
       <HintPath>..\packages\Emby.XmlTv.1.0.9\lib\portable-net45+win8\Emby.XmlTv.dll</HintPath>
       <HintPath>..\packages\Emby.XmlTv.1.0.9\lib\portable-net45+win8\Emby.XmlTv.dll</HintPath>
       <Private>True</Private>
       <Private>True</Private>
@@ -292,6 +363,15 @@
       <HintPath>..\packages\MediaBrowser.Naming.1.0.5\lib\portable-net45+win8\MediaBrowser.Naming.dll</HintPath>
       <HintPath>..\packages\MediaBrowser.Naming.1.0.5\lib\portable-net45+win8\MediaBrowser.Naming.dll</HintPath>
       <Private>True</Private>
       <Private>True</Private>
     </Reference>
     </Reference>
+    <Reference Include="Microsoft.IO.RecyclableMemoryStream, Version=1.2.2.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
+      <HintPath>..\packages\Microsoft.IO.RecyclableMemoryStream.1.2.2\lib\net45\Microsoft.IO.RecyclableMemoryStream.dll</HintPath>
+    </Reference>
+    <Reference Include="ServiceStack.Text, Version=4.5.12.0, Culture=neutral, processorArchitecture=MSIL">
+      <HintPath>..\packages\ServiceStack.Text.4.5.12\lib\net45\ServiceStack.Text.dll</HintPath>
+    </Reference>
+    <Reference Include="SimpleInjector, Version=4.0.8.0, Culture=neutral, PublicKeyToken=984cb50dea722e99, processorArchitecture=MSIL">
+      <HintPath>..\packages\SimpleInjector.4.0.8\lib\net45\SimpleInjector.dll</HintPath>
+    </Reference>
     <Reference Include="SQLitePCL.pretty, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
     <Reference Include="SQLitePCL.pretty, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
       <HintPath>..\packages\SQLitePCL.pretty.1.1.0\lib\portable-net45+netcore45+wpa81+wp8\SQLitePCL.pretty.dll</HintPath>
       <HintPath>..\packages\SQLitePCL.pretty.1.1.0\lib\portable-net45+netcore45+wpa81+wp8\SQLitePCL.pretty.dll</HintPath>
       <Private>True</Private>
       <Private>True</Private>
@@ -299,10 +379,10 @@
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
     <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.7\lib\net45\SQLitePCLRaw.core.dll</HintPath>
-      <Private>True</Private>
+      <HintPath>..\packages\SQLitePCLRaw.core.1.1.8\lib\net45\SQLitePCLRaw.core.dll</HintPath>
     </Reference>
     </Reference>
     <Reference Include="System" />
     <Reference Include="System" />
+    <Reference Include="System.Configuration" />
     <Reference Include="System.Core" />
     <Reference Include="System.Core" />
     <Reference Include="System.Runtime.Serialization" />
     <Reference Include="System.Runtime.Serialization" />
     <Reference Include="System.Xml.Linq" />
     <Reference Include="System.Xml.Linq" />

+ 4 - 3
Emby.Server.Core/EntryPoints/ExternalPortForwarding.cs → Emby.Server.Implementations/EntryPoints/ExternalPortForwarding.cs

@@ -2,6 +2,7 @@
 using System.Collections.Generic;
 using System.Collections.Generic;
 using System.Globalization;
 using System.Globalization;
 using System.Net;
 using System.Net;
+using System.Threading.Tasks;
 using MediaBrowser.Common.Net;
 using MediaBrowser.Common.Net;
 using MediaBrowser.Controller;
 using MediaBrowser.Controller;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Configuration;
@@ -11,9 +12,9 @@ using MediaBrowser.Model.Events;
 using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.Threading;
 using MediaBrowser.Model.Threading;
 using Mono.Nat;
 using Mono.Nat;
-using System.Threading.Tasks;
+using MediaBrowser.Model.Extensions;
 
 
-namespace Emby.Server.Core.EntryPoints
+namespace Emby.Server.Implementations.EntryPoints
 {
 {
     public class ExternalPortForwarding : IServerEntryPoint
     public class ExternalPortForwarding : IServerEntryPoint
     {
     {
@@ -50,7 +51,7 @@ namespace Emby.Server.Core.EntryPoints
             values.Add(config.EnableHttps.ToString());
             values.Add(config.EnableHttps.ToString());
             values.Add(_appHost.EnableHttps.ToString());
             values.Add(_appHost.EnableHttps.ToString());
 
 
-            return string.Join("|", values.ToArray());
+            return string.Join("|", values.ToArray(values.Count));
         }
         }
 
 
         void _config_ConfigurationUpdated(object sender, EventArgs e)
         void _config_ConfigurationUpdated(object sender, EventArgs e)

+ 2 - 1
Emby.Server.Implementations/EntryPoints/UsageEntryPoint.cs

@@ -12,6 +12,7 @@ using System.Threading;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
 using MediaBrowser.Controller;
 using MediaBrowser.Controller;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Model.Extensions;
 
 
 namespace Emby.Server.Implementations.EntryPoints
 namespace Emby.Server.Implementations.EntryPoints
 {
 {
@@ -58,7 +59,7 @@ namespace Emby.Server.Implementations.EntryPoints
                     session.ApplicationVersion
                     session.ApplicationVersion
                 };
                 };
 
 
-                var key = string.Join("_", keys.ToArray()).GetMD5();
+                var key = string.Join("_", keys.ToArray(keys.Count)).GetMD5();
 
 
                 _apps.GetOrAdd(key, guid => GetNewClientInfo(session));
                 _apps.GetOrAdd(key, guid => GetNewClientInfo(session));
             }
             }

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

@@ -125,13 +125,6 @@ namespace Emby.Server.Implementations.HttpServer
             return _appHost.CreateInstance(type);
             return _appHost.CreateInstance(type);
         }
         }
 
 
-        private ServiceController CreateServiceController()
-        {
-            var types = _restServices.Select(r => r.GetType()).ToArray();
-
-            return new ServiceController(() => types);
-        }
-
         /// <summary>
         /// <summary>
         /// Applies the request filters. Returns whether or not the request has been handled 
         /// Applies the request filters. Returns whether or not the request has been handled 
         /// and no more processing should be done.
         /// and no more processing should be done.
@@ -186,7 +179,7 @@ namespace Emby.Server.Implementations.HttpServer
 
 
             attributes.Sort((x, y) => x.Priority - y.Priority);
             attributes.Sort((x, y) => x.Priority - y.Priority);
 
 
-            return attributes.ToArray();
+            return attributes.ToArray(attributes.Count);
         }
         }
 
 
         /// <summary>
         /// <summary>
@@ -697,11 +690,13 @@ namespace Emby.Server.Implementations.HttpServer
         {
         {
             _restServices.AddRange(services);
             _restServices.AddRange(services);
 
 
-            ServiceController = CreateServiceController();
+            ServiceController = new ServiceController();
 
 
             _logger.Info("Calling ServiceStack AppHost.Init");
             _logger.Info("Calling ServiceStack AppHost.Init");
 
 
-            ServiceController.Init(this);
+            var types = _restServices.Select(r => r.GetType()).ToArray();
+
+            ServiceController.Init(this, types);
 
 
             var requestFilters = _appHost.GetExports<IRequestFilter>().ToList();
             var requestFilters = _appHost.GetExports<IRequestFilter>().ToList();
             foreach (var filter in requestFilters)
             foreach (var filter in requestFilters)
@@ -741,7 +736,7 @@ namespace Emby.Server.Implementations.HttpServer
                 });
                 });
             }
             }
 
 
-            return routes.ToArray();
+            return routes.ToArray(routes.Count);
         }
         }
 
 
         public Func<string, object> GetParseFn(Type propertyType)
         public Func<string, object> GetParseFn(Type propertyType)

+ 2 - 1
Emby.Server.Implementations/HttpServer/LoggerUtils.cs

@@ -4,6 +4,7 @@ using System.Globalization;
 using System.Linq;
 using System.Linq;
 using MediaBrowser.Model.Services;
 using MediaBrowser.Model.Services;
 using SocketHttpListener.Net;
 using SocketHttpListener.Net;
+using MediaBrowser.Model.Extensions;
 
 
 namespace Emby.Server.Implementations.HttpServer
 namespace Emby.Server.Implementations.HttpServer
 {
 {
@@ -29,7 +30,7 @@ namespace Emby.Server.Implementations.HttpServer
             }
             }
             else
             else
             {
             {
-                var headerText = string.Join(", ", headers.Select(i => i.Name + "=" + i.Value).ToArray());
+                var headerText = string.Join(", ", headers.Select(i => i.Name + "=" + i.Value).ToArray(headers.Count));
 
 
                 logger.Info("HTTP {0} {1}. {2}", method, url, headerText);
                 logger.Info("HTTP {0} {1}. {2}", method, url, headerText);
             }
             }

+ 2 - 1
Emby.Server.Implementations/HttpServer/SocketSharp/HttpUtility.cs

@@ -3,6 +3,7 @@ using System.Collections;
 using System.Collections.Generic;
 using System.Collections.Generic;
 using System.Text;
 using System.Text;
 using MediaBrowser.Model.Services;
 using MediaBrowser.Model.Services;
+using MediaBrowser.Model.Extensions;
 
 
 namespace Emby.Server.Implementations.HttpServer.SocketSharp
 namespace Emby.Server.Implementations.HttpServer.SocketSharp
 {
 {
@@ -585,7 +586,7 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp
                     WriteCharBytes(bytes, ch, e);
                     WriteCharBytes(bytes, ch, e);
             }
             }
 
 
-            byte[] buf = bytes.ToArray();
+            byte[] buf = bytes.ToArray(bytes.Count);
             bytes = null;
             bytes = null;
             return e.GetString(buf, 0, buf.Length);
             return e.GetString(buf, 0, buf.Length);
 
 

+ 1 - 3
Emby.Server.Core/HttpServerFactory.cs → Emby.Server.Implementations/HttpServerFactory.cs

@@ -1,9 +1,7 @@
 using System;
 using System;
 using System.IO;
 using System.IO;
 using System.Net.Security;
 using System.Net.Security;
-using System.Net.Sockets;
 using System.Security.Cryptography.X509Certificates;
 using System.Security.Cryptography.X509Certificates;
-using System.Threading;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
 using Emby.Common.Implementations.Net;
 using Emby.Common.Implementations.Net;
 using Emby.Server.Implementations.HttpServer;
 using Emby.Server.Implementations.HttpServer;
@@ -21,7 +19,7 @@ using MediaBrowser.Model.Text;
 using ServiceStack.Text.Jsv;
 using ServiceStack.Text.Jsv;
 using SocketHttpListener.Primitives;
 using SocketHttpListener.Primitives;
 
 
-namespace Emby.Server.Core
+namespace Emby.Server.Implementations
 {
 {
     /// <summary>
     /// <summary>
     /// Class ServerFactory
     /// Class ServerFactory

+ 1 - 2
Emby.Server.Core/IO/LibraryMonitor.cs → Emby.Server.Implementations/IO/LibraryMonitor.cs

@@ -13,9 +13,8 @@ using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.System;
 using MediaBrowser.Model.System;
 using MediaBrowser.Model.Tasks;
 using MediaBrowser.Model.Tasks;
 using MediaBrowser.Model.Threading;
 using MediaBrowser.Model.Threading;
-using Emby.Server.Implementations.IO;
 
 
-namespace Emby.Server.Core.IO
+namespace Emby.Server.Implementations.IO
 {
 {
     public class LibraryMonitor : ILibraryMonitor
     public class LibraryMonitor : ILibraryMonitor
     {
     {

+ 1 - 1
Emby.Server.Core/IO/MemoryStreamProvider.cs → Emby.Server.Implementations/IO/MemoryStreamProvider.cs

@@ -2,7 +2,7 @@
 using MediaBrowser.Model.IO;
 using MediaBrowser.Model.IO;
 using Microsoft.IO;
 using Microsoft.IO;
 
 
-namespace Emby.Server.Core.IO
+namespace Emby.Server.Implementations.IO
 {
 {
     public class RecyclableMemoryStreamProvider : IMemoryStreamFactory
     public class RecyclableMemoryStreamProvider : IMemoryStreamFactory
     {
     {

+ 3 - 7
Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs

@@ -293,20 +293,16 @@ namespace Emby.Server.Implementations.Images
             return true;
             return true;
         }
         }
 
 
-        protected List<BaseItem> GetFinalItems(List<BaseItem> items)
+        protected List<BaseItem> GetFinalItems(IEnumerable<BaseItem> items)
         {
         {
             return GetFinalItems(items, 4);
             return GetFinalItems(items, 4);
         }
         }
 
 
-        protected virtual List<BaseItem> GetFinalItems(List<BaseItem> items, int limit)
+        protected virtual List<BaseItem> GetFinalItems(IEnumerable<BaseItem> items, int limit)
         {
         {
-            // Rotate the images once every x days
-            var random = DateTime.Now.DayOfYear % MaxImageAgeDays;
-
             return items
             return items
-                .OrderBy(i => (random + string.Empty + items.IndexOf(i)).GetMD5())
+                .OrderBy(i => Guid.NewGuid())
                 .Take(limit)
                 .Take(limit)
-                .OrderBy(i => i.Name)
                 .ToList();
                 .ToList();
         }
         }
 
 

+ 7 - 30
Emby.Server.Implementations/Library/LibraryManager.cs

@@ -136,14 +136,6 @@ namespace Emby.Server.Implementations.Library
         /// <value>The configuration manager.</value>
         /// <value>The configuration manager.</value>
         private IServerConfigurationManager ConfigurationManager { get; set; }
         private IServerConfigurationManager ConfigurationManager { get; set; }
 
 
-        /// <summary>
-        /// A collection of items that may be referenced from multiple physical places in the library
-        /// (typically, multiple user roots).  We store them here and be sure they all reference a
-        /// single instance.
-        /// </summary>
-        /// <value>The by reference items.</value>
-        private ConcurrentDictionary<Guid, BaseItem> ByReferenceItems { get; set; }
-
         private readonly Func<ILibraryMonitor> _libraryMonitorFactory;
         private readonly Func<ILibraryMonitor> _libraryMonitorFactory;
         private readonly Func<IProviderManager> _providerManagerFactory;
         private readonly Func<IProviderManager> _providerManagerFactory;
         private readonly Func<IUserViewManager> _userviewManager;
         private readonly Func<IUserViewManager> _userviewManager;
@@ -186,7 +178,6 @@ namespace Emby.Server.Implementations.Library
             _fileSystem = fileSystem;
             _fileSystem = fileSystem;
             _providerManagerFactory = providerManagerFactory;
             _providerManagerFactory = providerManagerFactory;
             _userviewManager = userviewManager;
             _userviewManager = userviewManager;
-            ByReferenceItems = new ConcurrentDictionary<Guid, BaseItem>();
             _libraryItemsCache = new ConcurrentDictionary<Guid, BaseItem>();
             _libraryItemsCache = new ConcurrentDictionary<Guid, BaseItem>();
 
 
             ConfigurationManager.ConfigurationUpdated += ConfigurationUpdated;
             ConfigurationManager.ConfigurationUpdated += ConfigurationUpdated;
@@ -560,22 +551,6 @@ namespace Emby.Server.Implementations.Library
             return key.GetMD5();
             return key.GetMD5();
         }
         }
 
 
-        /// <summary>
-        /// Ensure supplied item has only one instance throughout
-        /// </summary>
-        /// <param name="item">The item.</param>
-        /// <returns>The proper instance to the item</returns>
-        public BaseItem GetOrAddByReferenceItem(BaseItem item)
-        {
-            // Add this item to our list if not there already
-            if (!ByReferenceItems.TryAdd(item.Id, item))
-            {
-                // Already there - return the existing reference
-                item = ByReferenceItems[item.Id];
-            }
-            return item;
-        }
-
         public BaseItem ResolvePath(FileSystemMetadata fileInfo,
         public BaseItem ResolvePath(FileSystemMetadata fileInfo,
             Folder parent = null)
             Folder parent = null)
         {
         {
@@ -1298,7 +1273,7 @@ namespace Emby.Server.Implementations.Library
             return item;
             return item;
         }
         }
 
 
-        public IEnumerable<BaseItem> GetItemList(InternalItemsQuery query, bool allowExternalContent)
+        public List<BaseItem> GetItemList(InternalItemsQuery query, bool allowExternalContent)
         {
         {
             if (query.Recursive && query.ParentId.HasValue)
             if (query.Recursive && query.ParentId.HasValue)
             {
             {
@@ -1317,7 +1292,7 @@ namespace Emby.Server.Implementations.Library
             return ItemRepository.GetItemList(query);
             return ItemRepository.GetItemList(query);
         }
         }
 
 
-        public IEnumerable<BaseItem> GetItemList(InternalItemsQuery query)
+        public List<BaseItem> GetItemList(InternalItemsQuery query)
         {
         {
             return GetItemList(query, true);
             return GetItemList(query, true);
         }
         }
@@ -1341,7 +1316,7 @@ namespace Emby.Server.Implementations.Library
             return ItemRepository.GetCount(query);
             return ItemRepository.GetCount(query);
         }
         }
 
 
-        public IEnumerable<BaseItem> GetItemList(InternalItemsQuery query, List<BaseItem> parents)
+        public List<BaseItem> GetItemList(InternalItemsQuery query, List<BaseItem> parents)
         {
         {
             SetTopParentIdsOrAncestors(query, parents);
             SetTopParentIdsOrAncestors(query, parents);
 
 
@@ -1515,9 +1490,11 @@ namespace Emby.Server.Implementations.Library
                 return ItemRepository.GetItems(query);
                 return ItemRepository.GetItems(query);
             }
             }
 
 
+            var list = ItemRepository.GetItemList(query);
+
             return new QueryResult<BaseItem>
             return new QueryResult<BaseItem>
             {
             {
-                Items = ItemRepository.GetItemList(query).ToArray()
+                Items = list.ToArray(list.Count)
             };
             };
         }
         }
 
 
@@ -2610,7 +2587,7 @@ namespace Emby.Server.Implementations.Library
 
 
             var resolvers = new IItemResolver[]
             var resolvers = new IItemResolver[]
             {
             {
-                new GenericVideoResolver<Trailer>(this)
+                new GenericVideoResolver<Trailer>(this, _fileSystem)
             };
             };
 
 
             return ResolvePaths(files, directoryService, null, new LibraryOptions(), null, resolvers)
             return ResolvePaths(files, directoryService, null, new LibraryOptions(), null, resolvers)

+ 3 - 2
Emby.Server.Implementations/Library/LocalTrailerPostScanTask.cs

@@ -3,6 +3,7 @@ using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Entities;
 using System;
 using System;
+using System.Collections.Generic;
 using System.Linq;
 using System.Linq;
 using System.Threading;
 using System.Threading;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
@@ -45,7 +46,7 @@ namespace Emby.Server.Implementations.Library
                 Recursive = true,
                 Recursive = true,
                 DtoOptions = new DtoOptions(false)
                 DtoOptions = new DtoOptions(false)
 
 
-            }).ToArray();
+            });
 
 
             var numComplete = 0;
             var numComplete = 0;
 
 
@@ -64,7 +65,7 @@ namespace Emby.Server.Implementations.Library
             progress.Report(100);
             progress.Report(100);
         }
         }
 
 
-        private async Task AssignTrailers(IHasTrailers item, BaseItem[] channelTrailers)
+        private async Task AssignTrailers(IHasTrailers item, IEnumerable<BaseItem> channelTrailers)
         {
         {
             if (item is Game)
             if (item is Game)
             {
             {

+ 11 - 11
Emby.Server.Implementations/Library/MusicManager.cs

@@ -19,27 +19,27 @@ namespace Emby.Server.Implementations.Library
             _libraryManager = libraryManager;
             _libraryManager = libraryManager;
         }
         }
 
 
-        public IEnumerable<Audio> GetInstantMixFromSong(Audio item, User user, DtoOptions dtoOptions)
+        public List<BaseItem> GetInstantMixFromSong(Audio item, User user, DtoOptions dtoOptions)
         {
         {
             var list = new List<Audio>
             var list = new List<Audio>
             {
             {
                 item
                 item
             };
             };
 
 
-            return list.Concat(GetInstantMixFromGenres(item.Genres, user, dtoOptions));
+            return list.Concat(GetInstantMixFromGenres(item.Genres, user, dtoOptions)).ToList();
         }
         }
 
 
-        public IEnumerable<Audio> GetInstantMixFromArtist(MusicArtist item, User user, DtoOptions dtoOptions)
+        public List<BaseItem> GetInstantMixFromArtist(MusicArtist item, User user, DtoOptions dtoOptions)
         {
         {
             return GetInstantMixFromGenres(item.Genres, user, dtoOptions);
             return GetInstantMixFromGenres(item.Genres, user, dtoOptions);
         }
         }
 
 
-        public IEnumerable<Audio> GetInstantMixFromAlbum(MusicAlbum item, User user, DtoOptions dtoOptions)
+        public List<BaseItem> GetInstantMixFromAlbum(MusicAlbum item, User user, DtoOptions dtoOptions)
         {
         {
             return GetInstantMixFromGenres(item.Genres, user, dtoOptions);
             return GetInstantMixFromGenres(item.Genres, user, dtoOptions);
         }
         }
 
 
-        public IEnumerable<Audio> GetInstantMixFromFolder(Folder item, User user, DtoOptions dtoOptions)
+        public List<BaseItem> GetInstantMixFromFolder(Folder item, User user, DtoOptions dtoOptions)
         {
         {
             var genres = item
             var genres = item
                .GetRecursiveChildren(user, new InternalItemsQuery(user)
                .GetRecursiveChildren(user, new InternalItemsQuery(user)
@@ -55,12 +55,12 @@ namespace Emby.Server.Implementations.Library
             return GetInstantMixFromGenres(genres, user, dtoOptions);
             return GetInstantMixFromGenres(genres, user, dtoOptions);
         }
         }
 
 
-        public IEnumerable<Audio> GetInstantMixFromPlaylist(Playlist item, User user, DtoOptions dtoOptions)
+        public List<BaseItem> GetInstantMixFromPlaylist(Playlist item, User user, DtoOptions dtoOptions)
         {
         {
             return GetInstantMixFromGenres(item.Genres, user, dtoOptions);
             return GetInstantMixFromGenres(item.Genres, user, dtoOptions);
         }
         }
 
 
-        public IEnumerable<Audio> GetInstantMixFromGenres(IEnumerable<string> genres, User user, DtoOptions dtoOptions)
+        public List<BaseItem> GetInstantMixFromGenres(IEnumerable<string> genres, User user, DtoOptions dtoOptions)
         {
         {
             var genreIds = genres.DistinctNames().Select(i =>
             var genreIds = genres.DistinctNames().Select(i =>
             {
             {
@@ -78,7 +78,7 @@ namespace Emby.Server.Implementations.Library
             return GetInstantMixFromGenreIds(genreIds, user, dtoOptions);
             return GetInstantMixFromGenreIds(genreIds, user, dtoOptions);
         }
         }
 
 
-        public IEnumerable<Audio> GetInstantMixFromGenreIds(IEnumerable<string> genreIds, User user, DtoOptions dtoOptions)
+        public List<BaseItem> GetInstantMixFromGenreIds(IEnumerable<string> genreIds, User user, DtoOptions dtoOptions)
         {
         {
             return _libraryManager.GetItemList(new InternalItemsQuery(user)
             return _libraryManager.GetItemList(new InternalItemsQuery(user)
             {
             {
@@ -92,10 +92,10 @@ namespace Emby.Server.Implementations.Library
 
 
                 DtoOptions = dtoOptions
                 DtoOptions = dtoOptions
 
 
-            }).Cast<Audio>();
+            });
         }
         }
 
 
-        public IEnumerable<Audio> GetInstantMixFromItem(BaseItem item, User user, DtoOptions dtoOptions)
+        public List<BaseItem> GetInstantMixFromItem(BaseItem item, User user, DtoOptions dtoOptions)
         {
         {
             var genre = item as MusicGenre;
             var genre = item as MusicGenre;
             if (genre != null)
             if (genre != null)
@@ -133,7 +133,7 @@ namespace Emby.Server.Implementations.Library
                 return GetInstantMixFromFolder(folder, user, dtoOptions);
                 return GetInstantMixFromFolder(folder, user, dtoOptions);
             }
             }
 
 
-            return new Audio[] { };
+            return new List<BaseItem>();
         }
         }
     }
     }
 }
 }

+ 5 - 2
Emby.Server.Implementations/Library/Resolvers/BaseVideoResolver.cs

@@ -6,6 +6,7 @@ using System;
 using System.IO;
 using System.IO;
 using System.Linq;
 using System.Linq;
 using MediaBrowser.Controller.Providers;
 using MediaBrowser.Controller.Providers;
+using MediaBrowser.Model.IO;
 using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.Logging;
 
 
 namespace Emby.Server.Implementations.Library.Resolvers
 namespace Emby.Server.Implementations.Library.Resolvers
@@ -18,9 +19,11 @@ namespace Emby.Server.Implementations.Library.Resolvers
         where T : Video, new()
         where T : Video, new()
     {
     {
         protected readonly ILibraryManager LibraryManager;
         protected readonly ILibraryManager LibraryManager;
+        protected readonly IFileSystem FileSystem;
 
 
-        protected BaseVideoResolver(ILibraryManager libraryManager)
+        protected BaseVideoResolver(ILibraryManager libraryManager, IFileSystem fileSystem)
         {
         {
+            FileSystem = fileSystem;
             LibraryManager = libraryManager;
             LibraryManager = libraryManager;
         }
         }
 
 
@@ -271,7 +274,7 @@ namespace Emby.Server.Implementations.Library.Resolvers
                 return false;
                 return false;
             }
             }
 
 
-            return directoryService.GetFilePaths(fullPath).Any(i => string.Equals(Path.GetExtension(i), ".vob", StringComparison.OrdinalIgnoreCase));
+            return FileSystem.GetFilePaths(fullPath).Any(i => string.Equals(Path.GetExtension(i), ".vob", StringComparison.OrdinalIgnoreCase));
         }
         }
 
 
         /// <summary>
         /// <summary>

+ 5 - 7
Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs

@@ -23,11 +23,6 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
     /// </summary>
     /// </summary>
     public class MovieResolver : BaseVideoResolver<Video>, IMultiItemResolver
     public class MovieResolver : BaseVideoResolver<Video>, IMultiItemResolver
     {
     {
-        public MovieResolver(ILibraryManager libraryManager)
-            : base(libraryManager)
-        {
-        }
-
         /// <summary>
         /// <summary>
         /// Gets the priority.
         /// Gets the priority.
         /// </summary>
         /// </summary>
@@ -452,8 +447,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
 
 
             var folderPaths = multiDiscFolders.Select(i => i.FullName).Where(i =>
             var folderPaths = multiDiscFolders.Select(i => i.FullName).Where(i =>
             {
             {
-                var subFileEntries = directoryService.GetFileSystemEntries(i)
-                    .ToList();
+                var subFileEntries = directoryService.GetFileSystemEntries(i);
 
 
                 var subfolders = subFileEntries
                 var subfolders = subFileEntries
                  .Where(e => e.IsDirectory)
                  .Where(e => e.IsDirectory)
@@ -547,5 +541,9 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
 
 
             return !validCollectionTypes.Contains(collectionType, StringComparer.OrdinalIgnoreCase);
             return !validCollectionTypes.Contains(collectionType, StringComparer.OrdinalIgnoreCase);
         }
         }
+
+        public MovieResolver(ILibraryManager libraryManager, IFileSystem fileSystem) : base(libraryManager, fileSystem)
+        {
+        }
     }
     }
 }
 }

+ 1 - 1
Emby.Server.Implementations/Library/Resolvers/PhotoResolver.cs

@@ -44,7 +44,7 @@ namespace Emby.Server.Implementations.Library.Resolvers
                         var filename = Path.GetFileNameWithoutExtension(args.Path);
                         var filename = Path.GetFileNameWithoutExtension(args.Path);
 
 
                         // Make sure the image doesn't belong to a video file
                         // Make sure the image doesn't belong to a video file
-                        if (args.DirectoryService.GetFilePaths(_fileSystem.GetDirectoryName(args.Path)).Any(i => IsOwnedByMedia(args.GetLibraryOptions(), i, filename)))
+                        if (_fileSystem.GetFilePaths(_fileSystem.GetDirectoryName(args.Path)).Any(i => IsOwnedByMedia(args.GetLibraryOptions(), i, filename)))
                         {
                         {
                             return null;
                             return null;
                         }
                         }

+ 5 - 4
Emby.Server.Implementations/Library/Resolvers/TV/EpisodeResolver.cs

@@ -3,6 +3,7 @@ using MediaBrowser.Controller.Entities.TV;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Library;
 using System.Linq;
 using System.Linq;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.IO;
 
 
 namespace Emby.Server.Implementations.Library.Resolvers.TV
 namespace Emby.Server.Implementations.Library.Resolvers.TV
 {
 {
@@ -11,10 +12,6 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV
     /// </summary>
     /// </summary>
     public class EpisodeResolver : BaseVideoResolver<Episode>
     public class EpisodeResolver : BaseVideoResolver<Episode>
     {
     {
-        public EpisodeResolver(ILibraryManager libraryManager) : base(libraryManager)
-        {
-        }
-
         /// <summary>
         /// <summary>
         /// Resolves the specified args.
         /// Resolves the specified args.
         /// </summary>
         /// </summary>
@@ -76,5 +73,9 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV
 
 
             return null;
             return null;
         }
         }
+
+        public EpisodeResolver(ILibraryManager libraryManager, IFileSystem fileSystem) : base(libraryManager, fileSystem)
+        {
+        }
     }
     }
 }
 }

+ 6 - 6
Emby.Server.Implementations/Library/Resolvers/VideoResolver.cs

@@ -1,6 +1,7 @@
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Resolvers;
 using MediaBrowser.Controller.Resolvers;
+using MediaBrowser.Model.IO;
 
 
 namespace Emby.Server.Implementations.Library.Resolvers
 namespace Emby.Server.Implementations.Library.Resolvers
 {
 {
@@ -9,11 +10,6 @@ namespace Emby.Server.Implementations.Library.Resolvers
     /// </summary>
     /// </summary>
     public class VideoResolver : BaseVideoResolver<Video>
     public class VideoResolver : BaseVideoResolver<Video>
     {
     {
-        public VideoResolver(ILibraryManager libraryManager)
-            : base(libraryManager)
-        {
-        }
-
         protected override Video Resolve(ItemResolveArgs args)
         protected override Video Resolve(ItemResolveArgs args)
         {
         {
             if (args.Parent != null)
             if (args.Parent != null)
@@ -33,12 +29,16 @@ namespace Emby.Server.Implementations.Library.Resolvers
         {
         {
             get { return ResolverPriority.Last; }
             get { return ResolverPriority.Last; }
         }
         }
+
+        public VideoResolver(ILibraryManager libraryManager, IFileSystem fileSystem) : base(libraryManager, fileSystem)
+        {
+        }
     }
     }
 
 
     public class GenericVideoResolver<T> : BaseVideoResolver<T>
     public class GenericVideoResolver<T> : BaseVideoResolver<T>
         where T : Video, new ()
         where T : Video, new ()
     {
     {
-        public GenericVideoResolver(ILibraryManager libraryManager) : base(libraryManager)
+        public GenericVideoResolver(ILibraryManager libraryManager, IFileSystem fileSystem) : base(libraryManager, fileSystem)
         {
         {
         }
         }
     }
     }

+ 3 - 2
Emby.Server.Implementations/Library/SearchEngine.cs

@@ -10,6 +10,7 @@ using System.Linq;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
 using MediaBrowser.Controller.Dto;
 using MediaBrowser.Controller.Dto;
 using MediaBrowser.Controller.Extensions;
 using MediaBrowser.Controller.Extensions;
+using MediaBrowser.Model.Extensions;
 
 
 namespace Emby.Server.Implementations.Library
 namespace Emby.Server.Implementations.Library
 {
 {
@@ -163,8 +164,8 @@ namespace Emby.Server.Implementations.Library
             var mediaItems = _libraryManager.GetItemList(new InternalItemsQuery(user)
             var mediaItems = _libraryManager.GetItemList(new InternalItemsQuery(user)
             {
             {
                 NameContains = searchTerm,
                 NameContains = searchTerm,
-                ExcludeItemTypes = excludeItemTypes.ToArray(),
-                IncludeItemTypes = includeItemTypes.ToArray(),
+                ExcludeItemTypes = excludeItemTypes.ToArray(excludeItemTypes.Count),
+                IncludeItemTypes = includeItemTypes.ToArray(includeItemTypes.Count),
                 Limit = query.Limit,
                 Limit = query.Limit,
                 IncludeItemsByName = string.IsNullOrWhiteSpace(query.ParentId),
                 IncludeItemsByName = string.IsNullOrWhiteSpace(query.ParentId),
                 ParentId = string.IsNullOrWhiteSpace(query.ParentId) ? (Guid?)null : new Guid(query.ParentId),
                 ParentId = string.IsNullOrWhiteSpace(query.ParentId) ? (Guid?)null : new Guid(query.ParentId),

+ 3 - 2
Emby.Server.Implementations/Library/UserViewManager.cs

@@ -15,6 +15,7 @@ using System.Threading.Tasks;
 using MediaBrowser.Controller.Dto;
 using MediaBrowser.Controller.Dto;
 using MediaBrowser.Controller.Entities.Audio;
 using MediaBrowser.Controller.Entities.Audio;
 using MediaBrowser.Model.Globalization;
 using MediaBrowser.Model.Globalization;
+using MediaBrowser.Model.Extensions;
 
 
 namespace Emby.Server.Implementations.Library
 namespace Emby.Server.Implementations.Library
 {
 {
@@ -231,7 +232,7 @@ namespace Emby.Server.Implementations.Library
             return list;
             return list;
         }
         }
 
 
-        private IEnumerable<BaseItem> GetItemsForLatestItems(User user, LatestItemsQuery request, DtoOptions options)
+        private List<BaseItem> GetItemsForLatestItems(User user, LatestItemsQuery request, DtoOptions options)
         {
         {
             var parentId = request.ParentId;
             var parentId = request.ParentId;
 
 
@@ -325,7 +326,7 @@ namespace Emby.Server.Implementations.Library
                 Limit = limit * 5,
                 Limit = limit * 5,
                 IsPlayed = isPlayed,
                 IsPlayed = isPlayed,
                 DtoOptions = options,
                 DtoOptions = options,
-                MediaTypes = mediaTypes.ToArray()
+                MediaTypes = mediaTypes.ToArray(mediaTypes.Count)
             };
             };
 
 
             if (parents.Count == 0)
             if (parents.Count == 0)

+ 5 - 12
Emby.Server.Implementations/Library/Validators/PeopleValidator.cs

@@ -55,28 +55,21 @@ namespace Emby.Server.Implementations.Library.Validators
         /// <returns>Task.</returns>
         /// <returns>Task.</returns>
         public async Task ValidatePeople(CancellationToken cancellationToken, IProgress<double> progress)
         public async Task ValidatePeople(CancellationToken cancellationToken, IProgress<double> progress)
         {
         {
-            var people = _libraryManager.GetPeople(new InternalPeopleQuery());
-
-            var dict = new Dictionary<string, bool>(StringComparer.OrdinalIgnoreCase);
-
-            foreach (var person in people)
-            {
-                dict[person.Name] = true;
-            }
+            var people = _libraryManager.GetPeopleNames(new InternalPeopleQuery());
 
 
             var numComplete = 0;
             var numComplete = 0;
 
 
-            _logger.Debug("Will refresh {0} people", dict.Count);
+            var numPeople = people.Count;
 
 
-            var numPeople = dict.Count;
+            _logger.Debug("Will refresh {0} people", numPeople);
 
 
-            foreach (var person in dict)
+            foreach (var person in people)
             {
             {
                 cancellationToken.ThrowIfCancellationRequested();
                 cancellationToken.ThrowIfCancellationRequested();
 
 
                 try
                 try
                 {
                 {
-                    var item = _libraryManager.GetPerson(person.Key);
+                    var item = _libraryManager.GetPerson(person);
 
 
                     var options = new MetadataRefreshOptions(_fileSystem)
                     var options = new MetadataRefreshOptions(_fileSystem)
                     {
                     {

+ 1 - 1
Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs

@@ -70,7 +70,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
                     return "ts";
                     return "ts";
                 }
                 }
 
 
-                return "mp4";
+                return "mkv";
             }
             }
         }
         }
 
 

+ 3 - 3
Emby.Server.Implementations/LiveTv/LiveTvDtoService.cs

@@ -176,7 +176,7 @@ namespace Emby.Server.Implementations.LiveTv
                 {
                 {
                     try
                     try
                     {
                     {
-                        dto.ParentBackdropImageTags = new List<string>
+                        dto.ParentBackdropImageTags = new string[]
                             {
                             {
                                 _imageProcessor.GetImageCacheTag(librarySeries, image)
                                 _imageProcessor.GetImageCacheTag(librarySeries, image)
                             };
                             };
@@ -218,14 +218,14 @@ namespace Emby.Server.Implementations.LiveTv
                         }
                         }
                     }
                     }
 
 
-                    if (dto.ParentBackdropImageTags == null || dto.ParentBackdropImageTags.Count == 0)
+                    if (dto.ParentBackdropImageTags == null || dto.ParentBackdropImageTags.Length == 0)
                     {
                     {
                         image = program.GetImageInfo(ImageType.Backdrop, 0);
                         image = program.GetImageInfo(ImageType.Backdrop, 0);
                         if (image != null)
                         if (image != null)
                         {
                         {
                             try
                             try
                             {
                             {
-                                dto.ParentBackdropImageTags = new List<string>
+                                dto.ParentBackdropImageTags = new string[]
                             {
                             {
                                 _imageProcessor.GetImageCacheTag(program, image)
                                 _imageProcessor.GetImageCacheTag(program, image)
                             };
                             };

+ 26 - 25
Emby.Server.Implementations/LiveTv/LiveTvManager.cs

@@ -173,7 +173,7 @@ namespace Emby.Server.Implementations.LiveTv
             }
             }
         }
         }
 
 
-        public async Task<QueryResult<LiveTvChannel>> GetInternalChannels(LiveTvChannelQuery query, DtoOptions dtoOptions, CancellationToken cancellationToken)
+        public async Task<QueryResult<BaseItem>> GetInternalChannels(LiveTvChannelQuery query, DtoOptions dtoOptions, CancellationToken cancellationToken)
         {
         {
             var user = string.IsNullOrEmpty(query.UserId) ? null : _userManager.GetUserById(query.UserId);
             var user = string.IsNullOrEmpty(query.UserId) ? null : _userManager.GetUserById(query.UserId);
 
 
@@ -208,15 +208,7 @@ namespace Emby.Server.Implementations.LiveTv
                 internalQuery.OrderBy.Add(new Tuple<string, SortOrder>(ItemSortBy.SortName, SortOrder.Ascending));
                 internalQuery.OrderBy.Add(new Tuple<string, SortOrder>(ItemSortBy.SortName, SortOrder.Ascending));
             }
             }
 
 
-            var channelResult = _libraryManager.GetItemsResult(internalQuery);
-
-            var result = new QueryResult<LiveTvChannel>
-            {
-                Items = channelResult.Items.Cast<LiveTvChannel>().ToArray(),
-                TotalRecordCount = channelResult.TotalRecordCount
-            };
-
-            return result;
+            return _libraryManager.GetItemsResult(internalQuery);
         }
         }
 
 
         public LiveTvChannel GetInternalChannel(string id)
         public LiveTvChannel GetInternalChannel(string id)
@@ -993,7 +985,9 @@ namespace Emby.Server.Implementations.LiveTv
 
 
             var queryResult = _libraryManager.QueryItems(internalQuery);
             var queryResult = _libraryManager.QueryItems(internalQuery);
 
 
-            var returnArray = (await _dtoService.GetBaseItemDtos(queryResult.Items, options, user).ConfigureAwait(false)).ToArray();
+            var returnList = (await _dtoService.GetBaseItemDtos(queryResult.Items, options, user)
+                .ConfigureAwait(false));
+            var returnArray = returnList.ToArray(returnList.Count);
 
 
             var result = new QueryResult<BaseItemDto>
             var result = new QueryResult<BaseItemDto>
             {
             {
@@ -1077,7 +1071,9 @@ namespace Emby.Server.Implementations.LiveTv
 
 
             var user = _userManager.GetUserById(query.UserId);
             var user = _userManager.GetUserById(query.UserId);
 
 
-            var returnArray = (await _dtoService.GetBaseItemDtos(internalResult.Items, options, user).ConfigureAwait(false)).ToArray();
+            var returnList = (await _dtoService.GetBaseItemDtos(internalResult.Items, options, user)
+                .ConfigureAwait(false));
+            var returnArray = returnList.ToArray(returnList.Count);
 
 
             var result = new QueryResult<BaseItemDto>
             var result = new QueryResult<BaseItemDto>
             {
             {
@@ -1639,7 +1635,7 @@ namespace Emby.Server.Implementations.LiveTv
             {
             {
                 MediaTypes = new[] { MediaType.Video },
                 MediaTypes = new[] { MediaType.Video },
                 Recursive = true,
                 Recursive = true,
-                AncestorIds = folderIds.Select(i => i.ToString("N")).ToArray(),
+                AncestorIds = folderIds.Select(i => i.ToString("N")).ToArray(folderIds.Count),
                 IsFolder = false,
                 IsFolder = false,
                 IsVirtualItem = false,
                 IsVirtualItem = false,
                 Limit = query.Limit,
                 Limit = query.Limit,
@@ -1647,9 +1643,9 @@ namespace Emby.Server.Implementations.LiveTv
                 SortBy = new[] { ItemSortBy.DateCreated },
                 SortBy = new[] { ItemSortBy.DateCreated },
                 SortOrder = SortOrder.Descending,
                 SortOrder = SortOrder.Descending,
                 EnableTotalRecordCount = query.EnableTotalRecordCount,
                 EnableTotalRecordCount = query.EnableTotalRecordCount,
-                IncludeItemTypes = includeItemTypes.ToArray(),
-                ExcludeItemTypes = excludeItemTypes.ToArray(),
-                Genres = genres.ToArray(),
+                IncludeItemTypes = includeItemTypes.ToArray(includeItemTypes.Count),
+                ExcludeItemTypes = excludeItemTypes.ToArray(excludeItemTypes.Count),
+                Genres = genres.ToArray(genres.Count),
                 DtoOptions = dtoOptions
                 DtoOptions = dtoOptions
             });
             });
         }
         }
@@ -1695,17 +1691,20 @@ namespace Emby.Server.Implementations.LiveTv
             var internalResult = _libraryManager.GetItemsResult(new InternalItemsQuery(user)
             var internalResult = _libraryManager.GetItemsResult(new InternalItemsQuery(user)
             {
             {
                 Recursive = true,
                 Recursive = true,
-                AncestorIds = folders.Select(i => i.Id.ToString("N")).ToArray(),
+                AncestorIds = folders.Select(i => i.Id.ToString("N")).ToArray(folders.Count),
                 Limit = query.Limit,
                 Limit = query.Limit,
                 SortBy = new[] { ItemSortBy.DateCreated },
                 SortBy = new[] { ItemSortBy.DateCreated },
                 SortOrder = SortOrder.Descending,
                 SortOrder = SortOrder.Descending,
                 EnableTotalRecordCount = query.EnableTotalRecordCount,
                 EnableTotalRecordCount = query.EnableTotalRecordCount,
-                IncludeItemTypes = includeItemTypes.ToArray(),
-                ExcludeItemTypes = excludeItemTypes.ToArray(),
+                IncludeItemTypes = includeItemTypes.ToArray(includeItemTypes.Count),
+                ExcludeItemTypes = excludeItemTypes.ToArray(excludeItemTypes.Count),
                 DtoOptions = options
                 DtoOptions = options
             });
             });
 
 
-            var returnArray = (await _dtoService.GetBaseItemDtos(internalResult.Items, options, user).ConfigureAwait(false)).ToArray();
+            var returnList = (await _dtoService.GetBaseItemDtos(internalResult.Items, options, user)
+                .ConfigureAwait(false));
+
+            var returnArray = returnList.ToArray(returnList.Count);
 
 
             return new QueryResult<BaseItemDto>
             return new QueryResult<BaseItemDto>
             {
             {
@@ -1996,7 +1995,9 @@ namespace Emby.Server.Implementations.LiveTv
 
 
             var internalResult = await GetInternalRecordings(query, options, cancellationToken).ConfigureAwait(false);
             var internalResult = await GetInternalRecordings(query, options, cancellationToken).ConfigureAwait(false);
 
 
-            var returnArray = (await _dtoService.GetBaseItemDtos(internalResult.Items, options, user).ConfigureAwait(false)).ToArray();
+            var returnList = (await _dtoService.GetBaseItemDtos(internalResult.Items, options, user)
+                .ConfigureAwait(false));
+            var returnArray = returnList.ToArray(returnList.Count);
 
 
             return new QueryResult<BaseItemDto>
             return new QueryResult<BaseItemDto>
             {
             {
@@ -2084,7 +2085,7 @@ namespace Emby.Server.Implementations.LiveTv
 
 
             var returnArray = returnList
             var returnArray = returnList
                 .OrderBy(i => i.StartDate)
                 .OrderBy(i => i.StartDate)
-                .ToArray();
+                .ToArray(returnList.Count);
 
 
             return new QueryResult<TimerInfoDto>
             return new QueryResult<TimerInfoDto>
             {
             {
@@ -2341,7 +2342,7 @@ namespace Emby.Server.Implementations.LiveTv
                 TopParentIds = new[] { GetInternalLiveTvFolder(CancellationToken.None).Result.Id.ToString("N") },
                 TopParentIds = new[] { GetInternalLiveTvFolder(CancellationToken.None).Result.Id.ToString("N") },
                 DtoOptions = options
                 DtoOptions = options
 
 
-            }).ToList() : new List<BaseItem>();
+            }) : new List<BaseItem>();
 
 
             RemoveFields(options);
             RemoveFields(options);
 
 
@@ -2705,7 +2706,7 @@ namespace Emby.Server.Implementations.LiveTv
 
 
             return new QueryResult<BaseItemDto>
             return new QueryResult<BaseItemDto>
             {
             {
-                Items = groups.ToArray(),
+                Items = groups.ToArray(groups.Count),
                 TotalRecordCount = groups.Count
                 TotalRecordCount = groups.Count
             };
             };
         }
         }
@@ -2992,7 +2993,7 @@ namespace Emby.Server.Implementations.LiveTv
                     Name = tunerChannelId,
                     Name = tunerChannelId,
                     Value = providerChannelId
                     Value = providerChannelId
                 });
                 });
-                listingsProviderInfo.ChannelMappings = list.ToArray();
+                listingsProviderInfo.ChannelMappings = list.ToArray(list.Count);
             }
             }
 
 
             _config.SaveConfiguration("livetv", config);
             _config.SaveConfiguration("livetv", config);

+ 2 - 1
Emby.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs

@@ -14,6 +14,7 @@ using System.Linq;
 using System.Threading;
 using System.Threading;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
 using MediaBrowser.Model.Dlna;
 using MediaBrowser.Model.Dlna;
+using MediaBrowser.Model.Extensions;
 
 
 namespace Emby.Server.Implementations.LiveTv
 namespace Emby.Server.Implementations.LiveTv
 {
 {
@@ -102,7 +103,7 @@ namespace Emby.Server.Implementations.LiveTv
                     openKeys.Add(item.GetType().Name);
                     openKeys.Add(item.GetType().Name);
                     openKeys.Add(item.Id.ToString("N"));
                     openKeys.Add(item.Id.ToString("N"));
                     openKeys.Add(source.Id ?? string.Empty);
                     openKeys.Add(source.Id ?? string.Empty);
-                    source.OpenToken = string.Join(StreamIdDelimeterString, openKeys.ToArray());
+                    source.OpenToken = string.Join(StreamIdDelimeterString, openKeys.ToArray(openKeys.Count));
                 }
                 }
 
 
                 // Dummy this up so that direct play checks can still run
                 // Dummy this up so that direct play checks can still run

+ 3 - 3
Emby.Server.Implementations/Localization/LocalizationManager.cs

@@ -132,7 +132,7 @@ namespace Emby.Server.Implementations.Localization
         /// Gets the cultures.
         /// Gets the cultures.
         /// </summary>
         /// </summary>
         /// <returns>IEnumerable{CultureDto}.</returns>
         /// <returns>IEnumerable{CultureDto}.</returns>
-        public IEnumerable<CultureDto> GetCultures()
+        public List<CultureDto> GetCultures()
         {
         {
             var type = GetType();
             var type = GetType();
             var path = type.Namespace + ".iso6392.txt";
             var path = type.Namespace + ".iso6392.txt";
@@ -169,14 +169,14 @@ namespace Emby.Server.Implementations.Localization
             return list.Where(i => !string.IsNullOrWhiteSpace(i.Name) &&
             return list.Where(i => !string.IsNullOrWhiteSpace(i.Name) &&
                 !string.IsNullOrWhiteSpace(i.DisplayName) &&
                 !string.IsNullOrWhiteSpace(i.DisplayName) &&
                 !string.IsNullOrWhiteSpace(i.ThreeLetterISOLanguageName) &&
                 !string.IsNullOrWhiteSpace(i.ThreeLetterISOLanguageName) &&
-                !string.IsNullOrWhiteSpace(i.TwoLetterISOLanguageName));
+                !string.IsNullOrWhiteSpace(i.TwoLetterISOLanguageName)).ToList();
         }
         }
 
 
         /// <summary>
         /// <summary>
         /// Gets the countries.
         /// Gets the countries.
         /// </summary>
         /// </summary>
         /// <returns>IEnumerable{CountryInfo}.</returns>
         /// <returns>IEnumerable{CountryInfo}.</returns>
-        public IEnumerable<CountryInfo> GetCountries()
+        public List<CountryInfo> GetCountries()
         {
         {
             var type = GetType();
             var type = GetType();
             var path = type.Namespace + ".countries.json";
             var path = type.Namespace + ".countries.json";

+ 1 - 2
Emby.Server.Core/Localization/TextLocalizer.cs → Emby.Server.Implementations/Localization/TextLocalizer.cs

@@ -3,9 +3,8 @@ using System.Globalization;
 using System.Linq;
 using System.Linq;
 using System.Text;
 using System.Text;
 using System.Text.RegularExpressions;
 using System.Text.RegularExpressions;
-using Emby.Server.Implementations.Localization;
 
 
-namespace Emby.Server.Core.Localization
+namespace Emby.Server.Implementations.Localization
 {
 {
     public class TextLocalizer : ITextLocalizer
     public class TextLocalizer : ITextLocalizer
     {
     {

+ 1 - 4
Emby.Server.Core/Logging/ConsoleLogger.cs → Emby.Server.Implementations/Logging/ConsoleLogger.cs

@@ -1,10 +1,7 @@
 using System;
 using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading.Tasks;
 using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.Logging;
 
 
-namespace Emby.Server.Core.Logging
+namespace Emby.Server.Implementations.Logging
 {
 {
     public class ConsoleLogger : IConsoleLogger
     public class ConsoleLogger : IConsoleLogger
     {
     {

+ 7 - 6
Emby.Server.Implementations/Notifications/SqliteNotificationsRepository.cs

@@ -12,6 +12,7 @@ using MediaBrowser.Model.IO;
 using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.Notifications;
 using MediaBrowser.Model.Notifications;
 using SQLitePCL.pretty;
 using SQLitePCL.pretty;
+using MediaBrowser.Model.Extensions;
 
 
 namespace Emby.Server.Implementations.Notifications
 namespace Emby.Server.Implementations.Notifications
 {
 {
@@ -83,13 +84,13 @@ namespace Emby.Server.Implementations.Notifications
             clauses.Add("UserId=?");
             clauses.Add("UserId=?");
             paramList.Add(query.UserId.ToGuidBlob());
             paramList.Add(query.UserId.ToGuidBlob());
 
 
-            var whereClause = " where " + string.Join(" And ", clauses.ToArray());
+            var whereClause = " where " + string.Join(" And ", clauses.ToArray(clauses.Count));
 
 
             using (WriteLock.Read())
             using (WriteLock.Read())
             {
             {
                 using (var connection = CreateConnection(true))
                 using (var connection = CreateConnection(true))
                 {
                 {
-                    result.TotalRecordCount = connection.Query("select count(Id) from Notifications" + whereClause, paramList.ToArray()).SelectScalarInt().First();
+                    result.TotalRecordCount = connection.Query("select count(Id) from Notifications" + whereClause, paramList.ToArray(paramList.Count)).SelectScalarInt().First();
 
 
                     var commandText = string.Format("select Id,UserId,Date,Name,Description,Url,Level,IsRead,Category,RelatedId from Notifications{0} order by IsRead asc, Date desc", whereClause);
                     var commandText = string.Format("select Id,UserId,Date,Name,Description,Url,Level,IsRead,Category,RelatedId from Notifications{0} order by IsRead asc, Date desc", whereClause);
 
 
@@ -110,12 +111,12 @@ namespace Emby.Server.Implementations.Notifications
 
 
                     var resultList = new List<Notification>();
                     var resultList = new List<Notification>();
 
 
-                    foreach (var row in connection.Query(commandText, paramList.ToArray()))
+                    foreach (var row in connection.Query(commandText, paramList.ToArray(paramList.Count)))
                     {
                     {
                         resultList.Add(GetNotification(row));
                         resultList.Add(GetNotification(row));
                     }
                     }
 
 
-                    result.Notifications = resultList.ToArray();
+                    result.Notifications = resultList.ToArray(resultList.Count);
                 }
                 }
             }
             }
 
 
@@ -280,7 +281,7 @@ namespace Emby.Server.Implementations.Notifications
         public async Task MarkRead(IEnumerable<string> notificationIdList, string userId, bool isRead, CancellationToken cancellationToken)
         public async Task MarkRead(IEnumerable<string> notificationIdList, string userId, bool isRead, CancellationToken cancellationToken)
         {
         {
             var list = notificationIdList.ToList();
             var list = notificationIdList.ToList();
-            var idArray = list.Select(i => new Guid(i)).ToArray();
+            var idArray = list.Select(i => new Guid(i)).ToArray(list.Count);
 
 
             await MarkReadInternal(idArray, userId, isRead, cancellationToken).ConfigureAwait(false);
             await MarkReadInternal(idArray, userId, isRead, cancellationToken).ConfigureAwait(false);
 
 
@@ -290,7 +291,7 @@ namespace Emby.Server.Implementations.Notifications
                 {
                 {
                     NotificationsMarkedRead(this, new NotificationReadEventArgs
                     NotificationsMarkedRead(this, new NotificationReadEventArgs
                     {
                     {
-                        IdList = list.ToArray(),
+                        IdList = list.ToArray(list.Count),
                         IsRead = isRead,
                         IsRead = isRead,
                         UserId = userId
                         UserId = userId
                     });
                     });

+ 2 - 1
Emby.Server.Implementations/Notifications/WebSocketNotifier.cs

@@ -2,6 +2,7 @@
 using MediaBrowser.Controller.Notifications;
 using MediaBrowser.Controller.Notifications;
 using MediaBrowser.Controller.Plugins;
 using MediaBrowser.Controller.Plugins;
 using System.Linq;
 using System.Linq;
+using MediaBrowser.Model.Extensions;
 
 
 namespace Emby.Server.Implementations.Notifications
 namespace Emby.Server.Implementations.Notifications
 {
 {
@@ -33,7 +34,7 @@ namespace Emby.Server.Implementations.Notifications
             list.Add(e.UserId);
             list.Add(e.UserId);
             list.Add(e.IsRead.ToString().ToLower());
             list.Add(e.IsRead.ToString().ToLower());
 
 
-            var msg = string.Join("|", list.ToArray());
+            var msg = string.Join("|", list.ToArray(list.Count));
 
 
             _serverManager.SendWebSocketMessage("NotificationsMarkedRead", msg);
             _serverManager.SendWebSocketMessage("NotificationsMarkedRead", msg);
         }
         }

+ 1 - 1
Emby.Server.Implementations/Photos/PhotoAlbumImageProvider.cs

@@ -21,7 +21,7 @@ namespace Emby.Server.Implementations.Photos
         protected override List<BaseItem> GetItemsWithImages(IHasMetadata item)
         protected override List<BaseItem> GetItemsWithImages(IHasMetadata item)
         {
         {
             var photoAlbum = (PhotoAlbum)item;
             var photoAlbum = (PhotoAlbum)item;
-            var items = GetFinalItems(photoAlbum.Children.ToList());
+            var items = GetFinalItems(photoAlbum.Children);
 
 
             return items;
             return items;
         }
         }

+ 3 - 4
Emby.Server.Implementations/Playlists/PlaylistImageProvider.cs

@@ -65,8 +65,7 @@ namespace Emby.Server.Implementations.Playlists
                     return null;
                     return null;
                 })
                 })
                 .Where(i => i != null)
                 .Where(i => i != null)
-                .DistinctBy(i => i.Id)
-                .ToList();
+                .DistinctBy(i => i.Id);
 
 
             return GetFinalItems(items);
             return GetFinalItems(items);
         }
         }
@@ -93,7 +92,7 @@ namespace Emby.Server.Implementations.Playlists
                 ImageTypes = new[] { ImageType.Primary },
                 ImageTypes = new[] { ImageType.Primary },
                 DtoOptions = new DtoOptions(false)
                 DtoOptions = new DtoOptions(false)
 
 
-            }).ToList();
+            });
 
 
             return GetFinalItems(items);
             return GetFinalItems(items);
         }
         }
@@ -125,7 +124,7 @@ namespace Emby.Server.Implementations.Playlists
                 ImageTypes = new[] { ImageType.Primary },
                 ImageTypes = new[] { ImageType.Primary },
                 DtoOptions = new DtoOptions(false)
                 DtoOptions = new DtoOptions(false)
 
 
-            }).ToList();
+            });
 
 
             return GetFinalItems(items);
             return GetFinalItems(items);
         }
         }

+ 2 - 1
Emby.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs

@@ -15,6 +15,7 @@ using MediaBrowser.Controller.IO;
 using MediaBrowser.Model.IO;
 using MediaBrowser.Model.IO;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Tasks;
 using MediaBrowser.Model.Tasks;
+using MediaBrowser.Model.Extensions;
 
 
 namespace Emby.Server.Implementations.ScheduledTasks
 namespace Emby.Server.Implementations.ScheduledTasks
 {
 {
@@ -142,7 +143,7 @@ namespace Emby.Server.Implementations.ScheduledTasks
 
 
                         _fileSystem.CreateDirectory(parentPath);
                         _fileSystem.CreateDirectory(parentPath);
 
 
-                        _fileSystem.WriteAllText(failHistoryPath, string.Join("|", previouslyFailedImages.ToArray()));
+                        _fileSystem.WriteAllText(failHistoryPath, string.Join("|", previouslyFailedImages.ToArray(previouslyFailedImages.Count)));
                     }
                     }
 
 
                     numComplete++;
                     numComplete++;

+ 5 - 4
Emby.Server.Implementations/Security/AuthenticationRepository.cs

@@ -11,6 +11,7 @@ using MediaBrowser.Controller.Security;
 using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.Querying;
 using MediaBrowser.Model.Querying;
 using SQLitePCL.pretty;
 using SQLitePCL.pretty;
+using MediaBrowser.Model.Extensions;
 
 
 namespace Emby.Server.Implementations.Security
 namespace Emby.Server.Implementations.Security
 {
 {
@@ -174,13 +175,13 @@ namespace Emby.Server.Implementations.Security
 
 
             var whereTextWithoutPaging = whereClauses.Count == 0 ?
             var whereTextWithoutPaging = whereClauses.Count == 0 ?
               string.Empty :
               string.Empty :
-              " where " + string.Join(" AND ", whereClauses.ToArray());
+              " where " + string.Join(" AND ", whereClauses.ToArray(whereClauses.Count));
 
 
             if (startIndex > 0)
             if (startIndex > 0)
             {
             {
                 var pagingWhereText = whereClauses.Count == 0 ?
                 var pagingWhereText = whereClauses.Count == 0 ?
                     string.Empty :
                     string.Empty :
-                    " where " + string.Join(" AND ", whereClauses.ToArray());
+                    " where " + string.Join(" AND ", whereClauses.ToArray(whereClauses.Count));
 
 
                 whereClauses.Add(string.Format("Id NOT IN (SELECT Id FROM AccessTokens {0} ORDER BY DateCreated LIMIT {1})",
                 whereClauses.Add(string.Format("Id NOT IN (SELECT Id FROM AccessTokens {0} ORDER BY DateCreated LIMIT {1})",
                     pagingWhereText,
                     pagingWhereText,
@@ -189,7 +190,7 @@ namespace Emby.Server.Implementations.Security
 
 
             var whereText = whereClauses.Count == 0 ?
             var whereText = whereClauses.Count == 0 ?
                 string.Empty :
                 string.Empty :
-                " where " + string.Join(" AND ", whereClauses.ToArray());
+                " where " + string.Join(" AND ", whereClauses.ToArray(whereClauses.Count));
 
 
             commandText += whereText;
             commandText += whereText;
 
 
@@ -236,7 +237,7 @@ namespace Emby.Server.Implementations.Security
                             }
                             }
                         }
                         }
 
 
-                        result.Items = list.ToArray();
+                        result.Items = list.ToArray(list.Count);
                         return result;
                         return result;
 
 
                     }, ReadTransactionMode);
                     }, ReadTransactionMode);

+ 3 - 5
Emby.Server.Implementations/Services/ServiceController.cs

@@ -15,17 +15,15 @@ namespace Emby.Server.Implementations.Services
     public class ServiceController
     public class ServiceController
     {
     {
         public static ServiceController Instance;
         public static ServiceController Instance;
-        private readonly Func<IEnumerable<Type>> _resolveServicesFn;
 
 
-        public ServiceController(Func<IEnumerable<Type>> resolveServicesFn)
+        public ServiceController()
         {
         {
             Instance = this;
             Instance = this;
-            _resolveServicesFn = resolveServicesFn;
         }
         }
 
 
-        public void Init(HttpListenerHost appHost)
+        public void Init(HttpListenerHost appHost, Type[] serviceTypes)
         {
         {
-            foreach (var serviceType in _resolveServicesFn())
+            foreach (var serviceType in serviceTypes)
             {
             {
                 RegisterService(appHost, serviceType);
                 RegisterService(appHost, serviceType);
             }
             }

+ 2 - 1
Emby.Server.Implementations/Services/ServiceExec.cs

@@ -5,6 +5,7 @@ using System.Linq.Expressions;
 using System.Reflection;
 using System.Reflection;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
 using MediaBrowser.Model.Services;
 using MediaBrowser.Model.Services;
+using MediaBrowser.Model.Extensions;
 
 
 namespace Emby.Server.Implementations.Services
 namespace Emby.Server.Implementations.Services
 {
 {
@@ -123,7 +124,7 @@ namespace Emby.Server.Implementations.Services
                 }
                 }
 
 
                 if (reqFilters.Count > 0)
                 if (reqFilters.Count > 0)
-                    actionCtx.RequestFilters = reqFilters.OrderBy(i => i.Priority).ToArray();
+                    actionCtx.RequestFilters = reqFilters.OrderBy(i => i.Priority).ToArray(reqFilters.Count);
 
 
                 actions.Add(actionCtx);
                 actions.Add(actionCtx);
             }
             }

+ 6 - 5
Emby.Server.Implementations/Services/ServicePath.cs

@@ -5,6 +5,7 @@ using System.Linq;
 using System.Reflection;
 using System.Reflection;
 using System.Text;
 using System.Text;
 using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.Logging;
+using MediaBrowser.Model.Extensions;
 
 
 namespace Emby.Server.Implementations.Services
 namespace Emby.Server.Implementations.Services
 {
 {
@@ -142,13 +143,13 @@ namespace Emby.Server.Implementations.Services
                 }
                 }
             }
             }
 
 
-            var components = componentsList.ToArray();
+            var components = componentsList.ToArray(componentsList.Count);
             this.TotalComponentsCount = components.Length;
             this.TotalComponentsCount = components.Length;
 
 
             this.literalsToMatch = new string[this.TotalComponentsCount];
             this.literalsToMatch = new string[this.TotalComponentsCount];
             this.variablesNames = new string[this.TotalComponentsCount];
             this.variablesNames = new string[this.TotalComponentsCount];
             this.isWildcard = new bool[this.TotalComponentsCount];
             this.isWildcard = new bool[this.TotalComponentsCount];
-            this.componentsWithSeparators = hasSeparators.ToArray();
+            this.componentsWithSeparators = hasSeparators.ToArray(hasSeparators.Count);
             this.PathComponentsCount = this.componentsWithSeparators.Length;
             this.PathComponentsCount = this.componentsWithSeparators.Length;
             string firstLiteralMatch = null;
             string firstLiteralMatch = null;
 
 
@@ -268,7 +269,7 @@ namespace Emby.Server.Implementations.Services
                     propertyInfos.InsertRange(0, newPropertyInfos);
                     propertyInfos.InsertRange(0, newPropertyInfos);
                 }
                 }
 
 
-                return propertyInfos.ToArray();
+                return propertyInfos.ToArray(propertyInfos.Count);
             }
             }
 
 
             return GetTypesPublicProperties(type)
             return GetTypesPublicProperties(type)
@@ -285,7 +286,7 @@ namespace Emby.Server.Implementations.Services
                 if (mi != null && mi.IsStatic) continue;
                 if (mi != null && mi.IsStatic) continue;
                 pis.Add(pi);
                 pis.Add(pi);
             }
             }
-            return pis.ToArray();
+            return pis.ToArray(pis.Count);
         }
         }
 
 
 
 
@@ -450,7 +451,7 @@ namespace Emby.Server.Implementations.Services
                 }
                 }
             }
             }
 
 
-            withPathInfoParts = totalComponents.ToArray();
+            withPathInfoParts = totalComponents.ToArray(totalComponents.Count);
             return true;
             return true;
         }
         }
 
 

+ 3 - 2
Emby.Server.Implementations/Session/SessionManager.cs

@@ -32,6 +32,7 @@ using System.Threading.Tasks;
 using MediaBrowser.Controller.Net;
 using MediaBrowser.Controller.Net;
 using MediaBrowser.Model.Querying;
 using MediaBrowser.Model.Querying;
 using MediaBrowser.Model.Threading;
 using MediaBrowser.Model.Threading;
+using MediaBrowser.Model.Extensions;
 
 
 namespace Emby.Server.Implementations.Session
 namespace Emby.Server.Implementations.Session
 {
 {
@@ -1000,7 +1001,7 @@ namespace Emby.Server.Implementations.Session
                 command.PlayCommand = PlayCommand.PlayNow;
                 command.PlayCommand = PlayCommand.PlayNow;
             }
             }
 
 
-            command.ItemIds = items.Select(i => i.Id.ToString("N")).ToArray();
+            command.ItemIds = items.Select(i => i.Id.ToString("N")).ToArray(items.Count);
 
 
             if (user != null)
             if (user != null)
             {
             {
@@ -1033,7 +1034,7 @@ namespace Emby.Server.Implementations.Session
 
 
                         if (episodes.Count > 0)
                         if (episodes.Count > 0)
                         {
                         {
-                            command.ItemIds = episodes.Select(i => i.Id.ToString("N")).ToArray();
+                            command.ItemIds = episodes.Select(i => i.Id.ToString("N")).ToArray(episodes.Count);
                         }
                         }
                     }
                     }
                 }
                 }

+ 2 - 1
Emby.Server.Implementations/Social/SharingRepository.cs

@@ -8,6 +8,7 @@ using MediaBrowser.Common.Configuration;
 using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.Social;
 using MediaBrowser.Model.Social;
 using SQLitePCL.pretty;
 using SQLitePCL.pretty;
+using MediaBrowser.Model.Extensions;
 
 
 namespace Emby.Server.Implementations.Social
 namespace Emby.Server.Implementations.Social
 {
 {
@@ -86,7 +87,7 @@ namespace Emby.Server.Implementations.Social
                     var paramList = new List<object>();
                     var paramList = new List<object>();
                     paramList.Add(id.ToGuidBlob());
                     paramList.Add(id.ToGuidBlob());
 
 
-                    foreach (var row in connection.Query(commandText, paramList.ToArray()))
+                    foreach (var row in connection.Query(commandText, paramList.ToArray(paramList.Count)))
                     {
                     {
                         return GetSocialShareInfo(row);
                         return GetSocialShareInfo(row);
                     }
                     }

+ 1 - 1
Emby.Server.Core/SystemEvents.cs → Emby.Server.Implementations/SystemEvents.cs

@@ -3,7 +3,7 @@ using MediaBrowser.Common.Events;
 using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.System;
 using MediaBrowser.Model.System;
 
 
-namespace MediaBrowser.Server.Startup.Common
+namespace Emby.Server.Implementations
 {
 {
     public class SystemEvents : ISystemEvents
     public class SystemEvents : ISystemEvents
     {
     {

+ 2 - 2
Emby.Server.Implementations/UserViews/CollectionFolderImageProvider.cs

@@ -91,7 +91,7 @@ namespace Emby.Server.Implementations.UserViews
 
 
             }).DistinctBy(i => i.Id);
             }).DistinctBy(i => i.Id);
 
 
-            return GetFinalItems(items.Where(i => i.HasImage(ImageType.Primary) || i.HasImage(ImageType.Thumb)).ToList(), 8);
+            return GetFinalItems(items.Where(i => i.HasImage(ImageType.Primary) || i.HasImage(ImageType.Thumb)), 8);
         }
         }
 
 
         protected override bool Supports(IHasMetadata item)
         protected override bool Supports(IHasMetadata item)
@@ -149,7 +149,7 @@ namespace Emby.Server.Implementations.UserViews
                 DtoOptions = new DtoOptions(false)
                 DtoOptions = new DtoOptions(false)
             });
             });
 
 
-            return GetFinalItems(items.Where(i => i.HasImage(ImageType.Primary) || i.HasImage(ImageType.Thumb)).ToList(), 8);
+            return GetFinalItems(items.Where(i => i.HasImage(ImageType.Primary) || i.HasImage(ImageType.Thumb)), 8);
         }
         }
 
 
         protected override bool Supports(IHasMetadata item)
         protected override bool Supports(IHasMetadata item)

+ 4 - 4
Emby.Server.Implementations/UserViews/DynamicImageProvider.cs

@@ -62,9 +62,9 @@ namespace Emby.Server.Implementations.UserViews
                     IsMovie = true,
                     IsMovie = true,
                     DtoOptions = new DtoOptions(false)
                     DtoOptions = new DtoOptions(false)
 
 
-                }).ToList();
+                });
 
 
-                return GetFinalItems(programs).ToList();
+                return GetFinalItems(programs);
             }
             }
 
 
             if (string.Equals(view.ViewType, SpecialFolder.MovieGenre, StringComparison.OrdinalIgnoreCase) ||
             if (string.Equals(view.ViewType, SpecialFolder.MovieGenre, StringComparison.OrdinalIgnoreCase) ||
@@ -133,10 +133,10 @@ namespace Emby.Server.Implementations.UserViews
 
 
             if (isUsingCollectionStrip)
             if (isUsingCollectionStrip)
             {
             {
-                return GetFinalItems(items.Where(i => i.HasImage(ImageType.Primary) || i.HasImage(ImageType.Thumb)).ToList(), 8);
+                return GetFinalItems(items.Where(i => i.HasImage(ImageType.Primary) || i.HasImage(ImageType.Thumb)), 8);
             }
             }
 
 
-            return GetFinalItems(items.Where(i => i.HasImage(ImageType.Primary)).ToList());
+            return GetFinalItems(items.Where(i => i.HasImage(ImageType.Primary)));
         }
         }
 
 
         protected override bool Supports(IHasMetadata item)
         protected override bool Supports(IHasMetadata item)

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

@@ -2,6 +2,9 @@
 <packages>
 <packages>
   <package id="Emby.XmlTv" version="1.0.9" targetFramework="net46" />
   <package id="Emby.XmlTv" version="1.0.9" targetFramework="net46" />
   <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="Microsoft.IO.RecyclableMemoryStream" version="1.2.2" targetFramework="net46" />
+  <package id="ServiceStack.Text" version="4.5.12" targetFramework="net46" />
+  <package id="SimpleInjector" version="4.0.8" targetFramework="net46" />
   <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.7" targetFramework="net46" />
+  <package id="SQLitePCLRaw.core" version="1.1.8" targetFramework="net46" />
 </packages>
 </packages>

+ 11 - 735
MediaBrowser.Api/ApiEntryPoint.cs

@@ -1,27 +1,15 @@
-using MediaBrowser.Api.Playback;
-using MediaBrowser.Common.Configuration;
+using System;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Library;
+using MediaBrowser.Controller.Net;
 using MediaBrowser.Controller.Plugins;
 using MediaBrowser.Controller.Plugins;
 using MediaBrowser.Controller.Session;
 using MediaBrowser.Controller.Session;
-using MediaBrowser.Model.Configuration;
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Model.Session;
-using System;
-using System.Collections.Concurrent;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.IO;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-
-using MediaBrowser.Controller.MediaEncoding;
-using MediaBrowser.Controller.Net;
 using MediaBrowser.Model.Diagnostics;
 using MediaBrowser.Model.Diagnostics;
 using MediaBrowser.Model.IO;
 using MediaBrowser.Model.IO;
-using MediaBrowser.Model.Dto;
+using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.Threading;
 using MediaBrowser.Model.Threading;
+using System.Collections.Generic;
+using System.Threading;
 
 
 namespace MediaBrowser.Api
 namespace MediaBrowser.Api
 {
 {
@@ -53,11 +41,6 @@ namespace MediaBrowser.Api
         public readonly ITimerFactory TimerFactory;
         public readonly ITimerFactory TimerFactory;
         public readonly IProcessFactory ProcessFactory;
         public readonly IProcessFactory ProcessFactory;
 
 
-        /// <summary>
-        /// The active transcoding jobs
-        /// </summary>
-        private readonly List<TranscodingJob> _activeTranscodingJobs = new List<TranscodingJob>();
-
         private readonly Dictionary<string, SemaphoreSlim> _transcodingLocks =
         private readonly Dictionary<string, SemaphoreSlim> _transcodingLocks =
             new Dictionary<string, SemaphoreSlim>();
             new Dictionary<string, SemaphoreSlim>();
 
 
@@ -81,39 +64,21 @@ namespace MediaBrowser.Api
             ResultFactory = resultFactory;
             ResultFactory = resultFactory;
 
 
             Instance = this;
             Instance = this;
-            _sessionManager.PlaybackProgress += _sessionManager_PlaybackProgress;
-            _sessionManager.PlaybackStart += _sessionManager_PlaybackStart;
         }
         }
 
 
-        public SemaphoreSlim GetTranscodingLock(string outputPath)
+        public static string[] Split(string value, char separator, bool removeEmpty)
         {
         {
-            lock (_transcodingLocks)
+            if (string.IsNullOrWhiteSpace(value))
             {
             {
-                SemaphoreSlim result;
-                if (!_transcodingLocks.TryGetValue(outputPath, out result))
-                {
-                    result = new SemaphoreSlim(1, 1);
-                    _transcodingLocks[outputPath] = result;
-                }
-
-                return result;
+                return new string[] { };
             }
             }
-        }
 
 
-        private void _sessionManager_PlaybackStart(object sender, PlaybackProgressEventArgs e)
-        {
-            if (!string.IsNullOrWhiteSpace(e.PlaySessionId))
+            if (removeEmpty)
             {
             {
-                PingTranscodingJob(e.PlaySessionId, e.IsPaused);
+                return value.Split(new[] { separator }, StringSplitOptions.RemoveEmptyEntries);
             }
             }
-        }
 
 
-        void _sessionManager_PlaybackProgress(object sender, PlaybackProgressEventArgs e)
-        {
-            if (!string.IsNullOrWhiteSpace(e.PlaySessionId))
-            {
-                PingTranscodingJob(e.PlaySessionId, e.IsPaused);
-            }
+            return value.Split(separator);
         }
         }
 
 
         /// <summary>
         /// <summary>
@@ -121,41 +86,6 @@ namespace MediaBrowser.Api
         /// </summary>
         /// </summary>
         public void Run()
         public void Run()
         {
         {
-            try
-            {
-                DeleteEncodedMediaCache();
-            }
-            catch (FileNotFoundException)
-            {
-                // Don't clutter the log
-            }
-            catch (IOException)
-            {
-                // Don't clutter the log
-            }
-            catch (Exception ex)
-            {
-                Logger.ErrorException("Error deleting encoded media cache", ex);
-            }
-        }
-
-        public EncodingOptions GetEncodingOptions()
-        {
-            return _config.GetConfiguration<EncodingOptions>("encoding");
-        }
-
-        /// <summary>
-        /// Deletes the encoded media cache.
-        /// </summary>
-        private void DeleteEncodedMediaCache()
-        {
-            var path = _config.ApplicationPaths.TranscodingTempPath;
-
-            foreach (var file in _fileSystem.GetFilePaths(path, true)
-                .ToList())
-            {
-                _fileSystem.DeleteFile(file);
-            }
         }
         }
 
 
         /// <summary>
         /// <summary>
@@ -163,660 +93,6 @@ namespace MediaBrowser.Api
         /// </summary>
         /// </summary>
         public void Dispose()
         public void Dispose()
         {
         {
-            Dispose(true);
-            GC.SuppressFinalize(this);
-        }
-
-        /// <summary>
-        /// Releases unmanaged and - optionally - managed resources.
-        /// </summary>
-        /// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
-        protected virtual void Dispose(bool dispose)
-        {
-            var list = _activeTranscodingJobs.ToList();
-            var jobCount = list.Count;
-
-            Parallel.ForEach(list, j => KillTranscodingJob(j, false, path => true));
-
-            // Try to allow for some time to kill the ffmpeg processes and delete the partial stream files
-            if (jobCount > 0)
-            {
-                var task = Task.Delay(1000);
-                Task.WaitAll(task);
-            }
-        }
-
-        /// <summary>
-        /// Called when [transcode beginning].
-        /// </summary>
-        /// <param name="path">The path.</param>
-        /// <param name="playSessionId">The play session identifier.</param>
-        /// <param name="liveStreamId">The live stream identifier.</param>
-        /// <param name="transcodingJobId">The transcoding job identifier.</param>
-        /// <param name="type">The type.</param>
-        /// <param name="process">The process.</param>
-        /// <param name="deviceId">The device id.</param>
-        /// <param name="state">The state.</param>
-        /// <param name="cancellationTokenSource">The cancellation token source.</param>
-        /// <returns>TranscodingJob.</returns>
-        public TranscodingJob OnTranscodeBeginning(string path,
-            string playSessionId,
-            string liveStreamId,
-            string transcodingJobId,
-            TranscodingJobType type,
-            IProcess process,
-            string deviceId,
-            StreamState state,
-            CancellationTokenSource cancellationTokenSource)
-        {
-            lock (_activeTranscodingJobs)
-            {
-                var job = new TranscodingJob(Logger, TimerFactory)
-                {
-                    Type = type,
-                    Path = path,
-                    Process = process,
-                    ActiveRequestCount = 1,
-                    DeviceId = deviceId,
-                    CancellationTokenSource = cancellationTokenSource,
-                    Id = transcodingJobId,
-                    PlaySessionId = playSessionId,
-                    LiveStreamId = liveStreamId,
-                    MediaSource = state.MediaSource
-                };
-
-                _activeTranscodingJobs.Add(job);
-
-                ReportTranscodingProgress(job, state, null, null, null, null, null);
-
-                return job;
-            }
-        }
-
-        public void ReportTranscodingProgress(TranscodingJob job, StreamState state, TimeSpan? transcodingPosition, float? framerate, double? percentComplete, long? bytesTranscoded, int? bitRate)
-        {
-            var ticks = transcodingPosition.HasValue ? transcodingPosition.Value.Ticks : (long?)null;
-
-            if (job != null)
-            {
-                job.Framerate = framerate;
-                job.CompletionPercentage = percentComplete;
-                job.TranscodingPositionTicks = ticks;
-                job.BytesTranscoded = bytesTranscoded;
-                job.BitRate = bitRate;
-            }
-
-            var deviceId = state.Request.DeviceId;
-
-            if (!string.IsNullOrWhiteSpace(deviceId))
-            {
-                var audioCodec = state.ActualOutputAudioCodec;
-                var videoCodec = state.ActualOutputVideoCodec;
-
-                _sessionManager.ReportTranscodingInfo(deviceId, new TranscodingInfo
-                {
-                    Bitrate = bitRate ?? state.TotalOutputBitrate,
-                    AudioCodec = audioCodec,
-                    VideoCodec = videoCodec,
-                    Container = state.OutputContainer,
-                    Framerate = framerate,
-                    CompletionPercentage = percentComplete,
-                    Width = state.OutputWidth,
-                    Height = state.OutputHeight,
-                    AudioChannels = state.OutputAudioChannels,
-                    IsAudioDirect = string.Equals(state.OutputAudioCodec, "copy", StringComparison.OrdinalIgnoreCase),
-                    IsVideoDirect = string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase),
-                    TranscodeReasons = state.TranscodeReasons
-                });
-            }
-        }
-
-        /// <summary>
-        /// <summary>
-        /// The progressive
-        /// </summary>
-        /// Called when [transcode failed to start].
-        /// </summary>
-        /// <param name="path">The path.</param>
-        /// <param name="type">The type.</param>
-        /// <param name="state">The state.</param>
-        public void OnTranscodeFailedToStart(string path, TranscodingJobType type, StreamState state)
-        {
-            lock (_activeTranscodingJobs)
-            {
-                var job = _activeTranscodingJobs.FirstOrDefault(j => j.Type == type && string.Equals(j.Path, path, StringComparison.OrdinalIgnoreCase));
-
-                if (job != null)
-                {
-                    _activeTranscodingJobs.Remove(job);
-                }
-            }
-
-            lock (_transcodingLocks)
-            {
-                _transcodingLocks.Remove(path);
-            }
-
-            if (!string.IsNullOrWhiteSpace(state.Request.DeviceId))
-            {
-                _sessionManager.ClearTranscodingInfo(state.Request.DeviceId);
-            }
-        }
-
-        /// <summary>
-        /// Determines whether [has active transcoding job] [the specified path].
-        /// </summary>
-        /// <param name="path">The path.</param>
-        /// <param name="type">The type.</param>
-        /// <returns><c>true</c> if [has active transcoding job] [the specified path]; otherwise, <c>false</c>.</returns>
-        public bool HasActiveTranscodingJob(string path, TranscodingJobType type)
-        {
-            return GetTranscodingJob(path, type) != null;
-        }
-
-        public TranscodingJob GetTranscodingJob(string path, TranscodingJobType type)
-        {
-            lock (_activeTranscodingJobs)
-            {
-                return _activeTranscodingJobs.FirstOrDefault(j => j.Type == type && string.Equals(j.Path, path, StringComparison.OrdinalIgnoreCase));
-            }
-        }
-
-        public TranscodingJob GetTranscodingJob(string playSessionId)
-        {
-            lock (_activeTranscodingJobs)
-            {
-                return _activeTranscodingJobs.FirstOrDefault(j => string.Equals(j.PlaySessionId, playSessionId, StringComparison.OrdinalIgnoreCase));
-            }
-        }
-
-        /// <summary>
-        /// Called when [transcode begin request].
-        /// </summary>
-        /// <param name="path">The path.</param>
-        /// <param name="type">The type.</param>
-        public TranscodingJob OnTranscodeBeginRequest(string path, TranscodingJobType type)
-        {
-            lock (_activeTranscodingJobs)
-            {
-                var job = _activeTranscodingJobs.FirstOrDefault(j => j.Type == type && string.Equals(j.Path, path, StringComparison.OrdinalIgnoreCase));
-
-                if (job == null)
-                {
-                    return null;
-                }
-
-                OnTranscodeBeginRequest(job);
-
-                return job;
-            }
-        }
-
-        public void OnTranscodeBeginRequest(TranscodingJob job)
-        {
-            job.ActiveRequestCount++;
-
-            if (string.IsNullOrWhiteSpace(job.PlaySessionId) || job.Type == TranscodingJobType.Progressive)
-            {
-                job.StopKillTimer();
-            }
-        }
-
-        public void OnTranscodeEndRequest(TranscodingJob job)
-        {
-            job.ActiveRequestCount--;
-            //Logger.Debug("OnTranscodeEndRequest job.ActiveRequestCount={0}", job.ActiveRequestCount);
-            if (job.ActiveRequestCount <= 0)
-            {
-                PingTimer(job, false);
-            }
-        }
-        internal void PingTranscodingJob(string playSessionId, bool? isUserPaused)
-        {
-            if (string.IsNullOrEmpty(playSessionId))
-            {
-                throw new ArgumentNullException("playSessionId");
-            }
-
-            //Logger.Debug("PingTranscodingJob PlaySessionId={0} isUsedPaused: {1}", playSessionId, isUserPaused);
-
-            List<TranscodingJob> jobs;
-
-            lock (_activeTranscodingJobs)
-            {
-                // This is really only needed for HLS. 
-                // Progressive streams can stop on their own reliably
-                jobs = _activeTranscodingJobs.Where(j => string.Equals(playSessionId, j.PlaySessionId, StringComparison.OrdinalIgnoreCase)).ToList();
-            }
-
-            foreach (var job in jobs)
-            {
-                if (isUserPaused.HasValue)
-                {
-                    //Logger.Debug("Setting job.IsUserPaused to {0}. jobId: {1}", isUserPaused, job.Id);
-                    job.IsUserPaused = isUserPaused.Value;
-                }
-                PingTimer(job, true);
-            }
-        }
-
-        private void PingTimer(TranscodingJob job, bool isProgressCheckIn)
-        {
-            if (job.HasExited)
-            {
-                job.StopKillTimer();
-                return;
-            }
-
-            var timerDuration = 10000;
-
-            if (job.Type != TranscodingJobType.Progressive)
-            {
-                timerDuration = 60000;
-            }
-
-            job.PingTimeout = timerDuration;
-            job.LastPingDate = DateTime.UtcNow;
-
-            // Don't start the timer for playback checkins with progressive streaming
-            if (job.Type != TranscodingJobType.Progressive || !isProgressCheckIn)
-            {
-                job.StartKillTimer(OnTranscodeKillTimerStopped);
-            }
-            else
-            {
-                job.ChangeKillTimerIfStarted();
-            }
-        }
-
-        /// <summary>
-        /// Called when [transcode kill timer stopped].
-        /// </summary>
-        /// <param name="state">The state.</param>
-        private void OnTranscodeKillTimerStopped(object state)
-        {
-            var job = (TranscodingJob)state;
-
-            if (!job.HasExited && job.Type != TranscodingJobType.Progressive)
-            {
-                var timeSinceLastPing = (DateTime.UtcNow - job.LastPingDate).TotalMilliseconds;
-
-                if (timeSinceLastPing < job.PingTimeout)
-                {
-                    job.StartKillTimer(OnTranscodeKillTimerStopped, job.PingTimeout);
-                    return;
-                }
-            }
-
-            Logger.Info("Transcoding kill timer stopped for JobId {0} PlaySessionId {1}. Killing transcoding", job.Id, job.PlaySessionId);
-
-            KillTranscodingJob(job, true, path => true);
-        }
-
-        /// <summary>
-        /// Kills the single transcoding job.
-        /// </summary>
-        /// <param name="deviceId">The device id.</param>
-        /// <param name="playSessionId">The play session identifier.</param>
-        /// <param name="deleteFiles">The delete files.</param>
-        /// <returns>Task.</returns>
-        internal void KillTranscodingJobs(string deviceId, string playSessionId, Func<string, bool> deleteFiles)
-        {
-            KillTranscodingJobs(j =>
-            {
-                if (!string.IsNullOrWhiteSpace(playSessionId))
-                {
-                    return string.Equals(playSessionId, j.PlaySessionId, StringComparison.OrdinalIgnoreCase);
-                }
-
-                return string.Equals(deviceId, j.DeviceId, StringComparison.OrdinalIgnoreCase);
-
-            }, deleteFiles);
-        }
-
-        /// <summary>
-        /// Kills the transcoding jobs.
-        /// </summary>
-        /// <param name="killJob">The kill job.</param>
-        /// <param name="deleteFiles">The delete files.</param>
-        /// <returns>Task.</returns>
-        private void KillTranscodingJobs(Func<TranscodingJob, bool> killJob, Func<string, bool> deleteFiles)
-        {
-            var jobs = new List<TranscodingJob>();
-
-            lock (_activeTranscodingJobs)
-            {
-                // This is really only needed for HLS. 
-                // Progressive streams can stop on their own reliably
-                jobs.AddRange(_activeTranscodingJobs.Where(killJob));
-            }
-
-            if (jobs.Count == 0)
-            {
-                return;
-            }
-
-            foreach (var job in jobs)
-            {
-                KillTranscodingJob(job, false, deleteFiles);
-            }
-        }
-
-        /// <summary>
-        /// Kills the transcoding job.
-        /// </summary>
-        /// <param name="job">The job.</param>
-        /// <param name="closeLiveStream">if set to <c>true</c> [close live stream].</param>
-        /// <param name="delete">The delete.</param>
-        private async void KillTranscodingJob(TranscodingJob job, bool closeLiveStream, Func<string, bool> delete)
-        {
-            job.DisposeKillTimer();
-
-            Logger.Debug("KillTranscodingJob - JobId {0} PlaySessionId {1}. Killing transcoding", job.Id, job.PlaySessionId);
-
-            lock (_activeTranscodingJobs)
-            {
-                _activeTranscodingJobs.Remove(job);
-
-                if (!job.CancellationTokenSource.IsCancellationRequested)
-                {
-                    job.CancellationTokenSource.Cancel();
-                }
-            }
-
-            lock (_transcodingLocks)
-            {
-                _transcodingLocks.Remove(job.Path);
-            }
-
-            lock (job.ProcessLock)
-            {
-                if (job.TranscodingThrottler != null)
-                {
-                    job.TranscodingThrottler.Stop();
-                }
-
-                var process = job.Process;
-
-                var hasExited = job.HasExited;
-
-                if (!hasExited)
-                {
-                    try
-                    {
-                        Logger.Info("Stopping ffmpeg process with q command for {0}", job.Path);
-
-                        //process.Kill();
-                        process.StandardInput.WriteLine("q");
-
-                        // Need to wait because killing is asynchronous
-                        if (!process.WaitForExit(5000))
-                        {
-                            Logger.Info("Killing ffmpeg process for {0}", job.Path);
-                            process.Kill();
-                        }
-                    }
-                    catch (Exception ex)
-                    {
-                        Logger.ErrorException("Error killing transcoding job for {0}", ex, job.Path);
-                    }
-                }
-            }
-
-            if (delete(job.Path))
-            {
-                DeletePartialStreamFiles(job.Path, job.Type, 0, 1500);
-            }
-
-            if (closeLiveStream && !string.IsNullOrWhiteSpace(job.LiveStreamId))
-            {
-                try
-                {
-                    await _mediaSourceManager.CloseLiveStream(job.LiveStreamId).ConfigureAwait(false);
-                }
-                catch (Exception ex)
-                {
-                    Logger.ErrorException("Error closing live stream for {0}", ex, job.Path);
-                }
-            }
-        }
-
-        private async void DeletePartialStreamFiles(string path, TranscodingJobType jobType, int retryCount, int delayMs)
-        {
-            if (retryCount >= 10)
-            {
-                return;
-            }
-
-            Logger.Info("Deleting partial stream file(s) {0}", path);
-
-            await Task.Delay(delayMs).ConfigureAwait(false);
-
-            try
-            {
-                if (jobType == TranscodingJobType.Progressive)
-                {
-                    DeleteProgressivePartialStreamFiles(path);
-                }
-                else
-                {
-                    DeleteHlsPartialStreamFiles(path);
-                }
-            }
-            catch (FileNotFoundException)
-            {
-
-            }
-            catch (IOException)
-            {
-                //Logger.ErrorException("Error deleting partial stream file(s) {0}", ex, path);
-
-                DeletePartialStreamFiles(path, jobType, retryCount + 1, 500);
-            }
-            catch
-            {
-                //Logger.ErrorException("Error deleting partial stream file(s) {0}", ex, path);
-            }
-        }
-
-        /// <summary>
-        /// Deletes the progressive partial stream files.
-        /// </summary>
-        /// <param name="outputFilePath">The output file path.</param>
-        private void DeleteProgressivePartialStreamFiles(string outputFilePath)
-        {
-            _fileSystem.DeleteFile(outputFilePath);
-        }
-
-        /// <summary>
-        /// Deletes the HLS partial stream files.
-        /// </summary>
-        /// <param name="outputFilePath">The output file path.</param>
-        private void DeleteHlsPartialStreamFiles(string outputFilePath)
-        {
-            var directory = _fileSystem.GetDirectoryName(outputFilePath);
-            var name = Path.GetFileNameWithoutExtension(outputFilePath);
-
-            var filesToDelete = _fileSystem.GetFilePaths(directory)
-                .Where(f => f.IndexOf(name, StringComparison.OrdinalIgnoreCase) != -1)
-                .ToList();
-
-            Exception e = null;
-
-            foreach (var file in filesToDelete)
-            {
-                try
-                {
-                    //Logger.Debug("Deleting HLS file {0}", file);
-                    _fileSystem.DeleteFile(file);
-                }
-                catch (FileNotFoundException)
-                {
-
-                }
-                catch (IOException ex)
-                {
-                    e = ex;
-                    //Logger.ErrorException("Error deleting HLS file {0}", ex, file);
-                }
-            }
-
-            if (e != null)
-            {
-                throw e;
-            }
-        }
-    }
-
-    /// <summary>
-    /// Class TranscodingJob
-    /// </summary>
-    public class TranscodingJob
-    {
-        /// <summary>
-        /// Gets or sets the play session identifier.
-        /// </summary>
-        /// <value>The play session identifier.</value>
-        public string PlaySessionId { get; set; }
-        /// <summary>
-        /// Gets or sets the live stream identifier.
-        /// </summary>
-        /// <value>The live stream identifier.</value>
-        public string LiveStreamId { get; set; }
-
-        public bool IsLiveOutput { get; set; }
-
-        /// <summary>
-        /// Gets or sets the path.
-        /// </summary>
-        /// <value>The path.</value>
-        public MediaSourceInfo MediaSource { get; set; }
-        public string Path { get; set; }
-        /// <summary>
-        /// Gets or sets the type.
-        /// </summary>
-        /// <value>The type.</value>
-        public TranscodingJobType Type { get; set; }
-        /// <summary>
-        /// Gets or sets the process.
-        /// </summary>
-        /// <value>The process.</value>
-        public IProcess Process { get; set; }
-        public ILogger Logger { get; private set; }
-        /// <summary>
-        /// Gets or sets the active request count.
-        /// </summary>
-        /// <value>The active request count.</value>
-        public int ActiveRequestCount { get; set; }
-        /// <summary>
-        /// Gets or sets the kill timer.
-        /// </summary>
-        /// <value>The kill timer.</value>
-        private ITimer KillTimer { get; set; }
-
-        private readonly ITimerFactory _timerFactory;
-
-        public string DeviceId { get; set; }
-
-        public CancellationTokenSource CancellationTokenSource { get; set; }
-
-        public object ProcessLock = new object();
-
-        public bool HasExited { get; set; }
-        public bool IsUserPaused { get; set; }
-
-        public string Id { get; set; }
-
-        public float? Framerate { get; set; }
-        public double? CompletionPercentage { get; set; }
-
-        public long? BytesDownloaded { get; set; }
-        public long? BytesTranscoded { get; set; }
-        public int? BitRate { get; set; }
-
-        public long? TranscodingPositionTicks { get; set; }
-        public long? DownloadPositionTicks { get; set; }
-
-        public TranscodingThrottler TranscodingThrottler { get; set; }
-
-        private readonly object _timerLock = new object();
-
-        public DateTime LastPingDate { get; set; }
-        public int PingTimeout { get; set; }
-
-        public TranscodingJob(ILogger logger, ITimerFactory timerFactory)
-        {
-            Logger = logger;
-            _timerFactory = timerFactory;
-        }
-
-        public void StopKillTimer()
-        {
-            lock (_timerLock)
-            {
-                if (KillTimer != null)
-                {
-                    KillTimer.Change(Timeout.Infinite, Timeout.Infinite);
-                }
-            }
-        }
-
-        public void DisposeKillTimer()
-        {
-            lock (_timerLock)
-            {
-                if (KillTimer != null)
-                {
-                    KillTimer.Dispose();
-                    KillTimer = null;
-                }
-            }
-        }
-
-        public void StartKillTimer(Action<object> callback)
-        {
-            StartKillTimer(callback, PingTimeout);
-        }
-
-        public void StartKillTimer(Action<object> callback, int intervalMs)
-        {
-            if (HasExited)
-            {
-                return;
-            }
-
-            lock (_timerLock)
-            {
-                if (KillTimer == null)
-                {
-                    //Logger.Debug("Starting kill timer at {0}ms. JobId {1} PlaySessionId {2}", intervalMs, Id, PlaySessionId);
-                    KillTimer = _timerFactory.Create(callback, this, intervalMs, Timeout.Infinite);
-                }
-                else
-                {
-                    //Logger.Debug("Changing kill timer to {0}ms. JobId {1} PlaySessionId {2}", intervalMs, Id, PlaySessionId);
-                    KillTimer.Change(intervalMs, Timeout.Infinite);
-                }
-            }
-        }
-
-        public void ChangeKillTimerIfStarted()
-        {
-            if (HasExited)
-            {
-                return;
-            }
-
-            lock (_timerLock)
-            {
-                if (KillTimer != null)
-                {
-                    var intervalMs = PingTimeout;
-
-                    //Logger.Debug("Changing kill timer to {0}ms. JobId {1} PlaySessionId {2}", intervalMs, Id, PlaySessionId);
-                    KillTimer.Change(intervalMs, Timeout.Infinite);
-                }
-            }
         }
         }
     }
     }
 }
 }

+ 1 - 1
MediaBrowser.Api/FilterService.cs

@@ -63,7 +63,7 @@ namespace MediaBrowser.Api
 
 
             var result = ((Folder)item).GetItemList(GetItemsQuery(request, user));
             var result = ((Folder)item).GetItemList(GetItemsQuery(request, user));
 
 
-            return ToOptimizedResult(GetFilters(result.ToArray()));
+            return ToOptimizedResult(GetFilters(result));
         }
         }
 
 
         private QueryFilters GetFilters(BaseItem[] items)
         private QueryFilters GetFilters(BaseItem[] items)

+ 5 - 2
MediaBrowser.Api/GamesService.cs

@@ -12,6 +12,7 @@ using System.Linq;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
 using MediaBrowser.Model.Querying;
 using MediaBrowser.Model.Querying;
 using MediaBrowser.Model.Services;
 using MediaBrowser.Model.Services;
+using MediaBrowser.Model.Extensions;
 
 
 namespace MediaBrowser.Api
 namespace MediaBrowser.Api
 {
 {
@@ -227,11 +228,13 @@ namespace MediaBrowser.Api
                 SimilarTo = item,
                 SimilarTo = item,
                 DtoOptions = dtoOptions
                 DtoOptions = dtoOptions
 
 
-            }).ToList();
+            });
+
+            var returnList = (await _dtoService.GetBaseItemDtos(itemsResult, dtoOptions, user).ConfigureAwait(false));
 
 
             var result = new QueryResult<BaseItemDto>
             var result = new QueryResult<BaseItemDto>
             {
             {
-                Items = (await _dtoService.GetBaseItemDtos(itemsResult, dtoOptions, user).ConfigureAwait(false)).ToArray(),
+                Items = returnList.ToArray(returnList.Count),
 
 
                 TotalRecordCount = itemsResult.Count
                 TotalRecordCount = itemsResult.Count
             };
             };

+ 8 - 5
MediaBrowser.Api/Images/ImageService.cs

@@ -279,13 +279,16 @@ namespace MediaBrowser.Api.Images
 
 
             var itemImages = item.ImageInfos;
             var itemImages = item.ImageInfos;
 
 
-            foreach (var image in itemImages.Where(i => !item.AllowsMultipleImages(i.Type)))
+            foreach (var image in itemImages)
             {
             {
-                var info = GetImageInfo(item, image, null);
-
-                if (info != null)
+                if (!item.AllowsMultipleImages(image.Type))
                 {
                 {
-                    list.Add(info);
+                    var info = GetImageInfo(item, image, null);
+
+                    if (info != null)
+                    {
+                        list.Add(info);
+                    }
                 }
                 }
             }
             }
 
 

+ 4 - 4
MediaBrowser.Api/ItemUpdateService.cs

@@ -66,8 +66,8 @@ namespace MediaBrowser.Api
             {
             {
                 ParentalRatingOptions = _localizationManager.GetParentalRatings().ToList(),
                 ParentalRatingOptions = _localizationManager.GetParentalRatings().ToList(),
                 ExternalIdInfos = _providerManager.GetExternalIdInfos(item).ToList(),
                 ExternalIdInfos = _providerManager.GetExternalIdInfos(item).ToList(),
-                Countries = _localizationManager.GetCountries().ToList(),
-                Cultures = _localizationManager.GetCultures().ToList()
+                Countries = _localizationManager.GetCountries(),
+                Cultures = _localizationManager.GetCultures()
             };
             };
 
 
             if (!item.IsVirtualItem && !(item is ICollectionFolder) && !(item is UserView) && !(item is AggregateFolder) && !(item is LiveTvChannel) && !(item is IItemByName) &&
             if (!item.IsVirtualItem && !(item is ICollectionFolder) && !(item is UserView) && !(item is AggregateFolder) && !(item is LiveTvChannel) && !(item is IItemByName) &&
@@ -269,7 +269,7 @@ namespace MediaBrowser.Api
 
 
             if (request.Studios != null)
             if (request.Studios != null)
             {
             {
-                item.Studios = request.Studios.Select(x => x.Name).ToList();
+                item.Studios = request.Studios.Select(x => x.Name).ToArray();
             }
             }
 
 
             if (request.DateCreated.HasValue)
             if (request.DateCreated.HasValue)
@@ -285,7 +285,7 @@ namespace MediaBrowser.Api
 
 
             if (request.ProductionLocations != null)
             if (request.ProductionLocations != null)
             {
             {
-                item.ProductionLocations = request.ProductionLocations.ToList();
+                item.ProductionLocations = request.ProductionLocations;
             }
             }
 
 
             item.PreferredMetadataCountryCode = request.PreferredMetadataCountryCode;
             item.PreferredMetadataCountryCode = request.PreferredMetadataCountryCode;

+ 11 - 9
MediaBrowser.Api/Library/LibraryService.cs

@@ -29,6 +29,7 @@ using MediaBrowser.Model.Globalization;
 using MediaBrowser.Model.Services;
 using MediaBrowser.Model.Services;
 using MediaBrowser.Common.Extensions;
 using MediaBrowser.Common.Extensions;
 using MediaBrowser.Common.Progress;
 using MediaBrowser.Common.Progress;
+using MediaBrowser.Model.Extensions;
 
 
 namespace MediaBrowser.Api.Library
 namespace MediaBrowser.Api.Library
 {
 {
@@ -460,22 +461,22 @@ namespace MediaBrowser.Api.Library
                     EnableImages = false
                     EnableImages = false
                 }
                 }
 
 
-            }).ToArray();
+            });
 
 
             if (!string.IsNullOrWhiteSpace(request.ImdbId))
             if (!string.IsNullOrWhiteSpace(request.ImdbId))
             {
             {
-                movies = movies.Where(i => string.Equals(request.ImdbId, i.GetProviderId(MetadataProviders.Imdb), StringComparison.OrdinalIgnoreCase)).ToArray();
+                movies = movies.Where(i => string.Equals(request.ImdbId, i.GetProviderId(MetadataProviders.Imdb), StringComparison.OrdinalIgnoreCase)).ToList();
             }
             }
             else if (!string.IsNullOrWhiteSpace(request.TmdbId))
             else if (!string.IsNullOrWhiteSpace(request.TmdbId))
             {
             {
-                movies = movies.Where(i => string.Equals(request.TmdbId, i.GetProviderId(MetadataProviders.Tmdb), StringComparison.OrdinalIgnoreCase)).ToArray();
+                movies = movies.Where(i => string.Equals(request.TmdbId, i.GetProviderId(MetadataProviders.Tmdb), StringComparison.OrdinalIgnoreCase)).ToList();
             }
             }
             else
             else
             {
             {
-                movies = new BaseItem[] { };
+                movies = new List<BaseItem>();
             }
             }
 
 
-            if (movies.Length > 0)
+            if (movies.Count > 0)
             {
             {
                 foreach (var item in movies)
                 foreach (var item in movies)
                 {
                 {
@@ -732,7 +733,8 @@ namespace MediaBrowser.Api.Library
                 {
                 {
                     DeleteFileLocation = true
                     DeleteFileLocation = true
                 });
                 });
-            }).ToArray();
+
+            }).ToArray(ids.Length);
 
 
             Task.WaitAll(tasks);
             Task.WaitAll(tasks);
         }
         }
@@ -758,7 +760,7 @@ namespace MediaBrowser.Api.Library
         {
         {
             var reviews = _itemRepo.GetCriticReviews(new Guid(request.Id));
             var reviews = _itemRepo.GetCriticReviews(new Guid(request.Id));
 
 
-            var reviewsArray = reviews.ToArray();
+            var reviewsArray = reviews.ToArray(reviews.Count);
 
 
             var result = new QueryResult<ItemReview>
             var result = new QueryResult<ItemReview>
             {
             {
@@ -833,7 +835,7 @@ namespace MediaBrowser.Api.Library
                 throw new ResourceNotFoundException("Item not found.");
                 throw new ResourceNotFoundException("Item not found.");
             }
             }
 
 
-            while (item.ThemeSongIds.Count == 0 && request.InheritFromParent && item.GetParent() != null)
+            while (item.ThemeSongIds.Length == 0 && request.InheritFromParent && item.GetParent() != null)
             {
             {
                 item = item.GetParent();
                 item = item.GetParent();
             }
             }
@@ -882,7 +884,7 @@ namespace MediaBrowser.Api.Library
                 throw new ResourceNotFoundException("Item not found.");
                 throw new ResourceNotFoundException("Item not found.");
             }
             }
 
 
-            while (item.ThemeVideoIds.Count == 0 && request.InheritFromParent && item.GetParent() != null)
+            while (item.ThemeVideoIds.Length == 0 && request.InheritFromParent && item.GetParent() != null)
             {
             {
                 item = item.GetParent();
                 item = item.GetParent();
             }
             }

+ 7 - 6
MediaBrowser.Api/LiveTv/LiveTvService.cs

@@ -16,13 +16,12 @@ using System.Linq;
 using System.Threading;
 using System.Threading;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
 using MediaBrowser.Model.IO;
 using MediaBrowser.Model.IO;
-using MediaBrowser.Api.Playback.Progressive;
 
 
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Entities.TV;
 using MediaBrowser.Controller.Entities.TV;
-using MediaBrowser.Controller.IO;
 using MediaBrowser.Model.Services;
 using MediaBrowser.Model.Services;
 using MediaBrowser.Model.System;
 using MediaBrowser.Model.System;
+using MediaBrowser.Model.Extensions;
 
 
 namespace MediaBrowser.Api.LiveTv
 namespace MediaBrowser.Api.LiveTv
 {
 {
@@ -734,7 +733,7 @@ namespace MediaBrowser.Api.LiveTv
 
 
             outputHeaders["Content-Type"] = Model.Net.MimeTypes.GetMimeType(path);
             outputHeaders["Content-Type"] = Model.Net.MimeTypes.GetMimeType(path);
 
 
-            return new ProgressiveFileCopier(_fileSystem, path, outputHeaders, null, Logger, _environment, CancellationToken.None)
+            return new ProgressiveFileCopier(_fileSystem, path, outputHeaders, Logger, _environment, CancellationToken.None)
             {
             {
                 AllowEndOfFile = false
                 AllowEndOfFile = false
             };
             };
@@ -753,7 +752,7 @@ namespace MediaBrowser.Api.LiveTv
 
 
             outputHeaders["Content-Type"] = Model.Net.MimeTypes.GetMimeType("file." + request.Container);
             outputHeaders["Content-Type"] = Model.Net.MimeTypes.GetMimeType("file." + request.Container);
 
 
-            return new ProgressiveFileCopier(directStreamProvider, outputHeaders, null, Logger, _environment, CancellationToken.None)
+            return new ProgressiveFileCopier(directStreamProvider, outputHeaders, Logger, _environment, CancellationToken.None)
             {
             {
                 AllowEndOfFile = false
                 AllowEndOfFile = false
             };
             };
@@ -921,7 +920,9 @@ namespace MediaBrowser.Api.LiveTv
 
 
             options.AddCurrentProgram = request.AddCurrentProgram;
             options.AddCurrentProgram = request.AddCurrentProgram;
 
 
-            var returnArray = (await _dtoService.GetBaseItemDtos(channelResult.Items, options, user).ConfigureAwait(false)).ToArray();
+            var returnList = (await _dtoService.GetBaseItemDtos(channelResult.Items, options, user)
+                .ConfigureAwait(false));
+            var returnArray = returnList.ToArray(returnList.Count);
 
 
             var result = new QueryResult<BaseItemDto>
             var result = new QueryResult<BaseItemDto>
             {
             {
@@ -962,7 +963,7 @@ namespace MediaBrowser.Api.LiveTv
         {
         {
             var query = new ProgramQuery
             var query = new ProgramQuery
             {
             {
-                ChannelIds = (request.ChannelIds ?? string.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToArray(),
+                ChannelIds = ApiEntryPoint.Split(request.ChannelIds, ',', true),
                 UserId = request.UserId,
                 UserId = request.UserId,
                 HasAired = request.HasAired,
                 HasAired = request.HasAired,
                 EnableTotalRecordCount = request.EnableTotalRecordCount
                 EnableTotalRecordCount = request.EnableTotalRecordCount

+ 39 - 68
MediaBrowser.Api/Playback/Progressive/ProgressiveStreamWriter.cs → MediaBrowser.Api/LiveTv/ProgressiveFileCopier.cs

@@ -1,23 +1,19 @@
-using MediaBrowser.Model.Logging;
-using System;
+using System;
+using System.Collections.Generic;
 using System.IO;
 using System.IO;
 using System.Threading;
 using System.Threading;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Controller.Net;
-using System.Collections.Generic;
-
-using MediaBrowser.Controller.IO;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Library;
+using MediaBrowser.Model.IO;
+using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.Services;
 using MediaBrowser.Model.Services;
 using MediaBrowser.Model.System;
 using MediaBrowser.Model.System;
 
 
-namespace MediaBrowser.Api.Playback.Progressive
+namespace MediaBrowser.Api.LiveTv
 {
 {
     public class ProgressiveFileCopier : IAsyncStreamWriter, IHasHeaders
     public class ProgressiveFileCopier : IAsyncStreamWriter, IHasHeaders
     {
     {
         private readonly IFileSystem _fileSystem;
         private readonly IFileSystem _fileSystem;
-        private readonly TranscodingJob _job;
         private readonly ILogger _logger;
         private readonly ILogger _logger;
         private readonly string _path;
         private readonly string _path;
         private readonly CancellationToken _cancellationToken;
         private readonly CancellationToken _cancellationToken;
@@ -32,22 +28,20 @@ namespace MediaBrowser.Api.Playback.Progressive
         private readonly IDirectStreamProvider _directStreamProvider;
         private readonly IDirectStreamProvider _directStreamProvider;
         private readonly IEnvironmentInfo _environment;
         private readonly IEnvironmentInfo _environment;
 
 
-        public ProgressiveFileCopier(IFileSystem fileSystem, string path, Dictionary<string, string> outputHeaders, TranscodingJob job, ILogger logger, IEnvironmentInfo environment, CancellationToken cancellationToken)
+        public ProgressiveFileCopier(IFileSystem fileSystem, string path, Dictionary<string, string> outputHeaders, ILogger logger, IEnvironmentInfo environment, CancellationToken cancellationToken)
         {
         {
             _fileSystem = fileSystem;
             _fileSystem = fileSystem;
             _path = path;
             _path = path;
             _outputHeaders = outputHeaders;
             _outputHeaders = outputHeaders;
-            _job = job;
             _logger = logger;
             _logger = logger;
             _cancellationToken = cancellationToken;
             _cancellationToken = cancellationToken;
             _environment = environment;
             _environment = environment;
         }
         }
 
 
-        public ProgressiveFileCopier(IDirectStreamProvider directStreamProvider, Dictionary<string, string> outputHeaders, TranscodingJob job, ILogger logger, IEnvironmentInfo environment, CancellationToken cancellationToken)
+        public ProgressiveFileCopier(IDirectStreamProvider directStreamProvider, Dictionary<string, string> outputHeaders, ILogger logger, IEnvironmentInfo environment, CancellationToken cancellationToken)
         {
         {
             _directStreamProvider = directStreamProvider;
             _directStreamProvider = directStreamProvider;
             _outputHeaders = outputHeaders;
             _outputHeaders = outputHeaders;
-            _job = job;
             _logger = logger;
             _logger = logger;
             _cancellationToken = cancellationToken;
             _cancellationToken = cancellationToken;
             _environment = environment;
             _environment = environment;
@@ -77,61 +71,48 @@ namespace MediaBrowser.Api.Playback.Progressive
         {
         {
             cancellationToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, _cancellationToken).Token;
             cancellationToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, _cancellationToken).Token;
 
 
-            try
+            if (_directStreamProvider != null)
             {
             {
-                if (_directStreamProvider != null)
-                {
-                    await _directStreamProvider.CopyToAsync(outputStream, cancellationToken).ConfigureAwait(false);
-                    return;
-                }
+                await _directStreamProvider.CopyToAsync(outputStream, cancellationToken).ConfigureAwait(false);
+                return;
+            }
 
 
-                var eofCount = 0;
+            var eofCount = 0;
 
 
-                // use non-async filestream along with read due to https://github.com/dotnet/corefx/issues/6039
-                var allowAsyncFileRead = _environment.OperatingSystem != OperatingSystem.Windows;
+            // use non-async filestream along with read due to https://github.com/dotnet/corefx/issues/6039
+            var allowAsyncFileRead = _environment.OperatingSystem != OperatingSystem.Windows;
 
 
-                using (var inputStream = GetInputStream(allowAsyncFileRead))
+            using (var inputStream = GetInputStream(allowAsyncFileRead))
+            {
+                if (StartPosition > 0)
                 {
                 {
-                    if (StartPosition > 0)
+                    inputStream.Position = StartPosition;
+                }
+
+                while (eofCount < 20 || !AllowEndOfFile)
+                {
+                    int bytesRead;
+                    if (allowAsyncFileRead)
+                    {
+                        bytesRead = await CopyToInternalAsync(inputStream, outputStream, cancellationToken).ConfigureAwait(false);
+                    }
+                    else
                     {
                     {
-                        inputStream.Position = StartPosition;
+                        bytesRead = await CopyToInternalAsyncWithSyncRead(inputStream, outputStream, cancellationToken).ConfigureAwait(false);
                     }
                     }
 
 
-                    while (eofCount < 20 || !AllowEndOfFile)
+                    //var position = fs.Position;
+                    //_logger.Debug("Streamed {0} bytes to position {1} from file {2}", bytesRead, position, path);
+
+                    if (bytesRead == 0)
                     {
                     {
-                        int bytesRead;
-                        if (allowAsyncFileRead)
-                        {
-                            bytesRead = await CopyToInternalAsync(inputStream, outputStream, cancellationToken).ConfigureAwait(false);
-                        }
-                        else
-                        {
-                            bytesRead = await CopyToInternalAsyncWithSyncRead(inputStream, outputStream, cancellationToken).ConfigureAwait(false);
-                        }
-
-                        //var position = fs.Position;
-                        //_logger.Debug("Streamed {0} bytes to position {1} from file {2}", bytesRead, position, path);
-
-                        if (bytesRead == 0)
-                        {
-                            if (_job == null || _job.HasExited)
-                            {
-                                eofCount++;
-                            }
-                            await Task.Delay(100, cancellationToken).ConfigureAwait(false);
-                        }
-                        else
-                        {
-                            eofCount = 0;
-                        }
+                        eofCount++;
+                        await Task.Delay(100, cancellationToken).ConfigureAwait(false);
+                    }
+                    else
+                    {
+                        eofCount = 0;
                     }
                     }
-                }
-            }
-            finally
-            {
-                if (_job != null)
-                {
-                    ApiEntryPoint.Instance.OnTranscodeEndRequest(_job);
                 }
                 }
             }
             }
         }
         }
@@ -152,11 +133,6 @@ namespace MediaBrowser.Api.Playback.Progressive
 
 
                     _bytesWritten += bytesRead;
                     _bytesWritten += bytesRead;
                     totalBytesRead += bytesRead;
                     totalBytesRead += bytesRead;
-
-                    if (_job != null)
-                    {
-                        _job.BytesDownloaded = Math.Max(_job.BytesDownloaded ?? _bytesWritten, _bytesWritten);
-                    }
                 }
                 }
             }
             }
 
 
@@ -179,11 +155,6 @@ namespace MediaBrowser.Api.Playback.Progressive
 
 
                     _bytesWritten += bytesRead;
                     _bytesWritten += bytesRead;
                     totalBytesRead += bytesRead;
                     totalBytesRead += bytesRead;
-
-                    if (_job != null)
-                    {
-                        _job.BytesDownloaded = Math.Max(_job.BytesDownloaded ?? _bytesWritten, _bytesWritten);
-                    }
                 }
                 }
             }
             }
 
 

+ 2 - 2
MediaBrowser.Api/LocalizationService.cs

@@ -85,7 +85,7 @@ namespace MediaBrowser.Api
         /// <returns>System.Object.</returns>
         /// <returns>System.Object.</returns>
         public object Get(GetCountries request)
         public object Get(GetCountries request)
         {
         {
-            var result = _localization.GetCountries().ToList();
+            var result = _localization.GetCountries();
 
 
             return ToOptimizedResult(result);
             return ToOptimizedResult(result);
         }
         }
@@ -97,7 +97,7 @@ namespace MediaBrowser.Api
         /// <returns>System.Object.</returns>
         /// <returns>System.Object.</returns>
         public object Get(GetCultures request)
         public object Get(GetCultures request)
         {
         {
-            var result = _localization.GetCultures().ToList();
+            var result = _localization.GetCultures();
 
 
             return ToOptimizedResult(result);
             return ToOptimizedResult(result);
         }
         }

+ 1 - 17
MediaBrowser.Api/MediaBrowser.Api.csproj

@@ -48,9 +48,7 @@
     <Compile Include="Dlna\DlnaService.cs" />
     <Compile Include="Dlna\DlnaService.cs" />
     <Compile Include="FilterService.cs" />
     <Compile Include="FilterService.cs" />
     <Compile Include="IHasDtoOptions.cs" />
     <Compile Include="IHasDtoOptions.cs" />
-    <Compile Include="Playback\MediaInfoService.cs" />
-    <Compile Include="Playback\TranscodingThrottler.cs" />
-    <Compile Include="Playback\UniversalAudioService.cs" />
+    <Compile Include="LiveTv\ProgressiveFileCopier.cs" />
     <Compile Include="PlaylistService.cs" />
     <Compile Include="PlaylistService.cs" />
     <Compile Include="Reports\Activities\ReportActivitiesBuilder.cs" />
     <Compile Include="Reports\Activities\ReportActivitiesBuilder.cs" />
     <Compile Include="Reports\Common\HeaderActivitiesMetadata.cs" />
     <Compile Include="Reports\Common\HeaderActivitiesMetadata.cs" />
@@ -101,18 +99,6 @@
     <Compile Include="NotificationsService.cs" />
     <Compile Include="NotificationsService.cs" />
     <Compile Include="PackageReviewService.cs" />
     <Compile Include="PackageReviewService.cs" />
     <Compile Include="PackageService.cs" />
     <Compile Include="PackageService.cs" />
-    <Compile Include="Playback\Hls\BaseHlsService.cs" />
-    <Compile Include="Playback\Hls\DynamicHlsService.cs" />
-    <Compile Include="Playback\Hls\HlsSegmentService.cs" />
-    <Compile Include="Playback\Hls\VideoHlsService.cs" />
-    <Compile Include="Playback\Progressive\AudioService.cs" />
-    <Compile Include="Playback\Progressive\BaseProgressiveStreamingService.cs" />
-    <Compile Include="Playback\BaseStreamingService.cs" />
-    <Compile Include="Playback\Progressive\ProgressiveStreamWriter.cs" />
-    <Compile Include="Playback\StaticRemoteStreamWriter.cs" />
-    <Compile Include="Playback\StreamRequest.cs" />
-    <Compile Include="Playback\StreamState.cs" />
-    <Compile Include="Playback\Progressive\VideoService.cs" />
     <Compile Include="PluginService.cs" />
     <Compile Include="PluginService.cs" />
     <Compile Include="Images\RemoteImageService.cs" />
     <Compile Include="Images\RemoteImageService.cs" />
     <Compile Include="ScheduledTasks\ScheduledTaskService.cs" />
     <Compile Include="ScheduledTasks\ScheduledTaskService.cs" />
@@ -126,7 +112,6 @@
     <Compile Include="System\ActivityLogWebSocketListener.cs" />
     <Compile Include="System\ActivityLogWebSocketListener.cs" />
     <Compile Include="System\SystemService.cs" />
     <Compile Include="System\SystemService.cs" />
     <Compile Include="Movies\TrailersService.cs" />
     <Compile Include="Movies\TrailersService.cs" />
-    <Compile Include="TestService.cs" />
     <Compile Include="TvShowsService.cs" />
     <Compile Include="TvShowsService.cs" />
     <Compile Include="UserLibrary\ArtistsService.cs" />
     <Compile Include="UserLibrary\ArtistsService.cs" />
     <Compile Include="UserLibrary\BaseItemsByNameService.cs" />
     <Compile Include="UserLibrary\BaseItemsByNameService.cs" />
@@ -136,7 +121,6 @@
     <Compile Include="UserLibrary\ItemsService.cs" />
     <Compile Include="UserLibrary\ItemsService.cs" />
     <Compile Include="UserLibrary\MusicGenresService.cs" />
     <Compile Include="UserLibrary\MusicGenresService.cs" />
     <Compile Include="UserLibrary\PersonsService.cs" />
     <Compile Include="UserLibrary\PersonsService.cs" />
-    <Compile Include="UserLibrary\PlaystateService.cs" />
     <Compile Include="UserLibrary\StudiosService.cs" />
     <Compile Include="UserLibrary\StudiosService.cs" />
     <Compile Include="UserLibrary\UserLibraryService.cs" />
     <Compile Include="UserLibrary\UserLibraryService.cs" />
     <Compile Include="UserLibrary\UserViewsService.cs" />
     <Compile Include="UserLibrary\UserViewsService.cs" />

+ 26 - 18
MediaBrowser.Api/Movies/MoviesService.cs

@@ -158,17 +158,19 @@ namespace MediaBrowser.Api.Movies
             var itemsResult = _libraryManager.GetItemList(new InternalItemsQuery(user)
             var itemsResult = _libraryManager.GetItemList(new InternalItemsQuery(user)
             {
             {
                 Limit = request.Limit,
                 Limit = request.Limit,
-                IncludeItemTypes = itemTypes.ToArray(),
+                IncludeItemTypes = itemTypes.ToArray(itemTypes.Count),
                 IsMovie = true,
                 IsMovie = true,
                 SimilarTo = item,
                 SimilarTo = item,
                 EnableGroupByMetadataKey = true,
                 EnableGroupByMetadataKey = true,
                 DtoOptions = dtoOptions
                 DtoOptions = dtoOptions
 
 
-            }).ToList();
+            });
+
+            var returnList = await _dtoService.GetBaseItemDtos(itemsResult, dtoOptions, user).ConfigureAwait(false);
 
 
             var result = new QueryResult<BaseItemDto>
             var result = new QueryResult<BaseItemDto>
             {
             {
-                Items = (await _dtoService.GetBaseItemDtos(itemsResult, dtoOptions, user).ConfigureAwait(false)).ToArray(),
+                Items = returnList.ToArray(returnList.Count),
 
 
                 TotalRecordCount = itemsResult.Count
                 TotalRecordCount = itemsResult.Count
             };
             };
@@ -200,7 +202,7 @@ namespace MediaBrowser.Api.Movies
                 DtoOptions = dtoOptions
                 DtoOptions = dtoOptions
             };
             };
 
 
-            var recentlyPlayedMovies = _libraryManager.GetItemList(query).ToList();
+            var recentlyPlayedMovies = _libraryManager.GetItemList(query);
 
 
             var itemTypes = new List<string> { typeof(Movie).Name };
             var itemTypes = new List<string> { typeof(Movie).Name };
             if (_config.Configuration.EnableExternalContentInSuggestions)
             if (_config.Configuration.EnableExternalContentInSuggestions)
@@ -211,19 +213,19 @@ namespace MediaBrowser.Api.Movies
 
 
             var likedMovies = _libraryManager.GetItemList(new InternalItemsQuery(user)
             var likedMovies = _libraryManager.GetItemList(new InternalItemsQuery(user)
             {
             {
-                IncludeItemTypes = itemTypes.ToArray(),
+                IncludeItemTypes = itemTypes.ToArray(itemTypes.Count),
                 IsMovie = true,
                 IsMovie = true,
                 SortBy = new[] { ItemSortBy.Random },
                 SortBy = new[] { ItemSortBy.Random },
                 SortOrder = SortOrder.Descending,
                 SortOrder = SortOrder.Descending,
                 Limit = 10,
                 Limit = 10,
                 IsFavoriteOrLiked = true,
                 IsFavoriteOrLiked = true,
-                ExcludeItemIds = recentlyPlayedMovies.Select(i => i.Id.ToString("N")).ToArray(),
+                ExcludeItemIds = recentlyPlayedMovies.Select(i => i.Id.ToString("N")).ToArray(recentlyPlayedMovies.Count),
                 EnableGroupByMetadataKey = true,
                 EnableGroupByMetadataKey = true,
                 ParentId = parentIdGuid,
                 ParentId = parentIdGuid,
                 Recursive = true,
                 Recursive = true,
                 DtoOptions = dtoOptions
                 DtoOptions = dtoOptions
 
 
-            }).ToList();
+            });
 
 
             var mostRecentMovies = recentlyPlayedMovies.Take(6).ToList();
             var mostRecentMovies = recentlyPlayedMovies.Take(6).ToList();
             // Get recently played directors
             // Get recently played directors
@@ -300,7 +302,7 @@ namespace MediaBrowser.Api.Movies
                     // Account for duplicates by imdb id, since the database doesn't support this yet
                     // Account for duplicates by imdb id, since the database doesn't support this yet
                     Limit = itemLimit + 2,
                     Limit = itemLimit + 2,
                     PersonTypes = new[] { PersonType.Director },
                     PersonTypes = new[] { PersonType.Director },
-                    IncludeItemTypes = itemTypes.ToArray(),
+                    IncludeItemTypes = itemTypes.ToArray(itemTypes.Count),
                     IsMovie = true,
                     IsMovie = true,
                     EnableGroupByMetadataKey = true,
                     EnableGroupByMetadataKey = true,
                     DtoOptions = dtoOptions
                     DtoOptions = dtoOptions
@@ -311,12 +313,14 @@ namespace MediaBrowser.Api.Movies
 
 
                 if (items.Count > 0)
                 if (items.Count > 0)
                 {
                 {
+                    var returnItems = _dtoService.GetBaseItemDtos(items, dtoOptions, user).Result;
+
                     yield return new RecommendationDto
                     yield return new RecommendationDto
                     {
                     {
                         BaselineItemName = name,
                         BaselineItemName = name,
                         CategoryId = name.GetMD5().ToString("N"),
                         CategoryId = name.GetMD5().ToString("N"),
                         RecommendationType = type,
                         RecommendationType = type,
-                        Items = _dtoService.GetBaseItemDtos(items, dtoOptions, user).Result.ToArray()
+                        Items = returnItems.ToArray(returnItems.Count)
                     };
                     };
                 }
                 }
             }
             }
@@ -338,7 +342,7 @@ namespace MediaBrowser.Api.Movies
                     Person = name,
                     Person = name,
                     // Account for duplicates by imdb id, since the database doesn't support this yet
                     // Account for duplicates by imdb id, since the database doesn't support this yet
                     Limit = itemLimit + 2,
                     Limit = itemLimit + 2,
-                    IncludeItemTypes = itemTypes.ToArray(),
+                    IncludeItemTypes = itemTypes.ToArray(itemTypes.Count),
                     IsMovie = true,
                     IsMovie = true,
                     EnableGroupByMetadataKey = true,
                     EnableGroupByMetadataKey = true,
                     DtoOptions = dtoOptions
                     DtoOptions = dtoOptions
@@ -349,12 +353,14 @@ namespace MediaBrowser.Api.Movies
 
 
                 if (items.Count > 0)
                 if (items.Count > 0)
                 {
                 {
+                    var returnItems = _dtoService.GetBaseItemDtos(items, dtoOptions, user).Result;
+
                     yield return new RecommendationDto
                     yield return new RecommendationDto
                     {
                     {
                         BaselineItemName = name,
                         BaselineItemName = name,
                         CategoryId = name.GetMD5().ToString("N"),
                         CategoryId = name.GetMD5().ToString("N"),
                         RecommendationType = type,
                         RecommendationType = type,
-                        Items = _dtoService.GetBaseItemDtos(items, dtoOptions, user).Result.ToArray()
+                        Items = returnItems.ToArray(returnItems.Count)
                     };
                     };
                 }
                 }
             }
             }
@@ -374,28 +380,30 @@ namespace MediaBrowser.Api.Movies
                 var similar = _libraryManager.GetItemList(new InternalItemsQuery(user)
                 var similar = _libraryManager.GetItemList(new InternalItemsQuery(user)
                 {
                 {
                     Limit = itemLimit,
                     Limit = itemLimit,
-                    IncludeItemTypes = itemTypes.ToArray(),
+                    IncludeItemTypes = itemTypes.ToArray(itemTypes.Count),
                     IsMovie = true,
                     IsMovie = true,
                     SimilarTo = item,
                     SimilarTo = item,
                     EnableGroupByMetadataKey = true,
                     EnableGroupByMetadataKey = true,
                     DtoOptions = dtoOptions
                     DtoOptions = dtoOptions
 
 
-                }).ToList();
+                });
 
 
                 if (similar.Count > 0)
                 if (similar.Count > 0)
                 {
                 {
+                    var returnItems = _dtoService.GetBaseItemDtos(similar, dtoOptions, user).Result;
+
                     yield return new RecommendationDto
                     yield return new RecommendationDto
                     {
                     {
                         BaselineItemName = item.Name,
                         BaselineItemName = item.Name,
                         CategoryId = item.Id.ToString("N"),
                         CategoryId = item.Id.ToString("N"),
                         RecommendationType = type,
                         RecommendationType = type,
-                        Items = _dtoService.GetBaseItemDtos(similar, dtoOptions, user).Result.ToArray()
+                        Items = returnItems.ToArray(returnItems.Count)
                     };
                     };
                 }
                 }
             }
             }
         }
         }
 
 
-        private IEnumerable<string> GetActors(IEnumerable<BaseItem> items)
+        private IEnumerable<string> GetActors(List<BaseItem> items)
         {
         {
             var people = _libraryManager.GetPeople(new InternalPeopleQuery
             var people = _libraryManager.GetPeople(new InternalPeopleQuery
             {
             {
@@ -406,7 +414,7 @@ namespace MediaBrowser.Api.Movies
                 MaxListOrder = 3
                 MaxListOrder = 3
             });
             });
 
 
-            var itemIds = items.Select(i => i.Id).ToList();
+            var itemIds = items.Select(i => i.Id).ToList(items.Count);
 
 
             return people
             return people
                 .Where(i => itemIds.Contains(i.ItemId))
                 .Where(i => itemIds.Contains(i.ItemId))
@@ -414,7 +422,7 @@ namespace MediaBrowser.Api.Movies
                 .DistinctNames();
                 .DistinctNames();
         }
         }
 
 
-        private IEnumerable<string> GetDirectors(IEnumerable<BaseItem> items)
+        private IEnumerable<string> GetDirectors(List<BaseItem> items)
         {
         {
             var people = _libraryManager.GetPeople(new InternalPeopleQuery
             var people = _libraryManager.GetPeople(new InternalPeopleQuery
             {
             {
@@ -424,7 +432,7 @@ namespace MediaBrowser.Api.Movies
                 }
                 }
             });
             });
 
 
-            var itemIds = items.Select(i => i.Id).ToList();
+            var itemIds = items.Select(i => i.Id).ToList(items.Count);
 
 
             return people
             return people
                 .Where(i => itemIds.Contains(i.ItemId))
                 .Where(i => itemIds.Contains(i.ItemId))

+ 7 - 3
MediaBrowser.Api/Music/InstantMixService.cs

@@ -9,6 +9,7 @@ using System.Collections.Generic;
 using System.Linq;
 using System.Linq;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
 using MediaBrowser.Model.Services;
 using MediaBrowser.Model.Services;
+using MediaBrowser.Model.Extensions;
 
 
 namespace MediaBrowser.Api.Music
 namespace MediaBrowser.Api.Music
 {
 {
@@ -180,16 +181,19 @@ namespace MediaBrowser.Api.Music
             return GetResult(items, user, request, dtoOptions);
             return GetResult(items, user, request, dtoOptions);
         }
         }
 
 
-        private async Task<object> GetResult(IEnumerable<Audio> items, User user, BaseGetSimilarItems request, DtoOptions dtoOptions)
+        private async Task<object> GetResult(List<BaseItem> items, User user, BaseGetSimilarItems request, DtoOptions dtoOptions)
         {
         {
-            var list = items.ToList();
+            var list = items;
 
 
             var result = new ItemsResult
             var result = new ItemsResult
             {
             {
                 TotalRecordCount = list.Count
                 TotalRecordCount = list.Count
             };
             };
 
 
-            result.Items = (await _dtoService.GetBaseItemDtos(list.Take(request.Limit ?? list.Count), dtoOptions, user).ConfigureAwait(false)).ToArray();
+            var returnList = (await _dtoService.GetBaseItemDtos(list.Take(request.Limit ?? list.Count), dtoOptions, user)
+                .ConfigureAwait(false));
+
+            result.Items = returnList.ToArray(returnList.Count);
 
 
             return ToOptimizedResult(result);
             return ToOptimizedResult(result);
         }
         }

+ 0 - 1024
MediaBrowser.Api/Playback/BaseStreamingService.cs

@@ -1,1024 +0,0 @@
-using MediaBrowser.Common.Extensions;
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Devices;
-using MediaBrowser.Controller.Dlna;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.MediaEncoding;
-using MediaBrowser.Model.Dlna;
-using MediaBrowser.Model.Dto;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Extensions;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Model.MediaInfo;
-using MediaBrowser.Model.Serialization;
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.IO;
-using System.Linq;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Common.Net;
-using MediaBrowser.Controller;
-using MediaBrowser.Controller.Net;
-using MediaBrowser.Model.Configuration;
-using MediaBrowser.Model.Diagnostics;
-
-namespace MediaBrowser.Api.Playback
-{
-    /// <summary>
-    /// Class BaseStreamingService
-    /// </summary>
-    public abstract class BaseStreamingService : BaseApiService
-    {
-        /// <summary>
-        /// Gets or sets the application paths.
-        /// </summary>
-        /// <value>The application paths.</value>
-        protected IServerConfigurationManager ServerConfigurationManager { get; private set; }
-
-        /// <summary>
-        /// Gets or sets the user manager.
-        /// </summary>
-        /// <value>The user manager.</value>
-        protected IUserManager UserManager { get; private set; }
-
-        /// <summary>
-        /// Gets or sets the library manager.
-        /// </summary>
-        /// <value>The library manager.</value>
-        protected ILibraryManager LibraryManager { get; private set; }
-
-        /// <summary>
-        /// Gets or sets the iso manager.
-        /// </summary>
-        /// <value>The iso manager.</value>
-        protected IIsoManager IsoManager { get; private set; }
-
-        /// <summary>
-        /// Gets or sets the media encoder.
-        /// </summary>
-        /// <value>The media encoder.</value>
-        protected IMediaEncoder MediaEncoder { get; private set; }
-
-        protected IFileSystem FileSystem { get; private set; }
-
-        protected IDlnaManager DlnaManager { get; private set; }
-        protected IDeviceManager DeviceManager { get; private set; }
-        protected ISubtitleEncoder SubtitleEncoder { get; private set; }
-        protected IMediaSourceManager MediaSourceManager { get; private set; }
-        protected IZipClient ZipClient { get; private set; }
-        protected IJsonSerializer JsonSerializer { get; private set; }
-
-        public static IServerApplicationHost AppHost;
-        public static IHttpClient HttpClient;
-        protected IAuthorizationContext AuthorizationContext { get; private set; }
-
-        protected EncodingHelper EncodingHelper { get; set; }
-
-        /// <summary>
-        /// Initializes a new instance of the <see cref="BaseStreamingService" /> class.
-        /// </summary>
-        protected BaseStreamingService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IJsonSerializer jsonSerializer, IAuthorizationContext authorizationContext)
-        {
-            JsonSerializer = jsonSerializer;
-            AuthorizationContext = authorizationContext;
-            ZipClient = zipClient;
-            MediaSourceManager = mediaSourceManager;
-            DeviceManager = deviceManager;
-            SubtitleEncoder = subtitleEncoder;
-            DlnaManager = dlnaManager;
-            FileSystem = fileSystem;
-            ServerConfigurationManager = serverConfig;
-            UserManager = userManager;
-            LibraryManager = libraryManager;
-            IsoManager = isoManager;
-            MediaEncoder = mediaEncoder;
-            EncodingHelper = new EncodingHelper(MediaEncoder, FileSystem, SubtitleEncoder);
-        }
-
-        /// <summary>
-        /// Gets the command line arguments.
-        /// </summary>
-        protected abstract string GetCommandLineArguments(string outputPath, EncodingOptions encodingOptions, StreamState state, bool isEncoding);
-
-        /// <summary>
-        /// Gets the type of the transcoding job.
-        /// </summary>
-        /// <value>The type of the transcoding job.</value>
-        protected abstract TranscodingJobType TranscodingJobType { get; }
-
-        /// <summary>
-        /// Gets the output file extension.
-        /// </summary>
-        /// <param name="state">The state.</param>
-        /// <returns>System.String.</returns>
-        protected virtual string GetOutputFileExtension(StreamState state)
-        {
-            return Path.GetExtension(state.RequestedUrl);
-        }
-
-        /// <summary>
-        /// Gets the output file path.
-        /// </summary>
-        private string GetOutputFilePath(StreamState state, EncodingOptions encodingOptions, string outputFileExtension)
-        {
-            var folder = ServerConfigurationManager.ApplicationPaths.TranscodingTempPath;
-
-            var data = GetCommandLineArguments("dummy\\dummy", encodingOptions, state, false);
-
-            data += "-" + (state.Request.DeviceId ?? string.Empty);
-            data += "-" + (state.Request.PlaySessionId ?? string.Empty);
-
-            var dataHash = data.GetMD5().ToString("N");
-
-            if (EnableOutputInSubFolder)
-            {
-                return Path.Combine(folder, dataHash, dataHash + (outputFileExtension ?? string.Empty).ToLower());
-            }
-
-            return Path.Combine(folder, dataHash + (outputFileExtension ?? string.Empty).ToLower());
-        }
-
-        protected virtual bool EnableOutputInSubFolder
-        {
-            get { return false; }
-        }
-
-        protected readonly CultureInfo UsCulture = new CultureInfo("en-US");
-
-        protected virtual string GetDefaultH264Preset()
-        {
-            return "superfast";
-        }
-
-        private async Task AcquireResources(StreamState state, CancellationTokenSource cancellationTokenSource)
-        {
-            if (state.VideoType == VideoType.Iso && state.IsoType.HasValue && IsoManager.CanMount(state.MediaPath))
-            {
-                state.IsoMount = await IsoManager.Mount(state.MediaPath, cancellationTokenSource.Token).ConfigureAwait(false);
-            }
-
-            if (state.MediaSource.RequiresOpening && string.IsNullOrWhiteSpace(state.Request.LiveStreamId))
-            {
-                var liveStreamResponse = await MediaSourceManager.OpenLiveStream(new LiveStreamRequest
-                {
-                    OpenToken = state.MediaSource.OpenToken
-
-                }, cancellationTokenSource.Token).ConfigureAwait(false);
-
-                EncodingHelper.AttachMediaSourceInfo(state, liveStreamResponse.MediaSource, state.RequestedUrl);
-
-                if (state.VideoRequest != null)
-                {
-                    EncodingHelper.TryStreamCopy(state);
-                }
-            }
-
-            if (state.MediaSource.BufferMs.HasValue)
-            {
-                await Task.Delay(state.MediaSource.BufferMs.Value, cancellationTokenSource.Token).ConfigureAwait(false);
-            }
-        }
-
-        /// <summary>
-        /// Starts the FFMPEG.
-        /// </summary>
-        /// <param name="state">The state.</param>
-        /// <param name="outputPath">The output path.</param>
-        /// <param name="cancellationTokenSource">The cancellation token source.</param>
-        /// <param name="workingDirectory">The working directory.</param>
-        /// <returns>Task.</returns>
-        protected async Task<TranscodingJob> StartFfMpeg(StreamState state,
-            string outputPath,
-            CancellationTokenSource cancellationTokenSource,
-            string workingDirectory = null)
-        {
-            FileSystem.CreateDirectory(FileSystem.GetDirectoryName(outputPath));
-
-            await AcquireResources(state, cancellationTokenSource).ConfigureAwait(false);
-
-            if (state.VideoRequest != null && !string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase))
-            {
-                var auth = AuthorizationContext.GetAuthorizationInfo(Request);
-                if (!string.IsNullOrWhiteSpace(auth.UserId))
-                {
-                    var user = UserManager.GetUserById(auth.UserId);
-                    if (!user.Policy.EnableVideoPlaybackTranscoding)
-                    {
-                        ApiEntryPoint.Instance.OnTranscodeFailedToStart(outputPath, TranscodingJobType, state);
-
-                        throw new ArgumentException("User does not have access to video transcoding");
-                    }
-                }
-            }
-
-            var encodingOptions = ApiEntryPoint.Instance.GetEncodingOptions();
-
-            var transcodingId = Guid.NewGuid().ToString("N");
-            var commandLineArgs = GetCommandLineArguments(outputPath, encodingOptions, state, true);
-
-            var process = ApiEntryPoint.Instance.ProcessFactory.Create(new ProcessOptions
-            {
-                CreateNoWindow = true,
-                UseShellExecute = false,
-
-                // Must consume both stdout and stderr or deadlocks may occur
-                //RedirectStandardOutput = true,
-                RedirectStandardError = true,
-                RedirectStandardInput = true,
-
-                FileName = MediaEncoder.EncoderPath,
-                Arguments = commandLineArgs,
-
-                IsHidden = true,
-                ErrorDialog = false,
-                EnableRaisingEvents = true,
-                WorkingDirectory = !string.IsNullOrWhiteSpace(workingDirectory) ? workingDirectory : null
-            });
-
-            var transcodingJob = ApiEntryPoint.Instance.OnTranscodeBeginning(outputPath,
-                state.Request.PlaySessionId,
-                state.MediaSource.LiveStreamId,
-                transcodingId,
-                TranscodingJobType,
-                process,
-                state.Request.DeviceId,
-                state,
-                cancellationTokenSource);
-
-            var commandLineLogMessage = process.StartInfo.FileName + " " + process.StartInfo.Arguments;
-            Logger.Info(commandLineLogMessage);
-
-            var logFilePrefix = "ffmpeg-transcode";
-            if (state.VideoRequest != null && string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase) && string.Equals(state.OutputAudioCodec, "copy", StringComparison.OrdinalIgnoreCase))
-            {
-                logFilePrefix = "ffmpeg-directstream";
-            }
-            else if (state.VideoRequest != null && string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase))
-            {
-                logFilePrefix = "ffmpeg-remux";
-            }
-
-            var logFilePath = Path.Combine(ServerConfigurationManager.ApplicationPaths.LogDirectoryPath, logFilePrefix + "-" + Guid.NewGuid() + ".txt");
-            FileSystem.CreateDirectory(FileSystem.GetDirectoryName(logFilePath));
-
-            // FFMpeg writes debug/error info to stderr. This is useful when debugging so let's put it in the log directory.
-            state.LogFileStream = FileSystem.GetFileStream(logFilePath, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read, true);
-
-            var commandLineLogMessageBytes = Encoding.UTF8.GetBytes(Request.AbsoluteUri + Environment.NewLine + Environment.NewLine + JsonSerializer.SerializeToString(state.MediaSource) + Environment.NewLine + Environment.NewLine + commandLineLogMessage + Environment.NewLine + Environment.NewLine);
-            await state.LogFileStream.WriteAsync(commandLineLogMessageBytes, 0, commandLineLogMessageBytes.Length, cancellationTokenSource.Token).ConfigureAwait(false);
-
-            process.Exited += (sender, args) => OnFfMpegProcessExited(process, transcodingJob, state);
-
-            try
-            {
-                process.Start();
-            }
-            catch (Exception ex)
-            {
-                Logger.ErrorException("Error starting ffmpeg", ex);
-
-                ApiEntryPoint.Instance.OnTranscodeFailedToStart(outputPath, TranscodingJobType, state);
-
-                throw;
-            }
-
-            // MUST read both stdout and stderr asynchronously or a deadlock may occurr
-            //process.BeginOutputReadLine();
-
-            state.TranscodingJob = transcodingJob;
-
-            // Important - don't await the log task or we won't be able to kill ffmpeg when the user stops playback
-            new JobLogger(Logger).StartStreamingLog(state, process.StandardError.BaseStream, state.LogFileStream);
-
-            // Wait for the file to exist before proceeeding
-            while (!FileSystem.FileExists(state.WaitForPath ?? outputPath) && !transcodingJob.HasExited)
-            {
-                await Task.Delay(100, cancellationTokenSource.Token).ConfigureAwait(false);
-            }
-
-            if (state.IsInputVideo && transcodingJob.Type == TranscodingJobType.Progressive && !transcodingJob.HasExited)
-            {
-                await Task.Delay(1000, cancellationTokenSource.Token).ConfigureAwait(false);
-
-                if (state.ReadInputAtNativeFramerate && !transcodingJob.HasExited)
-                {
-                    await Task.Delay(1500, cancellationTokenSource.Token).ConfigureAwait(false);
-                }
-            }
-
-            if (!transcodingJob.HasExited)
-            {
-                StartThrottler(state, transcodingJob);
-            }
-
-            return transcodingJob;
-        }
-
-        private void StartThrottler(StreamState state, TranscodingJob transcodingJob)
-        {
-            if (EnableThrottling(state))
-            {
-                transcodingJob.TranscodingThrottler = state.TranscodingThrottler = new TranscodingThrottler(transcodingJob, Logger, ServerConfigurationManager, ApiEntryPoint.Instance.TimerFactory, FileSystem);
-                state.TranscodingThrottler.Start();
-            }
-        }
-
-        private bool EnableThrottling(StreamState state)
-        {
-            return false;
-            //// do not use throttling with hardware encoders
-            //return state.InputProtocol == MediaProtocol.File &&
-            //    state.RunTimeTicks.HasValue &&
-            //    state.RunTimeTicks.Value >= TimeSpan.FromMinutes(5).Ticks &&
-            //    state.IsInputVideo &&
-            //    state.VideoType == VideoType.VideoFile &&
-            //    !string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase) &&
-            //    string.Equals(GetVideoEncoder(state), "libx264", StringComparison.OrdinalIgnoreCase);
-        }
-
-        /// <summary>
-        /// Processes the exited.
-        /// </summary>
-        /// <param name="process">The process.</param>
-        /// <param name="job">The job.</param>
-        /// <param name="state">The state.</param>
-        private void OnFfMpegProcessExited(IProcess process, TranscodingJob job, StreamState state)
-        {
-            if (job != null)
-            {
-                job.HasExited = true;
-            }
-
-            Logger.Debug("Disposing stream resources");
-            state.Dispose();
-
-            try
-            {
-                Logger.Info("FFMpeg exited with code {0}", process.ExitCode);
-            }
-            catch
-            {
-                Logger.Error("FFMpeg exited with an error.");
-            }
-
-            // This causes on exited to be called twice:
-            //try
-            //{
-            //    // Dispose the process
-            //    process.Dispose();
-            //}
-            //catch (Exception ex)
-            //{
-            //    Logger.ErrorException("Error disposing ffmpeg.", ex);
-            //}
-        }
-
-        /// <summary>
-        /// Parses the parameters.
-        /// </summary>
-        /// <param name="request">The request.</param>
-        private void ParseParams(StreamRequest request)
-        {
-            var vals = request.Params.Split(';');
-
-            var videoRequest = request as VideoStreamRequest;
-
-            for (var i = 0; i < vals.Length; i++)
-            {
-                var val = vals[i];
-
-                if (string.IsNullOrWhiteSpace(val))
-                {
-                    continue;
-                }
-
-                if (i == 0)
-                {
-                    request.DeviceProfileId = val;
-                }
-                else if (i == 1)
-                {
-                    request.DeviceId = val;
-                }
-                else if (i == 2)
-                {
-                    request.MediaSourceId = val;
-                }
-                else if (i == 3)
-                {
-                    request.Static = string.Equals("true", val, StringComparison.OrdinalIgnoreCase);
-                }
-                else if (i == 4)
-                {
-                    if (videoRequest != null)
-                    {
-                        videoRequest.VideoCodec = val;
-                    }
-                }
-                else if (i == 5)
-                {
-                    request.AudioCodec = val;
-                }
-                else if (i == 6)
-                {
-                    if (videoRequest != null)
-                    {
-                        videoRequest.AudioStreamIndex = int.Parse(val, UsCulture);
-                    }
-                }
-                else if (i == 7)
-                {
-                    if (videoRequest != null)
-                    {
-                        videoRequest.SubtitleStreamIndex = int.Parse(val, UsCulture);
-                    }
-                }
-                else if (i == 8)
-                {
-                    if (videoRequest != null)
-                    {
-                        videoRequest.VideoBitRate = int.Parse(val, UsCulture);
-                    }
-                }
-                else if (i == 9)
-                {
-                    request.AudioBitRate = int.Parse(val, UsCulture);
-                }
-                else if (i == 10)
-                {
-                    request.MaxAudioChannels = int.Parse(val, UsCulture);
-                }
-                else if (i == 11)
-                {
-                    if (videoRequest != null)
-                    {
-                        videoRequest.MaxFramerate = float.Parse(val, UsCulture);
-                    }
-                }
-                else if (i == 12)
-                {
-                    if (videoRequest != null)
-                    {
-                        videoRequest.MaxWidth = int.Parse(val, UsCulture);
-                    }
-                }
-                else if (i == 13)
-                {
-                    if (videoRequest != null)
-                    {
-                        videoRequest.MaxHeight = int.Parse(val, UsCulture);
-                    }
-                }
-                else if (i == 14)
-                {
-                    request.StartTimeTicks = long.Parse(val, UsCulture);
-                }
-                else if (i == 15)
-                {
-                    if (videoRequest != null)
-                    {
-                        videoRequest.Level = val;
-                    }
-                }
-                else if (i == 16)
-                {
-                    if (videoRequest != null)
-                    {
-                        videoRequest.MaxRefFrames = int.Parse(val, UsCulture);
-                    }
-                }
-                else if (i == 17)
-                {
-                    if (videoRequest != null)
-                    {
-                        videoRequest.MaxVideoBitDepth = int.Parse(val, UsCulture);
-                    }
-                }
-                else if (i == 18)
-                {
-                    if (videoRequest != null)
-                    {
-                        videoRequest.Profile = val;
-                    }
-                }
-                else if (i == 19)
-                {
-                    // cabac no longer used
-                }
-                else if (i == 20)
-                {
-                    request.PlaySessionId = val;
-                }
-                else if (i == 21)
-                {
-                    // api_key
-                }
-                else if (i == 22)
-                {
-                    request.LiveStreamId = val;
-                }
-                else if (i == 23)
-                {
-                    // Duplicating ItemId because of MediaMonkey
-                }
-                else if (i == 24)
-                {
-                    if (videoRequest != null)
-                    {
-                        videoRequest.CopyTimestamps = string.Equals("true", val, StringComparison.OrdinalIgnoreCase);
-                    }
-                }
-                else if (i == 25)
-                {
-                    if (!string.IsNullOrWhiteSpace(val) && videoRequest != null)
-                    {
-                        SubtitleDeliveryMethod method;
-                        if (Enum.TryParse(val, out method))
-                        {
-                            videoRequest.SubtitleMethod = method;
-                        }
-                    }
-                }
-                else if (i == 26)
-                {
-                    request.TranscodingMaxAudioChannels = int.Parse(val, UsCulture);
-                }
-                else if (i == 27)
-                {
-                    if (videoRequest != null)
-                    {
-                        videoRequest.EnableSubtitlesInManifest = string.Equals("true", val, StringComparison.OrdinalIgnoreCase);
-                    }
-                }
-                else if (i == 28)
-                {
-                    request.Tag = val;
-                }
-                else if (i == 29)
-                {
-                    if (videoRequest != null)
-                    {
-                        videoRequest.RequireAvc = string.Equals("true", val, StringComparison.OrdinalIgnoreCase);
-                    }
-                }
-                else if (i == 30)
-                {
-                    request.SubtitleCodec = val;
-                }
-                else if (i == 31)
-                {
-                    if (videoRequest != null)
-                    {
-                        videoRequest.RequireNonAnamorphic = string.Equals("true", val, StringComparison.OrdinalIgnoreCase);
-                    }
-                }
-                else if (i == 32)
-                {
-                    if (videoRequest != null)
-                    {
-                        videoRequest.DeInterlace = string.Equals("true", val, StringComparison.OrdinalIgnoreCase);
-                    }
-                }
-                else if (i == 33)
-                {
-                    request.TranscodeReasons = val;
-                }
-            }
-        }
-
-        /// <summary>
-        /// Parses the dlna headers.
-        /// </summary>
-        /// <param name="request">The request.</param>
-        private void ParseDlnaHeaders(StreamRequest request)
-        {
-            if (!request.StartTimeTicks.HasValue)
-            {
-                var timeSeek = GetHeader("TimeSeekRange.dlna.org");
-
-                request.StartTimeTicks = ParseTimeSeekHeader(timeSeek);
-            }
-        }
-
-        /// <summary>
-        /// Parses the time seek header.
-        /// </summary>
-        private long? ParseTimeSeekHeader(string value)
-        {
-            if (string.IsNullOrWhiteSpace(value))
-            {
-                return null;
-            }
-
-            if (value.IndexOf("npt=", StringComparison.OrdinalIgnoreCase) != 0)
-            {
-                throw new ArgumentException("Invalid timeseek header");
-            }
-            value = value.Substring(4).Split(new[] { '-' }, 2)[0];
-
-            if (value.IndexOf(':') == -1)
-            {
-                // Parses npt times in the format of '417.33'
-                double seconds;
-                if (double.TryParse(value, NumberStyles.Any, UsCulture, out seconds))
-                {
-                    return TimeSpan.FromSeconds(seconds).Ticks;
-                }
-
-                throw new ArgumentException("Invalid timeseek header");
-            }
-
-            // Parses npt times in the format of '10:19:25.7'
-            var tokens = value.Split(new[] { ':' }, 3);
-            double secondsSum = 0;
-            var timeFactor = 3600;
-
-            foreach (var time in tokens)
-            {
-                double digit;
-                if (double.TryParse(time, NumberStyles.Any, UsCulture, out digit))
-                {
-                    secondsSum += digit * timeFactor;
-                }
-                else
-                {
-                    throw new ArgumentException("Invalid timeseek header");
-                }
-                timeFactor /= 60;
-            }
-            return TimeSpan.FromSeconds(secondsSum).Ticks;
-        }
-
-        /// <summary>
-        /// Gets the state.
-        /// </summary>
-        /// <param name="request">The request.</param>
-        /// <param name="cancellationToken">The cancellation token.</param>
-        /// <returns>StreamState.</returns>
-        protected async Task<StreamState> GetState(StreamRequest request, CancellationToken cancellationToken)
-        {
-            ParseDlnaHeaders(request);
-
-            if (!string.IsNullOrWhiteSpace(request.Params))
-            {
-                ParseParams(request);
-            }
-
-            var url = Request.PathInfo;
-
-            if (string.IsNullOrEmpty(request.AudioCodec))
-            {
-                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)
-            {
-                Request = request,
-                RequestedUrl = url,
-                UserAgent = Request.UserAgent,
-                EnableDlnaHeaders = enableDlnaHeaders
-            };
-
-            var auth = AuthorizationContext.GetAuthorizationInfo(Request);
-            if (!string.IsNullOrWhiteSpace(auth.UserId))
-            {
-                state.User = UserManager.GetUserById(auth.UserId);
-            }
-
-            //if ((Request.UserAgent ?? string.Empty).IndexOf("iphone", StringComparison.OrdinalIgnoreCase) != -1 ||
-            //    (Request.UserAgent ?? string.Empty).IndexOf("ipad", StringComparison.OrdinalIgnoreCase) != -1 ||
-            //    (Request.UserAgent ?? string.Empty).IndexOf("ipod", StringComparison.OrdinalIgnoreCase) != -1)
-            //{
-            //    state.SegmentLength = 6;
-            //}
-
-            if (state.VideoRequest != null)
-            {
-                if (!string.IsNullOrWhiteSpace(state.VideoRequest.VideoCodec))
-                {
-                    state.SupportedVideoCodecs = state.VideoRequest.VideoCodec.Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).ToList();
-                    state.VideoRequest.VideoCodec = state.SupportedVideoCodecs.FirstOrDefault();
-                }
-            }
-
-            if (!string.IsNullOrWhiteSpace(request.AudioCodec))
-            {
-                state.SupportedAudioCodecs = request.AudioCodec.Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).ToList();
-                state.Request.AudioCodec = state.SupportedAudioCodecs.FirstOrDefault(i => MediaEncoder.CanEncodeToAudioCodec(i))
-                    ?? state.SupportedAudioCodecs.FirstOrDefault();
-            }
-
-            if (!string.IsNullOrWhiteSpace(request.SubtitleCodec))
-            {
-                state.SupportedSubtitleCodecs = request.SubtitleCodec.Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).ToList();
-                state.Request.SubtitleCodec = state.SupportedSubtitleCodecs.FirstOrDefault(i => MediaEncoder.CanEncodeToSubtitleCodec(i))
-                    ?? state.SupportedSubtitleCodecs.FirstOrDefault();
-            }
-
-            var item = LibraryManager.GetItemById(request.Id);
-
-            state.IsInputVideo = string.Equals(item.MediaType, MediaType.Video, StringComparison.OrdinalIgnoreCase);
-
-            //var primaryImage = item.GetImageInfo(ImageType.Primary, 0) ??
-            //             item.Parents.Select(i => i.GetImageInfo(ImageType.Primary, 0)).FirstOrDefault(i => i != null);
-            //if (primaryImage != null)
-            //{
-            //    state.AlbumCoverPath = primaryImage.Path;
-            //}
-
-            MediaSourceInfo mediaSource = null;
-            if (string.IsNullOrWhiteSpace(request.LiveStreamId))
-            {
-                TranscodingJob currentJob = !string.IsNullOrWhiteSpace(request.PlaySessionId) ?
-                    ApiEntryPoint.Instance.GetTranscodingJob(request.PlaySessionId)
-                    : null;
-
-                if (currentJob != null)
-                {
-                    mediaSource = currentJob.MediaSource;
-                }
-
-                if (mediaSource == null)
-                {
-                    var mediaSources = (await MediaSourceManager.GetPlayackMediaSources(request.Id, null, false, new[] { MediaType.Audio, MediaType.Video }, cancellationToken).ConfigureAwait(false)).ToList();
-
-                    mediaSource = string.IsNullOrEmpty(request.MediaSourceId)
-                       ? mediaSources.First()
-                       : mediaSources.FirstOrDefault(i => string.Equals(i.Id, request.MediaSourceId));
-
-                    if (mediaSource == null && string.Equals(request.Id, request.MediaSourceId, StringComparison.OrdinalIgnoreCase))
-                    {
-                        mediaSource = mediaSources.First();
-                    }
-                }
-            }
-            else
-            {
-                var liveStreamInfo = await MediaSourceManager.GetLiveStreamWithDirectStreamProvider(request.LiveStreamId, cancellationToken).ConfigureAwait(false);
-                mediaSource = liveStreamInfo.Item1;
-                state.DirectStreamProvider = liveStreamInfo.Item2;
-            }
-
-            var videoRequest = request as VideoStreamRequest;
-
-            EncodingHelper.AttachMediaSourceInfo(state, mediaSource, url);
-
-            var container = Path.GetExtension(state.RequestedUrl);
-
-            if (string.IsNullOrEmpty(container))
-            {
-                container = request.Container;
-            }
-
-            if (string.IsNullOrEmpty(container))
-            {
-                container = request.Static ?
-                    StreamBuilder.NormalizeMediaSourceFormatIntoSingleContainer(state.InputContainer, null, DlnaProfileType.Audio) :
-                    GetOutputFileExtension(state);
-            }
-
-            state.OutputContainer = (container ?? string.Empty).TrimStart('.');
-
-            state.OutputAudioBitrate = EncodingHelper.GetAudioBitrateParam(state.Request, state.AudioStream);
-
-            state.OutputAudioCodec = state.Request.AudioCodec;
-
-            state.OutputAudioChannels = EncodingHelper.GetNumAudioChannelsParam(state.Request, state.AudioStream, state.OutputAudioCodec);
-
-            if (videoRequest != null)
-            {
-                state.OutputVideoCodec = state.VideoRequest.VideoCodec;
-                state.OutputVideoBitrate = EncodingHelper.GetVideoBitrateParamValue(state.VideoRequest, state.VideoStream, state.OutputVideoCodec);
-
-                if (videoRequest != null)
-                {
-                    EncodingHelper.TryStreamCopy(state);
-                }
-
-                if (state.OutputVideoBitrate.HasValue && !string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase))
-                {
-                    var resolution = ResolutionNormalizer.Normalize(
-                        state.VideoStream == null ? (int?)null : state.VideoStream.BitRate,
-                        state.OutputVideoBitrate.Value,
-                        state.VideoStream == null ? null : state.VideoStream.Codec,
-                        state.OutputVideoCodec,
-                        videoRequest.MaxWidth,
-                        videoRequest.MaxHeight);
-
-                    videoRequest.MaxWidth = resolution.MaxWidth;
-                    videoRequest.MaxHeight = resolution.MaxHeight;
-                }
-
-                ApplyDeviceProfileSettings(state);
-            }
-            else
-            {
-                ApplyDeviceProfileSettings(state);
-            }
-
-            var ext = string.IsNullOrWhiteSpace(state.OutputContainer)
-                ? GetOutputFileExtension(state)
-                : ("." + state.OutputContainer);
-
-            var encodingOptions = ApiEntryPoint.Instance.GetEncodingOptions();
-
-            state.OutputFilePath = GetOutputFilePath(state, encodingOptions, ext);
-
-            return state;
-        }
-
-        private void ApplyDeviceProfileSettings(StreamState state)
-        {
-            var headers = Request.Headers.ToDictionary();
-
-            if (!string.IsNullOrWhiteSpace(state.Request.DeviceProfileId))
-            {
-                state.DeviceProfile = DlnaManager.GetProfile(state.Request.DeviceProfileId);
-            }
-            else
-            {
-                if (!string.IsNullOrWhiteSpace(state.Request.DeviceId))
-                {
-                    var caps = DeviceManager.GetCapabilities(state.Request.DeviceId);
-
-                    if (caps != null)
-                    {
-                        state.DeviceProfile = caps.DeviceProfile;
-                    }
-                    else
-                    {
-                        state.DeviceProfile = DlnaManager.GetProfile(headers);
-                    }
-                }
-            }
-
-            var profile = state.DeviceProfile;
-
-            if (profile == null)
-            {
-                // Don't use settings from the default profile. 
-                // Only use a specific profile if it was requested.
-                return;
-            }
-
-            var audioCodec = state.ActualOutputAudioCodec;
-            var videoCodec = state.ActualOutputVideoCodec;
-
-            var mediaProfile = state.VideoRequest == null ?
-                profile.GetAudioMediaProfile(state.OutputContainer, audioCodec, state.OutputAudioChannels, state.OutputAudioBitrate, state.OutputAudioSampleRate, state.OutputAudioBitDepth) :
-                profile.GetVideoMediaProfile(state.OutputContainer,
-                audioCodec,
-                videoCodec,
-                state.OutputWidth,
-                state.OutputHeight,
-                state.TargetVideoBitDepth,
-                state.OutputVideoBitrate,
-                state.TargetVideoProfile,
-                state.TargetVideoLevel,
-                state.TargetFramerate,
-                state.TargetPacketLength,
-                state.TargetTimestamp,
-                state.IsTargetAnamorphic,
-                state.IsTargetInterlaced,
-                state.TargetRefFrames,
-                state.TargetVideoStreamCount,
-                state.TargetAudioStreamCount,
-                state.TargetVideoCodecTag,
-                state.IsTargetAVC);
-
-            if (mediaProfile != null)
-            {
-                state.MimeType = mediaProfile.MimeType;
-            }
-
-            if (!state.Request.Static)
-            {
-                var transcodingProfile = state.VideoRequest == null ?
-                    profile.GetAudioTranscodingProfile(state.OutputContainer, audioCodec) :
-                    profile.GetVideoTranscodingProfile(state.OutputContainer, audioCodec, videoCodec);
-
-                if (transcodingProfile != null)
-                {
-                    state.EstimateContentLength = transcodingProfile.EstimateContentLength;
-                    state.EnableMpegtsM2TsMode = transcodingProfile.EnableMpegtsM2TsMode;
-                    state.TranscodeSeekInfo = transcodingProfile.TranscodeSeekInfo;
-
-                    if (state.VideoRequest != null)
-                    {
-                        state.VideoRequest.CopyTimestamps = transcodingProfile.CopyTimestamps;
-                        state.VideoRequest.EnableSubtitlesInManifest = transcodingProfile.EnableSubtitlesInManifest;
-                    }
-                }
-            }
-        }
-
-        /// <summary>
-        /// Adds the dlna headers.
-        /// </summary>
-        /// <param name="state">The state.</param>
-        /// <param name="responseHeaders">The response headers.</param>
-        /// <param name="isStaticallyStreamed">if set to <c>true</c> [is statically streamed].</param>
-        /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
-        protected void AddDlnaHeaders(StreamState state, IDictionary<string, string> responseHeaders, bool isStaticallyStreamed)
-        {
-            if (!state.EnableDlnaHeaders)
-            {
-                return;
-            }
-
-            var profile = state.DeviceProfile;
-
-            var transferMode = GetHeader("transferMode.dlna.org");
-            responseHeaders["transferMode.dlna.org"] = string.IsNullOrEmpty(transferMode) ? "Streaming" : transferMode;
-            responseHeaders["realTimeInfo.dlna.org"] = "DLNA.ORG_TLAG=*";
-
-            if (string.Equals(GetHeader("getMediaInfo.sec"), "1", StringComparison.OrdinalIgnoreCase))
-            {
-                if (state.RunTimeTicks.HasValue)
-                {
-                    var ms = TimeSpan.FromTicks(state.RunTimeTicks.Value).TotalMilliseconds;
-                    responseHeaders["MediaInfo.sec"] = string.Format("SEC_Duration={0};", Convert.ToInt32(ms).ToString(CultureInfo.InvariantCulture));
-                }
-            }
-
-            if (state.RunTimeTicks.HasValue && !isStaticallyStreamed && profile != null)
-            {
-                AddTimeSeekResponseHeaders(state, responseHeaders);
-            }
-
-            if (profile == null)
-            {
-                profile = DlnaManager.GetDefaultProfile();
-            }
-
-            var audioCodec = state.ActualOutputAudioCodec;
-
-            if (state.VideoRequest == null)
-            {
-                responseHeaders["contentFeatures.dlna.org"] = new ContentFeatureBuilder(profile)
-                    .BuildAudioHeader(
-                    state.OutputContainer,
-                    audioCodec,
-                    state.OutputAudioBitrate,
-                    state.OutputAudioSampleRate,
-                    state.OutputAudioChannels,
-                    state.OutputAudioBitDepth,
-                    isStaticallyStreamed,
-                    state.RunTimeTicks,
-                    state.TranscodeSeekInfo
-                    );
-            }
-            else
-            {
-                var videoCodec = state.ActualOutputVideoCodec;
-
-                responseHeaders["contentFeatures.dlna.org"] = new ContentFeatureBuilder(profile)
-                    .BuildVideoHeader(
-                    state.OutputContainer,
-                    videoCodec,
-                    audioCodec,
-                    state.OutputWidth,
-                    state.OutputHeight,
-                    state.TargetVideoBitDepth,
-                    state.OutputVideoBitrate,
-                    state.TargetTimestamp,
-                    isStaticallyStreamed,
-                    state.RunTimeTicks,
-                    state.TargetVideoProfile,
-                    state.TargetVideoLevel,
-                    state.TargetFramerate,
-                    state.TargetPacketLength,
-                    state.TranscodeSeekInfo,
-                    state.IsTargetAnamorphic,
-                    state.IsTargetInterlaced,
-                    state.TargetRefFrames,
-                    state.TargetVideoStreamCount,
-                    state.TargetAudioStreamCount,
-                    state.TargetVideoCodecTag,
-                    state.IsTargetAVC
-
-                    ).FirstOrDefault() ?? string.Empty;
-            }
-
-            foreach (var item in responseHeaders)
-            {
-                Request.Response.AddHeader(item.Key, item.Value);
-            }
-        }
-
-        private void AddTimeSeekResponseHeaders(StreamState state, IDictionary<string, string> responseHeaders)
-        {
-            var runtimeSeconds = TimeSpan.FromTicks(state.RunTimeTicks.Value).TotalSeconds.ToString(UsCulture);
-            var startSeconds = TimeSpan.FromTicks(state.Request.StartTimeTicks ?? 0).TotalSeconds.ToString(UsCulture);
-
-            responseHeaders["TimeSeekRange.dlna.org"] = string.Format("npt={0}-{1}/{1}", startSeconds, runtimeSeconds);
-            responseHeaders["X-AvailableSeekRange"] = string.Format("1 npt={0}-{1}", startSeconds, runtimeSeconds);
-        }
-    }
-}

Vissa filer visades inte eftersom för många filer har ändrats