Ver código fonte

Merge pull request #2815 from MediaBrowser/beta

Beta
Luke 7 anos atrás
pai
commit
dc578f3742
100 arquivos alterados com 1289 adições e 3326 exclusões
  1. 1 2
      Emby.Common.Implementations/Emby.Common.Implementations.csproj
  2. 12 2
      Emby.Common.Implementations/Logging/NlogManager.cs
  3. 0 4
      Emby.Common.Implementations/Net/UdpSocket.cs
  4. 1 1
      Emby.Common.Implementations/Networking/NetworkManager.cs
  5. 4 2
      Emby.Common.Implementations/ScheduledTasks/ScheduledTaskWorker.cs
  6. 2 2
      Emby.Common.Implementations/packages.config
  7. 6 2
      Emby.Dlna/ContentDirectory/ContentDirectory.cs
  8. 378 77
      Emby.Dlna/ContentDirectory/ControlHandler.cs
  9. 34 2
      Emby.Dlna/Didl/DidlBuilder.cs
  10. 3 7
      Emby.Dlna/DlnaManager.cs
  11. 22 23
      Emby.Dlna/PlayTo/Device.cs
  12. 1 1
      Emby.Dlna/PlayTo/PlayToController.cs
  13. 2 1
      Emby.Dlna/Profiles/DefaultProfile.cs
  14. 1 1
      Emby.Dlna/Server/DescriptionXmlBuilder.cs
  15. 16 12
      Emby.Dlna/Service/BaseControlHandler.cs
  16. 22 12
      Emby.Drawing/ImageProcessor.cs
  17. 1 1
      Emby.Photos/PhotoProvider.cs
  18. 0 176
      Emby.Server.Core/Emby.Server.Core.csproj
  19. 0 34
      Emby.Server.Core/Properties/AssemblyInfo.cs
  20. 0 11
      Emby.Server.Core/app.config
  21. 0 6
      Emby.Server.Core/packages.config
  22. 2 1
      Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs
  23. 5 4
      Emby.Server.Implementations/Activity/ActivityRepository.cs
  24. 109 159
      Emby.Server.Implementations/ApplicationHost.cs
  25. 1 1
      Emby.Server.Implementations/ApplicationPathHelper.cs
  26. 4 4
      Emby.Server.Implementations/Channels/ChannelImageProvider.cs
  27. 22 19
      Emby.Server.Implementations/Channels/ChannelManager.cs
  28. 3 3
      Emby.Server.Implementations/Collections/CollectionImageProvider.cs
  29. 6 3
      Emby.Server.Implementations/Collections/CollectionManager.cs
  30. 3 2
      Emby.Server.Implementations/Configuration/ServerConfigurationManager.cs
  31. 0 0
      Emby.Server.Implementations/Cryptography/ASN1.cs
  32. 0 0
      Emby.Server.Implementations/Cryptography/ASN1Convert.cs
  33. 0 0
      Emby.Server.Implementations/Cryptography/BitConverterLE.cs
  34. 0 0
      Emby.Server.Implementations/Cryptography/CertificateGenerator.cs
  35. 0 0
      Emby.Server.Implementations/Cryptography/CryptoConvert.cs
  36. 0 0
      Emby.Server.Implementations/Cryptography/PKCS1.cs
  37. 0 0
      Emby.Server.Implementations/Cryptography/PKCS12.cs
  38. 0 0
      Emby.Server.Implementations/Cryptography/PKCS7.cs
  39. 0 0
      Emby.Server.Implementations/Cryptography/PKCS8.cs
  40. 0 0
      Emby.Server.Implementations/Cryptography/PfxGenerator.cs
  41. 0 0
      Emby.Server.Implementations/Cryptography/X501Name.cs
  42. 0 0
      Emby.Server.Implementations/Cryptography/X509Builder.cs
  43. 0 0
      Emby.Server.Implementations/Cryptography/X509Certificate.cs
  44. 0 0
      Emby.Server.Implementations/Cryptography/X509CertificateBuilder.cs
  45. 0 0
      Emby.Server.Implementations/Cryptography/X509CertificateCollection.cs
  46. 0 0
      Emby.Server.Implementations/Cryptography/X509Extension.cs
  47. 0 0
      Emby.Server.Implementations/Cryptography/X509Extensions.cs
  48. 0 0
      Emby.Server.Implementations/Cryptography/X520Attributes.cs
  49. 10 17
      Emby.Server.Implementations/Data/BaseSqliteRepository.cs
  50. 2 45
      Emby.Server.Implementations/Data/CleanDatabaseScheduledTask.cs
  51. 0 284
      Emby.Server.Implementations/Data/SqliteFileOrganizationRepository.cs
  52. 205 229
      Emby.Server.Implementations/Data/SqliteItemRepository.cs
  53. 27 68
      Emby.Server.Implementations/Dto/DtoService.cs
  54. 87 11
      Emby.Server.Implementations/Emby.Server.Implementations.csproj
  55. 4 3
      Emby.Server.Implementations/EntryPoints/ExternalPortForwarding.cs
  56. 2 1
      Emby.Server.Implementations/EntryPoints/UsageEntryPoint.cs
  57. 0 813
      Emby.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs
  58. 0 33
      Emby.Server.Implementations/FileOrganization/Extensions.cs
  59. 0 80
      Emby.Server.Implementations/FileOrganization/FileOrganizationNotifier.cs
  60. 0 283
      Emby.Server.Implementations/FileOrganization/FileOrganizationService.cs
  61. 0 81
      Emby.Server.Implementations/FileOrganization/NameUtils.cs
  62. 0 101
      Emby.Server.Implementations/FileOrganization/OrganizerScheduledTask.cs
  63. 0 236
      Emby.Server.Implementations/FileOrganization/TvFolderOrganizer.cs
  64. 6 11
      Emby.Server.Implementations/HttpServer/HttpListenerHost.cs
  65. 48 140
      Emby.Server.Implementations/HttpServer/HttpResultFactory.cs
  66. 2 1
      Emby.Server.Implementations/HttpServer/LoggerUtils.cs
  67. 2 1
      Emby.Server.Implementations/HttpServer/SocketSharp/HttpUtility.cs
  68. 1 3
      Emby.Server.Implementations/HttpServerFactory.cs
  69. 0 92
      Emby.Server.Implementations/IO/FileRefresher.cs
  70. 1 2
      Emby.Server.Implementations/IO/LibraryMonitor.cs
  71. 1 1
      Emby.Server.Implementations/IO/MemoryStreamProvider.cs
  72. 17 21
      Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs
  73. 14 36
      Emby.Server.Implementations/Library/LibraryManager.cs
  74. 4 3
      Emby.Server.Implementations/Library/LocalTrailerPostScanTask.cs
  75. 7 8
      Emby.Server.Implementations/Library/MediaSourceManager.cs
  76. 11 11
      Emby.Server.Implementations/Library/MusicManager.cs
  77. 12 8
      Emby.Server.Implementations/Library/ResolverHelper.cs
  78. 5 7
      Emby.Server.Implementations/Library/Resolvers/BaseVideoResolver.cs
  79. 9 11
      Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs
  80. 1 1
      Emby.Server.Implementations/Library/Resolvers/PhotoResolver.cs
  81. 5 4
      Emby.Server.Implementations/Library/Resolvers/TV/EpisodeResolver.cs
  82. 6 6
      Emby.Server.Implementations/Library/Resolvers/VideoResolver.cs
  83. 3 2
      Emby.Server.Implementations/Library/SearchEngine.cs
  84. 1 1
      Emby.Server.Implementations/Library/UserManager.cs
  85. 39 3
      Emby.Server.Implementations/Library/UserViewManager.cs
  86. 5 12
      Emby.Server.Implementations/Library/Validators/PeopleValidator.cs
  87. 3 3
      Emby.Server.Implementations/LiveTv/ChannelImageProvider.cs
  88. 2 7
      Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
  89. 6 3
      Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs
  90. 4 4
      Emby.Server.Implementations/LiveTv/LiveTvDtoService.cs
  91. 44 35
      Emby.Server.Implementations/LiveTv/LiveTvManager.cs
  92. 3 3
      Emby.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs
  93. 3 3
      Emby.Server.Implementations/LiveTv/RecordingImageProvider.cs
  94. 12 8
      Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs
  95. 7 11
      Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs
  96. 1 1
      Emby.Server.Implementations/Localization/Core/en-US.json
  97. 3 3
      Emby.Server.Implementations/Localization/LocalizationManager.cs
  98. 1 0
      Emby.Server.Implementations/Localization/Ratings/es.txt
  99. 1 0
      Emby.Server.Implementations/Localization/Ratings/ro.txt
  100. 1 0
      Emby.Server.Implementations/Localization/Ratings/us.txt

+ 1 - 2
Emby.Common.Implementations/Emby.Common.Implementations.csproj

@@ -32,8 +32,7 @@
   </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">
     <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>
       <HintPath>..\packages\ServiceStack.Text.4.5.8\lib\net45\ServiceStack.Text.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";

+ 0 - 4
Emby.Common.Implementations/Net/UdpSocket.cs

@@ -37,8 +37,6 @@ namespace Emby.Common.Implementations.Net
         private TaskCompletionSource<SocketReceiveResult> _currentReceiveTaskCompletionSource;
         private TaskCompletionSource<SocketReceiveResult> _currentReceiveTaskCompletionSource;
         private TaskCompletionSource<int> _currentSendTaskCompletionSource;
         private TaskCompletionSource<int> _currentSendTaskCompletionSource;
 
 
-        private readonly SemaphoreSlim _sendLock = new SemaphoreSlim(1, 1);
-
         public UdpSocket(Socket socket, int localPort, IPAddress ip)
         public UdpSocket(Socket socket, int localPort, IPAddress ip)
         {
         {
             if (socket == null) throw new ArgumentNullException("socket");
             if (socket == null) throw new ArgumentNullException("socket");
@@ -234,8 +232,6 @@ namespace Emby.Common.Implementations.Net
                 if (socket != null)
                 if (socket != null)
                     socket.Dispose();
                     socket.Dispose();
 
 
-                _sendLock.Dispose();
-
                 var tcs = _currentReceiveTaskCompletionSource;
                 var tcs = _currentReceiveTaskCompletionSource;
                 if (tcs != null)
                 if (tcs != null)
                 {
                 {

+ 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.8" 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>

+ 6 - 2
Emby.Dlna/ContentDirectory/ContentDirectory.cs

@@ -12,6 +12,7 @@ using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
 using System.Linq;
 using System.Linq;
 using MediaBrowser.Controller.MediaEncoding;
 using MediaBrowser.Controller.MediaEncoding;
+using MediaBrowser.Controller.TV;
 using MediaBrowser.Model.Globalization;
 using MediaBrowser.Model.Globalization;
 using MediaBrowser.Model.Xml;
 using MediaBrowser.Model.Xml;
 
 
@@ -31,6 +32,7 @@ namespace Emby.Dlna.ContentDirectory
         private readonly IUserViewManager _userViewManager;
         private readonly IUserViewManager _userViewManager;
         private readonly Func<IMediaEncoder> _mediaEncoder;
         private readonly Func<IMediaEncoder> _mediaEncoder;
         protected readonly IXmlReaderSettingsFactory XmlReaderSettingsFactory;
         protected readonly IXmlReaderSettingsFactory XmlReaderSettingsFactory;
+        private readonly ITVSeriesManager _tvSeriesManager;
 
 
         public ContentDirectory(IDlnaManager dlna,
         public ContentDirectory(IDlnaManager dlna,
             IUserDataManager userDataManager,
             IUserDataManager userDataManager,
@@ -39,7 +41,7 @@ namespace Emby.Dlna.ContentDirectory
             IServerConfigurationManager config,
             IServerConfigurationManager config,
             IUserManager userManager,
             IUserManager userManager,
             ILogger logger,
             ILogger logger,
-            IHttpClient httpClient, ILocalizationManager localization, IChannelManager channelManager, IMediaSourceManager mediaSourceManager, IUserViewManager userViewManager, Func<IMediaEncoder> mediaEncoder, IXmlReaderSettingsFactory xmlReaderSettingsFactory)
+            IHttpClient httpClient, ILocalizationManager localization, IChannelManager channelManager, IMediaSourceManager mediaSourceManager, IUserViewManager userViewManager, Func<IMediaEncoder> mediaEncoder, IXmlReaderSettingsFactory xmlReaderSettingsFactory, ITVSeriesManager tvSeriesManager)
             : base(logger, httpClient)
             : base(logger, httpClient)
         {
         {
             _dlna = dlna;
             _dlna = dlna;
@@ -54,6 +56,7 @@ namespace Emby.Dlna.ContentDirectory
             _userViewManager = userViewManager;
             _userViewManager = userViewManager;
             _mediaEncoder = mediaEncoder;
             _mediaEncoder = mediaEncoder;
             XmlReaderSettingsFactory = xmlReaderSettingsFactory;
             XmlReaderSettingsFactory = xmlReaderSettingsFactory;
+            _tvSeriesManager = tvSeriesManager;
         }
         }
 
 
         private int SystemUpdateId
         private int SystemUpdateId
@@ -97,7 +100,8 @@ namespace Emby.Dlna.ContentDirectory
                 _mediaSourceManager,
                 _mediaSourceManager,
                 _userViewManager,
                 _userViewManager,
                 _mediaEncoder(),
                 _mediaEncoder(),
-                XmlReaderSettingsFactory)
+                XmlReaderSettingsFactory,
+                _tvSeriesManager)
                 .ProcessControlRequest(request);
                 .ProcessControlRequest(request);
         }
         }
 
 

+ 378 - 77
Emby.Dlna/ContentDirectory/ControlHandler.cs

@@ -27,8 +27,10 @@ using MediaBrowser.Controller.Dto;
 using MediaBrowser.Controller.Entities.Audio;
 using MediaBrowser.Controller.Entities.Audio;
 using MediaBrowser.Controller.MediaEncoding;
 using MediaBrowser.Controller.MediaEncoding;
 using MediaBrowser.Controller.Playlists;
 using MediaBrowser.Controller.Playlists;
+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
 {
 {
@@ -40,6 +42,7 @@ namespace Emby.Dlna.ContentDirectory
         private readonly IServerConfigurationManager _config;
         private readonly IServerConfigurationManager _config;
         private readonly User _user;
         private readonly User _user;
         private readonly IUserViewManager _userViewManager;
         private readonly IUserViewManager _userViewManager;
+        private readonly ITVSeriesManager _tvSeriesManager;
 
 
         private const string NS_DC = "http://purl.org/dc/elements/1.1/";
         private const string NS_DC = "http://purl.org/dc/elements/1.1/";
         private const string NS_DIDL = "urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/";
         private const string NS_DIDL = "urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/";
@@ -53,7 +56,7 @@ namespace Emby.Dlna.ContentDirectory
 
 
         private readonly DeviceProfile _profile;
         private readonly DeviceProfile _profile;
 
 
-        public ControlHandler(ILogger logger, ILibraryManager libraryManager, DeviceProfile profile, string serverAddress, string accessToken, IImageProcessor imageProcessor, IUserDataManager userDataManager, User user, int systemUpdateId, IServerConfigurationManager config, ILocalizationManager localization, IChannelManager channelManager, IMediaSourceManager mediaSourceManager, IUserViewManager userViewManager, IMediaEncoder mediaEncoder, IXmlReaderSettingsFactory xmlReaderSettingsFactory)
+        public ControlHandler(ILogger logger, ILibraryManager libraryManager, DeviceProfile profile, string serverAddress, string accessToken, IImageProcessor imageProcessor, IUserDataManager userDataManager, User user, int systemUpdateId, IServerConfigurationManager config, ILocalizationManager localization, IChannelManager channelManager, IMediaSourceManager mediaSourceManager, IUserViewManager userViewManager, IMediaEncoder mediaEncoder, IXmlReaderSettingsFactory xmlReaderSettingsFactory, ITVSeriesManager tvSeriesManager)
             : base(config, logger, xmlReaderSettingsFactory)
             : base(config, logger, xmlReaderSettingsFactory)
         {
         {
             _libraryManager = libraryManager;
             _libraryManager = libraryManager;
@@ -62,6 +65,7 @@ namespace Emby.Dlna.ContentDirectory
             _systemUpdateId = systemUpdateId;
             _systemUpdateId = systemUpdateId;
             _channelManager = channelManager;
             _channelManager = channelManager;
             _userViewManager = userViewManager;
             _userViewManager = userViewManager;
+            _tvSeriesManager = tvSeriesManager;
             _profile = profile;
             _profile = profile;
             _config = config;
             _config = config;
 
 
@@ -454,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()
             });
             });
         }
         }
@@ -488,6 +492,14 @@ namespace Emby.Dlna.ContentDirectory
             {
             {
                 return GetMusicFolders(item, user, stubType, sort, startIndex, limit);
                 return GetMusicFolders(item, user, stubType, sort, startIndex, limit);
             }
             }
+            if (collectionFolder != null && string.Equals(CollectionType.Movies, collectionFolder.CollectionType, StringComparison.OrdinalIgnoreCase))
+            {
+                return GetMovieFolders(item, user, stubType, sort, startIndex, limit);
+            }
+            if (collectionFolder != null && string.Equals(CollectionType.TvShows, collectionFolder.CollectionType, StringComparison.OrdinalIgnoreCase))
+            {
+                return GetTvFolders(item, user, stubType, sort, startIndex, limit);
+            }
 
 
             if (stubType.HasValue)
             if (stubType.HasValue)
             {
             {
@@ -497,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);
@@ -524,8 +536,8 @@ namespace Emby.Dlna.ContentDirectory
                 Limit = limit,
                 Limit = limit,
                 StartIndex = startIndex,
                 StartIndex = startIndex,
                 User = user,
                 User = user,
-                IsMissing = false,
-                PresetViews = new[] { CollectionType.Movies, CollectionType.TvShows },
+                IsVirtualItem = false,
+                PresetViews = new string[] { },
                 ExcludeItemTypes = new[] { typeof(Game).Name, typeof(Book).Name },
                 ExcludeItemTypes = new[] { typeof(Game).Name, typeof(Book).Name },
                 IsPlaceHolder = false,
                 IsPlaceHolder = false,
                 DtoOptions = GetDtoOptions()
                 DtoOptions = GetDtoOptions()
@@ -651,11 +663,236 @@ namespace Emby.Dlna.ContentDirectory
 
 
             return new QueryResult<ServerItem>
             return new QueryResult<ServerItem>
             {
             {
-                Items = list.ToArray(),
+                Items = list.ToArray(list.Count),
+                TotalRecordCount = list.Count
+            };
+        }
+
+        private QueryResult<ServerItem> GetMovieFolders(BaseItem item, User user, StubType? stubType, SortCriteria sort, int? startIndex, int? limit)
+        {
+            var query = new InternalItemsQuery(user)
+            {
+                StartIndex = startIndex,
+                Limit = limit
+            };
+            SetSorting(query, sort, false);
+
+            if (stubType.HasValue && stubType.Value == StubType.ContinueWatching)
+            {
+                return GetMovieContinueWatching(item, user, query);
+            }
+
+            if (stubType.HasValue && stubType.Value == StubType.Latest)
+            {
+                return GetMovieLatest(item, user, query);
+            }
+
+            if (stubType.HasValue && stubType.Value == StubType.Movies)
+            {
+                return GetMovieMovies(item, user, query);
+            }
+
+            if (stubType.HasValue && stubType.Value == StubType.Collections)
+            {
+                return GetMovieCollections(item, user, query);
+            }
+
+            if (stubType.HasValue && stubType.Value == StubType.Favorites)
+            {
+                return GetMovieFavorites(item, user, query);
+            }
+
+            if (stubType.HasValue && stubType.Value == StubType.Genres)
+            {
+                return GetGenres(item, user, query);
+            }
+
+            var list = new List<ServerItem>();
+
+            list.Add(new ServerItem(item)
+            {
+                StubType = StubType.ContinueWatching
+            });
+
+            list.Add(new ServerItem(item)
+            {
+                StubType = StubType.Latest
+            });
+
+            list.Add(new ServerItem(item)
+            {
+                StubType = StubType.Movies
+            });
+
+            list.Add(new ServerItem(item)
+            {
+                StubType = StubType.Collections
+            });
+
+            list.Add(new ServerItem(item)
+            {
+                StubType = StubType.Favorites
+            });
+
+            list.Add(new ServerItem(item)
+            {
+                StubType = StubType.Genres
+            });
+
+            return new QueryResult<ServerItem>
+            {
+                Items = list.ToArray(list.Count),
+                TotalRecordCount = list.Count
+            };
+        }
+
+        private QueryResult<ServerItem> GetTvFolders(BaseItem item, User user, StubType? stubType, SortCriteria sort, int? startIndex, int? limit)
+        {
+            var query = new InternalItemsQuery(user)
+            {
+                StartIndex = startIndex,
+                Limit = limit
+            };
+            SetSorting(query, sort, false);
+
+            if (stubType.HasValue && stubType.Value == StubType.ContinueWatching)
+            {
+                return GetMovieContinueWatching(item, user, query);
+            }
+
+            if (stubType.HasValue && stubType.Value == StubType.NextUp)
+            {
+                return GetNextUp(item, user, query);
+            }
+
+            if (stubType.HasValue && stubType.Value == StubType.Latest)
+            {
+                return GetTvLatest(item, user, query);
+            }
+
+            if (stubType.HasValue && stubType.Value == StubType.Series)
+            {
+                return GetSeries(item, user, query);
+            }
+
+            if (stubType.HasValue && stubType.Value == StubType.FavoriteSeries)
+            {
+                return GetFavoriteSeries(item, user, query);
+            }
+
+            if (stubType.HasValue && stubType.Value == StubType.FavoriteEpisodes)
+            {
+                return GetFavoriteEpisodes(item, user, query);
+            }
+
+            if (stubType.HasValue && stubType.Value == StubType.Genres)
+            {
+                return GetGenres(item, user, query);
+            }
+
+            var list = new List<ServerItem>();
+
+            list.Add(new ServerItem(item)
+            {
+                StubType = StubType.ContinueWatching
+            });
+
+            list.Add(new ServerItem(item)
+            {
+                StubType = StubType.NextUp
+            });
+
+            list.Add(new ServerItem(item)
+            {
+                StubType = StubType.Latest
+            });
+
+            list.Add(new ServerItem(item)
+            {
+                StubType = StubType.Series
+            });
+
+            list.Add(new ServerItem(item)
+            {
+                StubType = StubType.FavoriteSeries
+            });
+
+            list.Add(new ServerItem(item)
+            {
+                StubType = StubType.FavoriteEpisodes
+            });
+
+            list.Add(new ServerItem(item)
+            {
+                StubType = StubType.Genres
+            });
+
+            return new QueryResult<ServerItem>
+            {
+                Items = list.ToArray(list.Count),
                 TotalRecordCount = list.Count
                 TotalRecordCount = list.Count
             };
             };
         }
         }
 
 
+        private QueryResult<ServerItem> GetMovieContinueWatching(BaseItem parent, User user, InternalItemsQuery query)
+        {
+            query.Recursive = true;
+            query.Parent = parent;
+            query.SetUser(user);
+
+            query.OrderBy = new List<Tuple<string, SortOrder>>
+            {
+                new Tuple<string, SortOrder> (ItemSortBy.DatePlayed, SortOrder.Descending),
+                new Tuple<string, SortOrder> (ItemSortBy.SortName, SortOrder.Ascending)
+            };
+
+            query.IsResumable = true;
+            query.Limit = 10;
+
+            var result = _libraryManager.GetItemsResult(query);
+
+            return ToResult(result);
+        }
+
+        private QueryResult<ServerItem> GetSeries(BaseItem parent, User user, InternalItemsQuery query)
+        {
+            query.Recursive = true;
+            query.Parent = parent;
+            query.SetUser(user);
+
+            query.IncludeItemTypes = new[] { typeof(Series).Name };
+
+            var result = _libraryManager.GetItemsResult(query);
+
+            return ToResult(result);
+        }
+
+        private QueryResult<ServerItem> GetMovieMovies(BaseItem parent, User user, InternalItemsQuery query)
+        {
+            query.Recursive = true;
+            query.Parent = parent;
+            query.SetUser(user);
+
+            query.IncludeItemTypes = new[] { typeof(Movie).Name };
+
+            var result = _libraryManager.GetItemsResult(query);
+
+            return ToResult(result);
+        }
+
+        private QueryResult<ServerItem> GetMovieCollections(BaseItem parent, User user, InternalItemsQuery query)
+        {
+            query.Recursive = true;
+            //query.Parent = parent;
+            query.SetUser(user);
+
+            query.IncludeItemTypes = new[] { typeof(BoxSet).Name };
+
+            var result = _libraryManager.GetItemsResult(query);
+
+            return ToResult(result);
+        }
+
         private QueryResult<ServerItem> GetMusicAlbums(BaseItem parent, User user, InternalItemsQuery query)
         private QueryResult<ServerItem> GetMusicAlbums(BaseItem parent, User user, InternalItemsQuery query)
         {
         {
             query.Recursive = true;
             query.Recursive = true;
@@ -695,6 +932,45 @@ namespace Emby.Dlna.ContentDirectory
             return ToResult(result);
             return ToResult(result);
         }
         }
 
 
+        private QueryResult<ServerItem> GetFavoriteSeries(BaseItem parent, User user, InternalItemsQuery query)
+        {
+            query.Recursive = true;
+            query.Parent = parent;
+            query.SetUser(user);
+            query.IsFavorite = true;
+            query.IncludeItemTypes = new[] { typeof(Series).Name };
+
+            var result = _libraryManager.GetItemsResult(query);
+
+            return ToResult(result);
+        }
+
+        private QueryResult<ServerItem> GetFavoriteEpisodes(BaseItem parent, User user, InternalItemsQuery query)
+        {
+            query.Recursive = true;
+            query.Parent = parent;
+            query.SetUser(user);
+            query.IsFavorite = true;
+            query.IncludeItemTypes = new[] { typeof(Episode).Name };
+
+            var result = _libraryManager.GetItemsResult(query);
+
+            return ToResult(result);
+        }
+
+        private QueryResult<ServerItem> GetMovieFavorites(BaseItem parent, User user, InternalItemsQuery query)
+        {
+            query.Recursive = true;
+            query.Parent = parent;
+            query.SetUser(user);
+            query.IsFavorite = true;
+            query.IncludeItemTypes = new[] { typeof(Movie).Name };
+
+            var result = _libraryManager.GetItemsResult(query);
+
+            return ToResult(result);
+        }
+
         private QueryResult<ServerItem> GetFavoriteAlbums(BaseItem parent, User user, InternalItemsQuery query)
         private QueryResult<ServerItem> GetFavoriteAlbums(BaseItem parent, User user, InternalItemsQuery query)
         {
         {
             query.Recursive = true;
             query.Recursive = true;
@@ -708,6 +984,24 @@ namespace Emby.Dlna.ContentDirectory
             return ToResult(result);
             return ToResult(result);
         }
         }
 
 
+        private QueryResult<ServerItem> GetGenres(BaseItem parent, User user, InternalItemsQuery query)
+        {
+            var genresResult = _libraryManager.GetGenres(new InternalItemsQuery(user)
+            {
+                AncestorIds = new[] { parent.Id.ToString("N") },
+                StartIndex = query.StartIndex,
+                Limit = query.Limit
+            });
+
+            var result = new QueryResult<BaseItem>
+            {
+                TotalRecordCount = genresResult.TotalRecordCount,
+                Items = genresResult.Items.Select(i => i.Item1).ToArray(genresResult.Items.Length)
+            };
+
+            return ToResult(result);
+        }
+
         private QueryResult<ServerItem> GetMusicGenres(BaseItem parent, User user, InternalItemsQuery query)
         private QueryResult<ServerItem> GetMusicGenres(BaseItem parent, User user, InternalItemsQuery query)
         {
         {
             var genresResult = _libraryManager.GetMusicGenres(new InternalItemsQuery(user)
             var genresResult = _libraryManager.GetMusicGenres(new InternalItemsQuery(user)
@@ -720,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);
@@ -738,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);
@@ -756,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);
@@ -775,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);
@@ -810,6 +1104,55 @@ namespace Emby.Dlna.ContentDirectory
             return ToResult(items);
             return ToResult(items);
         }
         }
 
 
+        private QueryResult<ServerItem> GetNextUp(BaseItem parent, User user, InternalItemsQuery query)
+        {
+            query.SortBy = new string[] { };
+
+            var result = _tvSeriesManager.GetNextUp(new NextUpQuery
+            {
+                Limit = query.Limit,
+                StartIndex = query.StartIndex,
+                UserId = query.User.Id.ToString("N")
+
+            }, new List<Folder> { (Folder)parent }, query.DtoOptions);
+
+            return ToResult(result);
+        }
+
+        private QueryResult<ServerItem> GetTvLatest(BaseItem parent, User user, InternalItemsQuery query)
+        {
+            query.SortBy = new string[] { };
+
+            var items = _userViewManager.GetLatestItems(new LatestItemsQuery
+            {
+                UserId = user.Id.ToString("N"),
+                Limit = 50,
+                IncludeItemTypes = new[] { typeof(Episode).Name },
+                ParentId = parent == null ? null : parent.Id.ToString("N"),
+                GroupItems = false
+
+            }, query.DtoOptions).Select(i => i.Item1 ?? i.Item2.FirstOrDefault()).Where(i => i != null).ToList();
+
+            return ToResult(items);
+        }
+
+        private QueryResult<ServerItem> GetMovieLatest(BaseItem parent, User user, InternalItemsQuery query)
+        {
+            query.SortBy = new string[] { };
+
+            var items = _userViewManager.GetLatestItems(new LatestItemsQuery
+            {
+                UserId = user.Id.ToString("N"),
+                Limit = 50,
+                IncludeItemTypes = new[] { typeof(Movie).Name },
+                ParentId = parent == null ? null : parent.Id.ToString("N"),
+                GroupItems = true
+
+            }, query.DtoOptions).Select(i => i.Item1 ?? i.Item2.FirstOrDefault()).Where(i => i != null).ToList();
+
+            return ToResult(items);
+        }
+
         private QueryResult<ServerItem> GetMusicArtistItems(BaseItem item, Guid? parentId, User user, SortCriteria sort, int? startIndex, int? limit)
         private QueryResult<ServerItem> GetMusicArtistItems(BaseItem item, Guid? parentId, User user, SortCriteria sort, int? startIndex, int? limit)
         {
         {
             var query = new InternalItemsQuery(user)
             var query = new InternalItemsQuery(user)
@@ -854,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>
             {
             {
@@ -868,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>
             {
             {
@@ -885,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;
         }
         }
 
 
@@ -901,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>
             {
             {
@@ -942,65 +1284,16 @@ namespace Emby.Dlna.ContentDirectory
                 id = parts[23];
                 id = parts[23];
             }
             }
 
 
-            if (id.StartsWith("folder_", StringComparison.OrdinalIgnoreCase))
-            {
-                stubType = StubType.Folder;
-                id = id.Split(new[] { '_' }, 2)[1];
-            }
-            else if (id.StartsWith("people_", StringComparison.OrdinalIgnoreCase))
-            {
-                stubType = StubType.People;
-                id = id.Split(new[] { '_' }, 2)[1];
-            }
-            else if (id.StartsWith("latest_", StringComparison.OrdinalIgnoreCase))
-            {
-                stubType = StubType.Latest;
-                id = id.Split(new[] { '_' }, 2)[1];
-            }
-            else if (id.StartsWith("playlists_", StringComparison.OrdinalIgnoreCase))
-            {
-                stubType = StubType.Playlists;
-                id = id.Split(new[] { '_' }, 2)[1];
-            }
-            else if (id.StartsWith("Albums_", StringComparison.OrdinalIgnoreCase))
-            {
-                stubType = StubType.Albums;
-                id = id.Split(new[] { '_' }, 2)[1];
-            }
-            else if (id.StartsWith("AlbumArtists_", StringComparison.OrdinalIgnoreCase))
-            {
-                stubType = StubType.AlbumArtists;
-                id = id.Split(new[] { '_' }, 2)[1];
-            }
-            else if (id.StartsWith("Artists_", StringComparison.OrdinalIgnoreCase))
-            {
-                stubType = StubType.Artists;
-                id = id.Split(new[] { '_' }, 2)[1];
-            }
-            else if (id.StartsWith("Genres_", StringComparison.OrdinalIgnoreCase))
-            {
-                stubType = StubType.Genres;
-                id = id.Split(new[] { '_' }, 2)[1];
-            }
-            else if (id.StartsWith("Songs_", StringComparison.OrdinalIgnoreCase))
+            var enumNames = Enum.GetNames(typeof(StubType));
+            foreach (var name in enumNames)
             {
             {
-                stubType = StubType.Songs;
-                id = id.Split(new[] { '_' }, 2)[1];
-            }
-            else if (id.StartsWith("FavoriteAlbums_", StringComparison.OrdinalIgnoreCase))
-            {
-                stubType = StubType.FavoriteAlbums;
-                id = id.Split(new[] { '_' }, 2)[1];
-            }
-            else if (id.StartsWith("FavoriteArtists_", StringComparison.OrdinalIgnoreCase))
-            {
-                stubType = StubType.FavoriteArtists;
-                id = id.Split(new[] { '_' }, 2)[1];
-            }
-            else if (id.StartsWith("FavoriteSongs_", StringComparison.OrdinalIgnoreCase))
-            {
-                stubType = StubType.FavoriteSongs;
-                id = id.Split(new[] { '_' }, 2)[1];
+                if (id.StartsWith(name + "_", StringComparison.OrdinalIgnoreCase))
+                {
+                    stubType = (StubType)Enum.Parse(typeof(StubType), name, true);
+                    id = id.Split(new[] { '_' }, 2)[1];
+
+                    break;
+                }
             }
             }
 
 
             if (Guid.TryParse(id, out itemId))
             if (Guid.TryParse(id, out itemId))
@@ -1048,6 +1341,14 @@ namespace Emby.Dlna.ContentDirectory
         Genres = 8,
         Genres = 8,
         FavoriteSongs = 9,
         FavoriteSongs = 9,
         FavoriteArtists = 10,
         FavoriteArtists = 10,
-        FavoriteAlbums = 11
+        FavoriteAlbums = 11,
+        ContinueWatching = 12,
+        Movies = 13,
+        Collections = 14,
+        Favorites = 15,
+        NextUp = 16,
+        Series = 17,
+        FavoriteSeries = 18,
+        FavoriteEpisodes = 19
     }
     }
 }
 }

+ 34 - 2
Emby.Dlna/Didl/DidlBuilder.cs

@@ -193,7 +193,7 @@ namespace Emby.Dlna.Didl
         {
         {
             if (streamInfo == null)
             if (streamInfo == null)
             {
             {
-                var sources = _mediaSourceManager.GetStaticMediaSources(video, true, _user).ToList();
+                var sources = _mediaSourceManager.GetStaticMediaSources(video, true, _user);
 
 
                 streamInfo = new StreamBuilder(_mediaEncoder, GetStreamBuilderLogger(options)).BuildVideoItem(new VideoOptions
                 streamInfo = new StreamBuilder(_mediaEncoder, GetStreamBuilderLogger(options)).BuildVideoItem(new VideoOptions
                 {
                 {
@@ -439,6 +439,38 @@ namespace Emby.Dlna.Didl
             {
             {
                 return _localization.GetLocalizedString("ViewTypeMusicFavoriteSongs");
                 return _localization.GetLocalizedString("ViewTypeMusicFavoriteSongs");
             }
             }
+            if (itemStubType.HasValue && itemStubType.Value == StubType.ContinueWatching)
+            {
+                return _localization.GetLocalizedString("ViewTypeMovieResume");
+            }
+            if (itemStubType.HasValue && itemStubType.Value == StubType.Movies)
+            {
+                return _localization.GetLocalizedString("ViewTypeMovieMovies");
+            }
+            if (itemStubType.HasValue && itemStubType.Value == StubType.Collections)
+            {
+                return _localization.GetLocalizedString("ViewTypeMovieCollections");
+            }
+            if (itemStubType.HasValue && itemStubType.Value == StubType.Favorites)
+            {
+                return _localization.GetLocalizedString("ViewTypeMovieFavorites");
+            }
+            if (itemStubType.HasValue && itemStubType.Value == StubType.NextUp)
+            {
+                return _localization.GetLocalizedString("ViewTypeTvNextUp");
+            }
+            if (itemStubType.HasValue && itemStubType.Value == StubType.FavoriteSeries)
+            {
+                return _localization.GetLocalizedString("ViewTypeTvFavoriteSeries");
+            }
+            if (itemStubType.HasValue && itemStubType.Value == StubType.FavoriteEpisodes)
+            {
+                return _localization.GetLocalizedString("ViewTypeTvFavoriteEpisodes");
+            }
+            if (itemStubType.HasValue && itemStubType.Value == StubType.Series)
+            {
+                return _localization.GetLocalizedString("ViewTypeTvShowSeries");
+            }
 
 
             var episode = item as Episode;
             var episode = item as Episode;
             var season = context as Season;
             var season = context as Season;
@@ -476,7 +508,7 @@ namespace Emby.Dlna.Didl
 
 
             if (streamInfo == null)
             if (streamInfo == null)
             {
             {
-                var sources = _mediaSourceManager.GetStaticMediaSources(audio, true, _user).ToList();
+                var sources = _mediaSourceManager.GetStaticMediaSources(audio, true, _user);
 
 
                 streamInfo = new StreamBuilder(_mediaEncoder, GetStreamBuilderLogger(options)).BuildAudioItem(new AudioOptions
                 streamInfo = new StreamBuilder(_mediaEncoder, GetStreamBuilderLogger(options)).BuildAudioItem(new AudioOptions
                 {
                 {

+ 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;

+ 22 - 23
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
 {
 {
@@ -112,7 +113,7 @@ namespace Emby.Dlna.PlayTo
 
 
         private int GetInactiveTimerIntervalMs()
         private int GetInactiveTimerIntervalMs()
         {
         {
-            return 30000;
+            return Timeout.Infinite;
         }
         }
 
 
         public void Start()
         public void Start()
@@ -160,18 +161,15 @@ namespace Emby.Dlna.PlayTo
             if (_disposed)
             if (_disposed)
                 return;
                 return;
 
 
-            if (!_timerActive)
+            lock (_timerLock)
             {
             {
-                lock (_timerLock)
+                if (!_timerActive)
                 {
                 {
-                    if (!_timerActive)
-                    {
-                        _logger.Debug("RestartTimer");
-                        _timer.Change(10, GetPlaybackTimerIntervalMs());
-                    }
-
-                    _timerActive = true;
+                    _logger.Debug("RestartTimer");
+                    _timer.Change(10, GetPlaybackTimerIntervalMs());
                 }
                 }
+
+                _timerActive = true;
             }
             }
         }
         }
 
 
@@ -183,23 +181,20 @@ namespace Emby.Dlna.PlayTo
             if (_disposed)
             if (_disposed)
                 return;
                 return;
 
 
-            if (_timerActive)
+            lock (_timerLock)
             {
             {
-                lock (_timerLock)
+                if (_timerActive)
                 {
                 {
-                    if (_timerActive)
-                    {
-                        _logger.Debug("RestartTimerInactive");
-                        var interval = GetInactiveTimerIntervalMs();
+                    _logger.Debug("RestartTimerInactive");
+                    var interval = GetInactiveTimerIntervalMs();
 
 
-                        if (_timer != null)
-                        {
-                            _timer.Change(interval, interval);
-                        }
+                    if (_timer != null)
+                    {
+                        _timer.Change(interval, interval);
                     }
                     }
-
-                    _timerActive = false;
                 }
                 }
+
+                _timerActive = false;
             }
             }
         }
         }
 
 
@@ -492,6 +487,10 @@ namespace Emby.Dlna.PlayTo
                         RestartTimer();
                         RestartTimer();
                     }
                     }
                 }
                 }
+                else
+                {
+                    RestartTimerInactive();
+                }
             }
             }
             catch (HttpException ex)
             catch (HttpException ex)
             {
             {
@@ -890,7 +889,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)

+ 1 - 1
Emby.Dlna/PlayTo/PlayToController.cs

@@ -503,7 +503,7 @@ namespace Emby.Dlna.PlayTo
 
 
             var hasMediaSources = item as IHasMediaSources;
             var hasMediaSources = item as IHasMediaSources;
             var mediaSources = hasMediaSources != null
             var mediaSources = hasMediaSources != null
-                ? (_mediaSourceManager.GetStaticMediaSources(hasMediaSources, true, user)).ToList()
+                ? (_mediaSourceManager.GetStaticMediaSources(hasMediaSources, true, user))
                 : new List<MediaSourceInfo>();
                 : new List<MediaSourceInfo>();
 
 
             var playlistItem = GetPlaylistItem(item, mediaSources, profile, _session.DeviceId, mediaSourceId, audioStreamIndex, subtitleStreamIndex);
             var playlistItem = GetPlaylistItem(item, mediaSources, profile, _session.DeviceId, mediaSourceId, audioStreamIndex, subtitleStreamIndex);

+ 2 - 1
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
 {
 {
@@ -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);
         }
         }
     }
     }
 }
 }

+ 22 - 12
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
 {
 {
@@ -171,6 +169,13 @@ namespace Emby.Drawing
             return _imageEncoder.SupportedOutputFormats;
             return _imageEncoder.SupportedOutputFormats;
         }
         }
 
 
+        private static readonly string[] TransparentImageTypes = new string[] { ".png", ".webp" };
+        private bool SupportsTransparency(string path)
+        {
+            return TransparentImageTypes.Contains(Path.GetExtension(path) ?? string.Empty);
+            ;
+        }
+
         public async Task<Tuple<string, string, DateTime>> ProcessImage(ImageProcessingOptions options)
         public async Task<Tuple<string, string, DateTime>> ProcessImage(ImageProcessingOptions options)
         {
         {
             if (options == null)
             if (options == null)
@@ -179,7 +184,7 @@ namespace Emby.Drawing
             }
             }
 
 
             var originalImage = options.Image;
             var originalImage = options.Image;
-            IHasImages item = options.Item;
+            IHasMetadata item = options.Item;
 
 
             if (!originalImage.IsLocalFile)
             if (!originalImage.IsLocalFile)
             {
             {
@@ -260,6 +265,11 @@ namespace Emby.Drawing
                         item = _libraryManager().GetItemById(options.ItemId);
                         item = _libraryManager().GetItemById(options.ItemId);
                     }
                     }
 
 
+                    if (options.CropWhiteSpace && !SupportsTransparency(originalImagePath))
+                    {
+                        options.CropWhiteSpace = false;
+                    }
+
                     var resultPath = _imageEncoder.EncodeImage(originalImagePath, dateModified, tmpPath, autoOrient, orientation, quality, options, outputFormat);
                     var resultPath = _imageEncoder.EncodeImage(originalImagePath, dateModified, tmpPath, autoOrient, orientation, quality, options, outputFormat);
 
 
                     if (string.Equals(resultPath, originalImagePath, StringComparison.OrdinalIgnoreCase))
                     if (string.Equals(resultPath, originalImagePath, StringComparison.OrdinalIgnoreCase))
@@ -594,7 +604,7 @@ namespace Emby.Drawing
         /// <param name="image">The image.</param>
         /// <param name="image">The image.</param>
         /// <returns>Guid.</returns>
         /// <returns>Guid.</returns>
         /// <exception cref="System.ArgumentNullException">item</exception>
         /// <exception cref="System.ArgumentNullException">item</exception>
-        public string GetImageCacheTag(IHasImages item, ItemImageInfo image)
+        public string GetImageCacheTag(IHasMetadata item, ItemImageInfo image)
         {
         {
             if (item == null)
             if (item == null)
             {
             {
@@ -619,7 +629,7 @@ namespace Emby.Drawing
         /// <param name="imageEnhancers">The image enhancers.</param>
         /// <param name="imageEnhancers">The image enhancers.</param>
         /// <returns>Guid.</returns>
         /// <returns>Guid.</returns>
         /// <exception cref="System.ArgumentNullException">item</exception>
         /// <exception cref="System.ArgumentNullException">item</exception>
-        public string GetImageCacheTag(IHasImages item, ItemImageInfo image, List<IImageEnhancer> imageEnhancers)
+        public string GetImageCacheTag(IHasMetadata item, ItemImageInfo image, List<IImageEnhancer> imageEnhancers)
         {
         {
             if (item == null)
             if (item == null)
             {
             {
@@ -650,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>
@@ -660,7 +670,7 @@ namespace Emby.Drawing
         /// <param name="imageType">Type of the image.</param>
         /// <param name="imageType">Type of the image.</param>
         /// <param name="imageIndex">Index of the image.</param>
         /// <param name="imageIndex">Index of the image.</param>
         /// <returns>Task{System.String}.</returns>
         /// <returns>Task{System.String}.</returns>
-        public async Task<string> GetEnhancedImage(IHasImages item, ImageType imageType, int imageIndex)
+        public async Task<string> GetEnhancedImage(IHasMetadata item, ImageType imageType, int imageIndex)
         {
         {
             var enhancers = GetSupportedEnhancers(item, imageType).ToList();
             var enhancers = GetSupportedEnhancers(item, imageType).ToList();
 
 
@@ -672,7 +682,7 @@ namespace Emby.Drawing
         }
         }
 
 
         private async Task<Tuple<string, DateTime>> GetEnhancedImage(ItemImageInfo image,
         private async Task<Tuple<string, DateTime>> GetEnhancedImage(ItemImageInfo image,
-            IHasImages item,
+            IHasMetadata item,
             int imageIndex,
             int imageIndex,
             List<IImageEnhancer> enhancers)
             List<IImageEnhancer> enhancers)
         {
         {
@@ -717,7 +727,7 @@ namespace Emby.Drawing
         /// item
         /// item
         /// </exception>
         /// </exception>
         private async Task<string> GetEnhancedImageInternal(string originalImagePath,
         private async Task<string> GetEnhancedImageInternal(string originalImagePath,
-            IHasImages item,
+            IHasMetadata item,
             ImageType imageType,
             ImageType imageType,
             int imageIndex,
             int imageIndex,
             IEnumerable<IImageEnhancer> supportedEnhancers,
             IEnumerable<IImageEnhancer> supportedEnhancers,
@@ -771,7 +781,7 @@ namespace Emby.Drawing
         /// <param name="imageType">Type of the image.</param>
         /// <param name="imageType">Type of the image.</param>
         /// <param name="imageIndex">Index of the image.</param>
         /// <param name="imageIndex">Index of the image.</param>
         /// <returns>Task{EnhancedImage}.</returns>
         /// <returns>Task{EnhancedImage}.</returns>
-        private async Task ExecuteImageEnhancers(IEnumerable<IImageEnhancer> imageEnhancers, string inputPath, string outputPath, IHasImages item, ImageType imageType, int imageIndex)
+        private async Task ExecuteImageEnhancers(IEnumerable<IImageEnhancer> imageEnhancers, string inputPath, string outputPath, IHasMetadata item, ImageType imageType, int imageIndex)
         {
         {
             // Run the enhancers sequentially in order of priority
             // Run the enhancers sequentially in order of priority
             foreach (var enhancer in imageEnhancers)
             foreach (var enhancer in imageEnhancers)
@@ -856,7 +866,7 @@ namespace Emby.Drawing
             _logger.Info("Completed creation of image collage and saved to {0}", options.OutputPath);
             _logger.Info("Completed creation of image collage and saved to {0}", options.OutputPath);
         }
         }
 
 
-        public IEnumerable<IImageEnhancer> GetSupportedEnhancers(IHasImages item, ImageType imageType)
+        public IEnumerable<IImageEnhancer> GetSupportedEnhancers(IHasMetadata item, ImageType imageType)
         {
         {
             return ImageEnhancers.Where(i =>
             return ImageEnhancers.Where(i =>
             {
             {

+ 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);

+ 109 - 159
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,7 +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.FileOrganization;
+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;
@@ -35,103 +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.FileOrganization;
-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
@@ -216,7 +203,6 @@ namespace Emby.Server.Core
         internal IDisplayPreferencesRepository DisplayPreferencesRepository { get; set; }
         internal IDisplayPreferencesRepository DisplayPreferencesRepository { get; set; }
         internal IItemRepository ItemRepository { get; set; }
         internal IItemRepository ItemRepository { get; set; }
         private INotificationsRepository NotificationsRepository { get; set; }
         private INotificationsRepository NotificationsRepository { get; set; }
-        private IFileOrganizationRepository FileOrganizationRepository { get; set; }
 
 
         private INotificationManager NotificationManager { get; set; }
         private INotificationManager NotificationManager { get; set; }
         private ISubtitleManager SubtitleManager { get; set; }
         private ISubtitleManager SubtitleManager { get; set; }
@@ -226,7 +212,6 @@ namespace Emby.Server.Core
         internal IUserViewManager UserViewManager { get; set; }
         internal IUserViewManager UserViewManager { get; set; }
 
 
         private IAuthenticationRepository AuthenticationRepository { get; set; }
         private IAuthenticationRepository AuthenticationRepository { get; set; }
-        private ISyncRepository SyncRepository { get; set; }
         private ITVSeriesManager TVSeriesManager { get; set; }
         private ITVSeriesManager TVSeriesManager { get; set; }
         private ICollectionManager CollectionManager { get; set; }
         private ICollectionManager CollectionManager { get; set; }
         private IMediaSourceManager MediaSourceManager { get; set; }
         private IMediaSourceManager MediaSourceManager { get; set; }
@@ -360,13 +345,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);
 
 
@@ -413,7 +391,7 @@ namespace Emby.Server.Core
                 {
                 {
                     Logger.ErrorException("Error in {0}", ex, name);
                     Logger.ErrorException("Error in {0}", ex, name);
                 }
                 }
-                Logger.Info("Entry point completed: {0}. Duration: {1} seconds", name, (DateTime.UtcNow - now).TotalSeconds.ToString(CultureInfo.InvariantCulture));
+                Logger.Info("Entry point completed: {0}. Duration: {1} seconds", name, (DateTime.UtcNow - now).TotalSeconds.ToString(CultureInfo.InvariantCulture), "ImageInfos");
             }
             }
             Logger.Info("All entry points have started");
             Logger.Info("All entry points have started");
 
 
@@ -434,41 +412,41 @@ namespace Emby.Server.Core
 
 
             var result = new JsonSerializer(FileSystemManager, LogManager.GetLogger("JsonSerializer"));
             var result = new JsonSerializer(FileSystemManager, LogManager.GetLogger("JsonSerializer"));
 
 
-            ServiceStack.Text.JsConfig<LiveTvProgram>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "Keywords", "ExtraType" };
-            ServiceStack.Text.JsConfig<LiveTvChannel>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "Keywords", "ExtraType" };
-            ServiceStack.Text.JsConfig<LiveTvVideoRecording>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "Keywords", "ExtraType" };
-            ServiceStack.Text.JsConfig<LiveTvAudioRecording>.ExcludePropertyNames = new[] { "Artists", "AlbumArtists", "ChannelMediaSources", "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "Keywords", "ExtraType" };
-            ServiceStack.Text.JsConfig<Series>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "Keywords", "ExtraType" };
-            ServiceStack.Text.JsConfig<Audio>.ExcludePropertyNames = new[] { "Artists", "AlbumArtists", "ChannelMediaSources", "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "Keywords", "ExtraType" };
-            ServiceStack.Text.JsConfig<MusicAlbum>.ExcludePropertyNames = new[] { "Artists", "AlbumArtists", "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "Keywords", "ExtraType" };
-            ServiceStack.Text.JsConfig<MusicArtist>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "Keywords", "ExtraType" };
-            ServiceStack.Text.JsConfig<MusicGenre>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "Keywords", "ExtraType" };
-            ServiceStack.Text.JsConfig<MusicVideo>.ExcludePropertyNames = new[] { "Artists", "AlbumArtists", "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "Keywords", "ExtraType" };
-            ServiceStack.Text.JsConfig<Movie>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "Keywords", "ExtraType" };
-            ServiceStack.Text.JsConfig<Playlist>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "Keywords", "ExtraType" };
-            ServiceStack.Text.JsConfig<AudioPodcast>.ExcludePropertyNames = new[] { "Artists", "AlbumArtists", "ChannelMediaSources", "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "Keywords", "ExtraType" };
-            ServiceStack.Text.JsConfig<AudioBook>.ExcludePropertyNames = new[] { "Artists", "AlbumArtists", "ChannelMediaSources", "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "Keywords", "ExtraType" };
-            ServiceStack.Text.JsConfig<Trailer>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "Keywords", "ExtraType" };
-            ServiceStack.Text.JsConfig<BoxSet>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "Keywords", "ExtraType" };
-            ServiceStack.Text.JsConfig<Episode>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "Keywords", "ExtraType" };
-            ServiceStack.Text.JsConfig<Season>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "Keywords", "ExtraType" };
-            ServiceStack.Text.JsConfig<Book>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "Keywords", "ExtraType" };
-            ServiceStack.Text.JsConfig<CollectionFolder>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "Keywords", "ExtraType" };
-            ServiceStack.Text.JsConfig<Folder>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "Keywords", "ExtraType" };
-            ServiceStack.Text.JsConfig<Game>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "Keywords", "ExtraType" };
-            ServiceStack.Text.JsConfig<GameGenre>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "Keywords", "ExtraType" };
-            ServiceStack.Text.JsConfig<GameSystem>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "Keywords", "ExtraType" };
-            ServiceStack.Text.JsConfig<Genre>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "Keywords", "ExtraType" };
-            ServiceStack.Text.JsConfig<Person>.ExcludePropertyNames = new[] { "PlaceOfBirth", "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "Keywords", "ExtraType" };
-            ServiceStack.Text.JsConfig<Photo>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "Keywords", "ExtraType" };
-            ServiceStack.Text.JsConfig<PhotoAlbum>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "Keywords", "ExtraType" };
-            ServiceStack.Text.JsConfig<Studio>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "Keywords", "ExtraType" };
-            ServiceStack.Text.JsConfig<UserRootFolder>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "Keywords", "ExtraType" };
-            ServiceStack.Text.JsConfig<UserView>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "Keywords", "ExtraType" };
-            ServiceStack.Text.JsConfig<Video>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "Keywords", "ExtraType" };
-            ServiceStack.Text.JsConfig<Year>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "Keywords", "ExtraType" };
-            ServiceStack.Text.JsConfig<Channel>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "Keywords", "ExtraType" };
-            ServiceStack.Text.JsConfig<AggregateFolder>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "Keywords", "ExtraType" };
+            ServiceStack.Text.JsConfig<LiveTvProgram>.ExcludePropertyNames = new[] { "ProviderIds" };
+            ServiceStack.Text.JsConfig<LiveTvChannel>.ExcludePropertyNames = new[] { "ProviderIds" };
+            ServiceStack.Text.JsConfig<LiveTvVideoRecording>.ExcludePropertyNames = new[] { "ProviderIds" };
+            ServiceStack.Text.JsConfig<LiveTvAudioRecording>.ExcludePropertyNames = new[] { "ProviderIds" };
+            ServiceStack.Text.JsConfig<Series>.ExcludePropertyNames = new[] { "ProviderIds" };
+            ServiceStack.Text.JsConfig<Audio>.ExcludePropertyNames = new[] { "ProviderIds" };
+            ServiceStack.Text.JsConfig<MusicAlbum>.ExcludePropertyNames = new[] { "ProviderIds" };
+            ServiceStack.Text.JsConfig<MusicArtist>.ExcludePropertyNames = new[] { "ProviderIds" };
+            ServiceStack.Text.JsConfig<MusicGenre>.ExcludePropertyNames = new[] { "ProviderIds" };
+            ServiceStack.Text.JsConfig<MusicVideo>.ExcludePropertyNames = new[] { "ProviderIds" };
+            ServiceStack.Text.JsConfig<Movie>.ExcludePropertyNames = new[] { "ProviderIds" };
+            ServiceStack.Text.JsConfig<Playlist>.ExcludePropertyNames = new[] { "ProviderIds" };
+            ServiceStack.Text.JsConfig<AudioPodcast>.ExcludePropertyNames = new[] { "ProviderIds" };
+            ServiceStack.Text.JsConfig<AudioBook>.ExcludePropertyNames = new[] { "ProviderIds" };
+            ServiceStack.Text.JsConfig<Trailer>.ExcludePropertyNames = new[] { "ProviderIds" };
+            ServiceStack.Text.JsConfig<BoxSet>.ExcludePropertyNames = new[] { "ProviderIds" };
+            ServiceStack.Text.JsConfig<Episode>.ExcludePropertyNames = new[] { "ProviderIds" };
+            ServiceStack.Text.JsConfig<Season>.ExcludePropertyNames = new[] { "ProviderIds" };
+            ServiceStack.Text.JsConfig<Book>.ExcludePropertyNames = new[] { "ProviderIds" };
+            ServiceStack.Text.JsConfig<CollectionFolder>.ExcludePropertyNames = new[] { "ProviderIds" };
+            ServiceStack.Text.JsConfig<Folder>.ExcludePropertyNames = new[] { "ProviderIds" };
+            ServiceStack.Text.JsConfig<Game>.ExcludePropertyNames = new[] { "ProviderIds" };
+            ServiceStack.Text.JsConfig<GameGenre>.ExcludePropertyNames = new[] { "ProviderIds" };
+            ServiceStack.Text.JsConfig<GameSystem>.ExcludePropertyNames = new[] { "ProviderIds" };
+            ServiceStack.Text.JsConfig<Genre>.ExcludePropertyNames = new[] { "ProviderIds" };
+            ServiceStack.Text.JsConfig<Person>.ExcludePropertyNames = new[] { "ProviderIds" };
+            ServiceStack.Text.JsConfig<Photo>.ExcludePropertyNames = new[] { "ProviderIds" };
+            ServiceStack.Text.JsConfig<PhotoAlbum>.ExcludePropertyNames = new[] { "ProviderIds" };
+            ServiceStack.Text.JsConfig<Studio>.ExcludePropertyNames = new[] { "ProviderIds" };
+            ServiceStack.Text.JsConfig<UserRootFolder>.ExcludePropertyNames = new[] { "ProviderIds" };
+            ServiceStack.Text.JsConfig<UserView>.ExcludePropertyNames = new[] { "ProviderIds" };
+            ServiceStack.Text.JsConfig<Video>.ExcludePropertyNames = new[] { "ProviderIds" };
+            ServiceStack.Text.JsConfig<Year>.ExcludePropertyNames = new[] { "ProviderIds" };
+            ServiceStack.Text.JsConfig<Channel>.ExcludePropertyNames = new[] { "ProviderIds" };
+            ServiceStack.Text.JsConfig<AggregateFolder>.ExcludePropertyNames = new[] { "ProviderIds" };
 
 
             return result;
             return result;
         }
         }
@@ -583,9 +561,6 @@ namespace Emby.Server.Core
             ItemRepository = itemRepo;
             ItemRepository = itemRepo;
             RegisterSingleInstance(ItemRepository);
             RegisterSingleInstance(ItemRepository);
 
 
-            FileOrganizationRepository = GetFileOrganizationRepository();
-            RegisterSingleInstance(FileOrganizationRepository);
-
             AuthenticationRepository = GetAuthenticationRepository();
             AuthenticationRepository = GetAuthenticationRepository();
             RegisterSingleInstance(AuthenticationRepository);
             RegisterSingleInstance(AuthenticationRepository);
 
 
@@ -614,7 +589,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>();
@@ -644,9 +619,6 @@ namespace Emby.Server.Core
             var newsService = new Emby.Server.Implementations.News.NewsService(ApplicationPaths, JsonSerializer);
             var newsService = new Emby.Server.Implementations.News.NewsService(ApplicationPaths, JsonSerializer);
             RegisterSingleInstance<INewsService>(newsService);
             RegisterSingleInstance<INewsService>(newsService);
 
 
-            var fileOrganizationService = new FileOrganizationService(TaskManager, FileOrganizationRepository, LogManager.GetLogger("FileOrganizationService"), LibraryMonitor, LibraryManager, ServerConfigurationManager, FileSystemManager, ProviderManager);
-            RegisterSingleInstance<IFileOrganizationService>(fileOrganizationService);
-
             progress.Report(15);
             progress.Report(15);
 
 
             ChannelManager = new ChannelManager(UserManager, DtoService, LibraryManager, LogManager.GetLogger("ChannelManager"), ServerConfigurationManager, FileSystemManager, UserDataManager, JsonSerializer, LocalizationManager, HttpClient, ProviderManager);
             ChannelManager = new ChannelManager(UserManager, DtoService, LibraryManager, LogManager.GetLogger("ChannelManager"), ServerConfigurationManager, FileSystemManager, UserDataManager, JsonSerializer, LocalizationManager, HttpClient, ProviderManager);
@@ -676,7 +648,7 @@ namespace Emby.Server.Core
             UserViewManager = new UserViewManager(LibraryManager, LocalizationManager, UserManager, ChannelManager, LiveTvManager, ServerConfigurationManager);
             UserViewManager = new UserViewManager(LibraryManager, LocalizationManager, UserManager, ChannelManager, LiveTvManager, ServerConfigurationManager);
             RegisterSingleInstance(UserViewManager);
             RegisterSingleInstance(UserViewManager);
 
 
-            var contentDirectory = new ContentDirectory(dlnaManager, UserDataManager, ImageProcessor, LibraryManager, ServerConfigurationManager, UserManager, LogManager.GetLogger("UpnpContentDirectory"), HttpClient, LocalizationManager, ChannelManager, MediaSourceManager, UserViewManager, () => MediaEncoder, new XmlReaderSettingsFactory());
+            var contentDirectory = new ContentDirectory(dlnaManager, UserDataManager, ImageProcessor, LibraryManager, ServerConfigurationManager, UserManager, LogManager.GetLogger("UpnpContentDirectory"), HttpClient, LocalizationManager, ChannelManager, MediaSourceManager, UserViewManager, () => MediaEncoder, new XmlReaderSettingsFactory(), TVSeriesManager);
             RegisterSingleInstance<IContentDirectory>(contentDirectory);
             RegisterSingleInstance<IContentDirectory>(contentDirectory);
 
 
             var mediaRegistrar = new MediaReceiverRegistrar(LogManager.GetLogger("MediaReceiverRegistrar"), HttpClient, ServerConfigurationManager, new XmlReaderSettingsFactory());
             var mediaRegistrar = new MediaReceiverRegistrar(LogManager.GetLogger("MediaReceiverRegistrar"), HttpClient, ServerConfigurationManager, new XmlReaderSettingsFactory());
@@ -893,7 +865,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,
@@ -932,19 +904,6 @@ namespace Emby.Server.Core
             return repo;
             return repo;
         }
         }
 
 
-        /// <summary>
-        /// Gets the file organization repository.
-        /// </summary>
-        /// <returns>Task{IUserRepository}.</returns>
-        private IFileOrganizationRepository GetFileOrganizationRepository()
-        {
-            var repo = new SqliteFileOrganizationRepository(LogManager.GetLogger("SqliteFileOrganizationRepository"), ServerConfigurationManager.ApplicationPaths);
-
-            repo.Initialize();
-
-            return repo;
-        }
-
         private IAuthenticationRepository GetAuthenticationRepository()
         private IAuthenticationRepository GetAuthenticationRepository()
         {
         {
             var repo = new AuthenticationRepository(LogManager.GetLogger("AuthenticationRepository"), ServerConfigurationManager.ApplicationPaths);
             var repo = new AuthenticationRepository(LogManager.GetLogger("AuthenticationRepository"), ServerConfigurationManager.ApplicationPaths);
@@ -1002,8 +961,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;
         }
         }
@@ -1276,7 +1233,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)));
@@ -1289,10 +1246,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();
@@ -1636,14 +1590,10 @@ namespace Emby.Server.Core
         /// <returns>Task{CheckForUpdateResult}.</returns>
         /// <returns>Task{CheckForUpdateResult}.</returns>
         public override async Task<CheckForUpdateResult> CheckForApplicationUpdate(CancellationToken cancellationToken, IProgress<double> progress)
         public override async Task<CheckForUpdateResult> CheckForApplicationUpdate(CancellationToken cancellationToken, IProgress<double> progress)
         {
         {
-            var cacheLength = TimeSpan.FromHours(3);
+            var cacheLength = TimeSpan.FromHours(1);
             var updateLevel = SystemUpdateLevel;
             var updateLevel = SystemUpdateLevel;
 
 
-            if (updateLevel == PackageVersionClass.Beta)
-            {
-                cacheLength = TimeSpan.FromHours(1);
-            }
-            else if (updateLevel == PackageVersionClass.Dev)
+            if (updateLevel != PackageVersionClass.Release)
             {
             {
                 cacheLength = TimeSpan.FromMinutes(5);
                 cacheLength = TimeSpan.FromMinutes(5);
             }
             }

+ 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
     {
     {

+ 4 - 4
Emby.Server.Implementations/Channels/ChannelImageProvider.cs

@@ -18,12 +18,12 @@ namespace Emby.Server.Implementations.Channels
             _channelManager = channelManager;
             _channelManager = channelManager;
         }
         }
 
 
-        public IEnumerable<ImageType> GetSupportedImages(IHasImages item)
+        public IEnumerable<ImageType> GetSupportedImages(IHasMetadata item)
         {
         {
             return GetChannel(item).GetSupportedChannelImages();
             return GetChannel(item).GetSupportedChannelImages();
         }
         }
 
 
-        public Task<DynamicImageResponse> GetImage(IHasImages item, ImageType type, CancellationToken cancellationToken)
+        public Task<DynamicImageResponse> GetImage(IHasMetadata item, ImageType type, CancellationToken cancellationToken)
         {
         {
             var channel = GetChannel(item);
             var channel = GetChannel(item);
 
 
@@ -35,12 +35,12 @@ namespace Emby.Server.Implementations.Channels
             get { return "Channel Image Provider"; }
             get { return "Channel Image Provider"; }
         }
         }
 
 
-        public bool Supports(IHasImages item)
+        public bool Supports(IHasMetadata item)
         {
         {
             return item is Channel;
             return item is Channel;
         }
         }
 
 
-        private IChannel GetChannel(IHasImages item)
+        private IChannel GetChannel(IHasMetadata item)
         {
         {
             var channel = (Channel)item;
             var channel = (Channel)item;
 
 

+ 22 - 19
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)
@@ -1341,7 +1344,7 @@ namespace Emby.Server.Implementations.Channels
             var hasAlbumArtists = item as IHasAlbumArtist;
             var hasAlbumArtists = item as IHasAlbumArtist;
             if (hasAlbumArtists != null)
             if (hasAlbumArtists != null)
             {
             {
-                hasAlbumArtists.AlbumArtists = info.AlbumArtists;
+                hasAlbumArtists.AlbumArtists = info.AlbumArtists.ToArray(info.AlbumArtists.Count);
             }
             }
 
 
             var trailer = item as Trailer;
             var trailer = item as Trailer;

+ 3 - 3
Emby.Server.Implementations/Collections/CollectionImageProvider.cs

@@ -21,7 +21,7 @@ namespace Emby.Server.Implementations.Collections
         {
         {
         }
         }
 
 
-        protected override bool Supports(IHasImages item)
+        protected override bool Supports(IHasMetadata item)
         {
         {
             // Right now this is the only way to prevent this image from getting created ahead of internet image providers
             // Right now this is the only way to prevent this image from getting created ahead of internet image providers
             if (!item.IsLocked)
             if (!item.IsLocked)
@@ -32,7 +32,7 @@ namespace Emby.Server.Implementations.Collections
             return base.Supports(item);
             return base.Supports(item);
         }
         }
 
 
-        protected override List<BaseItem> GetItemsWithImages(IHasImages item)
+        protected override List<BaseItem> GetItemsWithImages(IHasMetadata item)
         {
         {
             var playlist = (BoxSet)item;
             var playlist = (BoxSet)item;
 
 
@@ -76,7 +76,7 @@ namespace Emby.Server.Implementations.Collections
             return GetFinalItems(items, 2);
             return GetFinalItems(items, 2);
         }
         }
 
 
-        protected override string CreateImage(IHasImages item, List<BaseItem> itemsWithImages, string outputPathWithoutExtension, ImageType imageType, int imageIndex)
+        protected override string CreateImage(IHasMetadata item, List<BaseItem> itemsWithImages, string outputPathWithoutExtension, ImageType imageType, int imageIndex)
         {
         {
             return CreateSingleImage(itemsWithImages, outputPathWithoutExtension, ImageType.Primary);
             return CreateSingleImage(itemsWithImages, outputPathWithoutExtension, ImageType.Primary);
         }
         }

+ 6 - 3
Emby.Server.Implementations/Collections/CollectionManager.cs

@@ -12,6 +12,7 @@ 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.Model.Extensions;
 
 
 namespace Emby.Server.Implementations.Collections
 namespace Emby.Server.Implementations.Collections
 {
 {
@@ -190,7 +191,9 @@ namespace Emby.Server.Implementations.Collections
 
 
             if (list.Count > 0)
             if (list.Count > 0)
             {
             {
-                collection.LinkedChildren.AddRange(list);
+                var newList = collection.LinkedChildren.ToList();
+                newList.AddRange(list);
+                collection.LinkedChildren = newList.ToArray(newList.Count);
 
 
                 collection.UpdateRatingToContent();
                 collection.UpdateRatingToContent();
 
 
@@ -241,9 +244,9 @@ namespace Emby.Server.Implementations.Collections
                 }
                 }
             }
             }
 
 
-            foreach (var child in list)
+            if (list.Count > 0)
             {
             {
-                collection.LinkedChildren.Remove(child);
+                collection.LinkedChildren = collection.LinkedChildren.Except(list).ToArray();
             }
             }
 
 
             collection.UpdateRatingToContent();
             collection.UpdateRatingToContent();

+ 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


+ 10 - 17
Emby.Server.Implementations/Data/BaseSqliteRepository.cs

@@ -131,25 +131,11 @@ namespace Emby.Server.Implementations.Data
                 {
                 {
                     queries.Add("PRAGMA temp_store = memory");
                     queries.Add("PRAGMA temp_store = memory");
                 }
                 }
-
-                ////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))
+                else
                 {
                 {
-                    queries.Add("PRAGMA journal_mode=WAL");
-
-                    using (WriteLock.Write())
-                    {
-                        db.ExecuteAll(string.Join(";", queries.ToArray()));
-                    }
+                    queries.Add("PRAGMA temp_store = file");
                 }
                 }
-                else*/
+
                 foreach (var query in queries)
                 foreach (var query in queries)
                 {
                 {
                     db.Execute(query);
                     db.Execute(query);
@@ -208,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());

+ 2 - 45
Emby.Server.Implementations/Data/CleanDatabaseScheduledTask.cs

@@ -11,9 +11,6 @@ using System.Threading;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
 using MediaBrowser.Common.Configuration;
 using MediaBrowser.Common.Configuration;
 using MediaBrowser.Model.IO;
 using MediaBrowser.Model.IO;
-using MediaBrowser.Controller.Channels;
-using MediaBrowser.Controller.Entities.Audio;
-using MediaBrowser.Model.Tasks;
 
 
 namespace Emby.Server.Implementations.Data
 namespace Emby.Server.Implementations.Data
 {
 {
@@ -34,31 +31,9 @@ namespace Emby.Server.Implementations.Data
             _appPaths = appPaths;
             _appPaths = appPaths;
         }
         }
 
 
-        public string Name
+        public Task Run(IProgress<double> progress, CancellationToken cancellationToken)
         {
         {
-            get { return "Clean Database"; }
-        }
-
-        public string Description
-        {
-            get { return "Deletes obsolete content from the database."; }
-        }
-
-        public string Category
-        {
-            get { return "Library"; }
-        }
-
-        public async Task Run(IProgress<double> progress, CancellationToken cancellationToken)
-        {
-            // Ensure these objects are lazy loaded.
-            // Without this there is a deadlock that will need to be investigated
-            var rootChildren = _libraryManager.RootFolder.Children.ToList();
-            rootChildren = _libraryManager.GetUserRootFolder().Children.ToList();
-
-            await CleanDeadItems(cancellationToken, progress).ConfigureAwait(false);
-
-            //await _itemRepo.UpdateInheritedValues(cancellationToken).ConfigureAwait(false);
+            return CleanDeadItems(cancellationToken, progress);
         }
         }
 
 
         private async Task CleanDeadItems(CancellationToken cancellationToken, IProgress<double> progress)
         private async Task CleanDeadItems(CancellationToken cancellationToken, IProgress<double> progress)
@@ -98,23 +73,5 @@ namespace Emby.Server.Implementations.Data
 
 
             progress.Report(100);
             progress.Report(100);
         }
         }
-
-        /// <summary>
-        /// Creates the triggers that define when the task will run
-        /// </summary>
-        /// <returns>IEnumerable{BaseTaskTrigger}.</returns>
-        public IEnumerable<TaskTriggerInfo> GetDefaultTriggers()
-        {
-            return new[] { 
-            
-                // Every so often
-                new TaskTriggerInfo { Type = TaskTriggerInfo.TriggerInterval, IntervalTicks = TimeSpan.FromHours(24).Ticks}
-            };
-        }
-
-        public string Key
-        {
-            get { return "CleanDatabase"; }
-        }
     }
     }
 }
 }

+ 0 - 284
Emby.Server.Implementations/Data/SqliteFileOrganizationRepository.cs

@@ -1,284 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.IO;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Controller;
-using MediaBrowser.Controller.Persistence;
-using MediaBrowser.Model.FileOrganization;
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Model.Querying;
-using SQLitePCL.pretty;
-
-namespace Emby.Server.Implementations.Data
-{
-    public class SqliteFileOrganizationRepository : BaseSqliteRepository, IFileOrganizationRepository, IDisposable
-    {
-        private readonly CultureInfo _usCulture = new CultureInfo("en-US");
-
-        public SqliteFileOrganizationRepository(ILogger logger, IServerApplicationPaths appPaths) : base(logger)
-        {
-            DbFilePath = Path.Combine(appPaths.DataPath, "fileorganization.db");
-        }
-
-        /// <summary>
-        /// Opens the connection to the database
-        /// </summary>
-        /// <returns>Task.</returns>
-        public void Initialize()
-        {
-            using (var connection = CreateConnection())
-            {
-                RunDefaultInitialization(connection);
-
-                string[] queries = {
-
-                                "create table if not exists FileOrganizerResults (ResultId GUID PRIMARY KEY, OriginalPath TEXT, TargetPath TEXT, FileLength INT, OrganizationDate datetime, Status TEXT, OrganizationType TEXT, StatusMessage TEXT, ExtractedName TEXT, ExtractedYear int null, ExtractedSeasonNumber int null, ExtractedEpisodeNumber int null, ExtractedEndingEpisodeNumber, DuplicatePaths TEXT int null)",
-                                "create index if not exists idx_FileOrganizerResults on FileOrganizerResults(ResultId)"
-                               };
-
-                connection.RunQueries(queries);
-            }
-        }
-
-        public async Task SaveResult(FileOrganizationResult result, CancellationToken cancellationToken)
-        {
-            if (result == null)
-            {
-                throw new ArgumentNullException("result");
-            }
-
-            cancellationToken.ThrowIfCancellationRequested();
-
-            using (WriteLock.Write())
-            {
-                using (var connection = CreateConnection())
-                {
-                    connection.RunInTransaction(db =>
-                    {
-                        var commandText = "replace into FileOrganizerResults (ResultId, OriginalPath, TargetPath, FileLength, OrganizationDate, Status, OrganizationType, StatusMessage, ExtractedName, ExtractedYear, ExtractedSeasonNumber, ExtractedEpisodeNumber, ExtractedEndingEpisodeNumber, DuplicatePaths) values (@ResultId, @OriginalPath, @TargetPath, @FileLength, @OrganizationDate, @Status, @OrganizationType, @StatusMessage, @ExtractedName, @ExtractedYear, @ExtractedSeasonNumber, @ExtractedEpisodeNumber, @ExtractedEndingEpisodeNumber, @DuplicatePaths)";
-
-                        using (var statement = db.PrepareStatement(commandText))
-                        {
-                            statement.TryBind("@ResultId", result.Id.ToGuidBlob());
-                            statement.TryBind("@OriginalPath", result.OriginalPath);
-
-                            statement.TryBind("@TargetPath", result.TargetPath);
-                            statement.TryBind("@FileLength", result.FileSize);
-                            statement.TryBind("@OrganizationDate", result.Date.ToDateTimeParamValue());
-                            statement.TryBind("@Status", result.Status.ToString());
-                            statement.TryBind("@OrganizationType", result.Type.ToString());
-                            statement.TryBind("@StatusMessage", result.StatusMessage);
-                            statement.TryBind("@ExtractedName", result.ExtractedName);
-                            statement.TryBind("@ExtractedYear", result.ExtractedYear);
-                            statement.TryBind("@ExtractedSeasonNumber", result.ExtractedSeasonNumber);
-                            statement.TryBind("@ExtractedEpisodeNumber", result.ExtractedEpisodeNumber);
-                            statement.TryBind("@ExtractedEndingEpisodeNumber", result.ExtractedEndingEpisodeNumber);
-                            statement.TryBind("@DuplicatePaths", string.Join("|", result.DuplicatePaths.ToArray()));
-
-                            statement.MoveNext();
-                        }
-                    }, TransactionMode);
-                }
-            }
-        }
-
-        public async Task Delete(string id)
-        {
-            if (string.IsNullOrEmpty(id))
-            {
-                throw new ArgumentNullException("id");
-            }
-
-            using (WriteLock.Write())
-            {
-                using (var connection = CreateConnection())
-                {
-                    connection.RunInTransaction(db =>
-                    {
-                        using (var statement = db.PrepareStatement("delete from FileOrganizerResults where ResultId = @ResultId"))
-                        {
-                            statement.TryBind("@ResultId", id.ToGuidBlob());
-                            statement.MoveNext();
-                        }
-                    }, TransactionMode);
-                }
-            }
-        }
-
-        public async Task DeleteAll()
-        {
-            using (WriteLock.Write())
-            {
-                using (var connection = CreateConnection())
-                {
-                    connection.RunInTransaction(db =>
-                    {
-                        var commandText = "delete from FileOrganizerResults";
-
-                        db.Execute(commandText);
-                    }, TransactionMode);
-                }
-            }
-        }
-
-        public QueryResult<FileOrganizationResult> GetResults(FileOrganizationResultQuery query)
-        {
-            if (query == null)
-            {
-                throw new ArgumentNullException("query");
-            }
-
-            using (WriteLock.Read())
-            {
-                using (var connection = CreateConnection(true))
-                {
-                    var commandText = "SELECT ResultId, OriginalPath, TargetPath, FileLength, OrganizationDate, Status, OrganizationType, StatusMessage, ExtractedName, ExtractedYear, ExtractedSeasonNumber, ExtractedEpisodeNumber, ExtractedEndingEpisodeNumber, DuplicatePaths from FileOrganizerResults";
-
-                    if (query.StartIndex.HasValue && query.StartIndex.Value > 0)
-                    {
-                        commandText += string.Format(" WHERE ResultId NOT IN (SELECT ResultId FROM FileOrganizerResults ORDER BY OrganizationDate desc LIMIT {0})",
-                            query.StartIndex.Value.ToString(_usCulture));
-                    }
-
-                    commandText += " ORDER BY OrganizationDate desc";
-
-                    if (query.Limit.HasValue)
-                    {
-                        commandText += " LIMIT " + query.Limit.Value.ToString(_usCulture);
-                    }
-
-                    var list = new List<FileOrganizationResult>();
-
-                    using (var statement = connection.PrepareStatement(commandText))
-                    {
-                        foreach (var row in statement.ExecuteQuery())
-                        {
-                            list.Add(GetResult(row));
-                        }
-                    }
-
-                    int count;
-                    using (var statement = connection.PrepareStatement("select count (ResultId) from FileOrganizerResults"))
-                    {
-                        count = statement.ExecuteQuery().SelectScalarInt().First();
-                    }
-
-                    return new QueryResult<FileOrganizationResult>()
-                    {
-                        Items = list.ToArray(),
-                        TotalRecordCount = count
-                    };
-                }
-            }
-        }
-
-        public FileOrganizationResult GetResult(string id)
-        {
-            if (string.IsNullOrEmpty(id))
-            {
-                throw new ArgumentNullException("id");
-            }
-
-            using (WriteLock.Read())
-            {
-                using (var connection = CreateConnection(true))
-                {
-                    using (var statement = connection.PrepareStatement("select ResultId, OriginalPath, TargetPath, FileLength, OrganizationDate, Status, OrganizationType, StatusMessage, ExtractedName, ExtractedYear, ExtractedSeasonNumber, ExtractedEpisodeNumber, ExtractedEndingEpisodeNumber, DuplicatePaths from FileOrganizerResults where ResultId=@ResultId"))
-                    {
-                        statement.TryBind("@ResultId", id.ToGuidBlob());
-
-                        foreach (var row in statement.ExecuteQuery())
-                        {
-                            return GetResult(row);
-                        }
-                    }
-
-                    return null;
-                }
-            }
-        }
-
-        public FileOrganizationResult GetResult(IReadOnlyList<IResultSetValue> reader)
-        {
-            var index = 0;
-
-            var result = new FileOrganizationResult
-            {
-                Id = reader[0].ReadGuidFromBlob().ToString("N")
-            };
-
-            index++;
-            if (reader[index].SQLiteType != SQLiteType.Null)
-            {
-                result.OriginalPath = reader[index].ToString();
-            }
-
-            index++;
-            if (reader[index].SQLiteType != SQLiteType.Null)
-            {
-                result.TargetPath = reader[index].ToString();
-            }
-
-            index++;
-            result.FileSize = reader[index].ToInt64();
-
-            index++;
-            result.Date = reader[index].ReadDateTime();
-
-            index++;
-            result.Status = (FileSortingStatus)Enum.Parse(typeof(FileSortingStatus), reader[index].ToString(), true);
-
-            index++;
-            result.Type = (FileOrganizerType)Enum.Parse(typeof(FileOrganizerType), reader[index].ToString(), true);
-
-            index++;
-            if (reader[index].SQLiteType != SQLiteType.Null)
-            {
-                result.StatusMessage = reader[index].ToString();
-            }
-
-            result.OriginalFileName = Path.GetFileName(result.OriginalPath);
-
-            index++;
-            if (reader[index].SQLiteType != SQLiteType.Null)
-            {
-                result.ExtractedName = reader[index].ToString();
-            }
-
-            index++;
-            if (reader[index].SQLiteType != SQLiteType.Null)
-            {
-                result.ExtractedYear = reader[index].ToInt();
-            }
-
-            index++;
-            if (reader[index].SQLiteType != SQLiteType.Null)
-            {
-                result.ExtractedSeasonNumber = reader[index].ToInt();
-            }
-
-            index++;
-            if (reader[index].SQLiteType != SQLiteType.Null)
-            {
-                result.ExtractedEpisodeNumber = reader[index].ToInt();
-            }
-
-            index++;
-            if (reader[index].SQLiteType != SQLiteType.Null)
-            {
-                result.ExtractedEndingEpisodeNumber = reader[index].ToInt();
-            }
-
-            index++;
-            if (reader[index].SQLiteType != SQLiteType.Null)
-            {
-                result.DuplicatePaths = reader[index].ToString().Split('|').Where(i => !string.IsNullOrEmpty(i)).ToList();
-            }
-
-            return result;
-        }
-    }
-}

Diferenças do arquivo suprimidas por serem muito extensas
+ 205 - 229
Emby.Server.Implementations/Data/SqliteItemRepository.cs


+ 27 - 68
Emby.Server.Implementations/Dto/DtoService.cs

@@ -359,11 +359,11 @@ namespace Emby.Server.Implementations.Dto
                 {
                 {
                     if (user == null)
                     if (user == null)
                     {
                     {
-                        dto.MediaSources = _mediaSourceManager().GetStaticMediaSources(hasMediaSources, true).ToList();
+                        dto.MediaSources = _mediaSourceManager().GetStaticMediaSources(hasMediaSources, true);
                     }
                     }
                     else
                     else
                     {
                     {
-                        dto.MediaSources = _mediaSourceManager().GetStaticMediaSources(hasMediaSources, true, user).ToList();
+                        dto.MediaSources = _mediaSourceManager().GetStaticMediaSources(hasMediaSources, true, user);
                     }
                     }
                 }
                 }
             }
             }
@@ -517,7 +517,7 @@ namespace Emby.Server.Implementations.Dto
                 }
                 }
             }
             }
 
 
-            if (!(item is LiveTvProgram) || fields.Contains(ItemFields.PlayAccess))
+            if (/*!(item is LiveTvProgram) ||*/ fields.Contains(ItemFields.PlayAccess))
             {
             {
                 dto.PlayAccess = item.GetPlayAccess(user);
                 dto.PlayAccess = item.GetPlayAccess(user);
             }
             }
@@ -639,7 +639,6 @@ namespace Emby.Server.Implementations.Dto
 
 
         private void SetGameProperties(BaseItemDto dto, Game item)
         private void SetGameProperties(BaseItemDto dto, Game item)
         {
         {
-            dto.Players = item.PlayersSupported;
             dto.GameSystem = item.GameSystem;
             dto.GameSystem = item.GameSystem;
             dto.MultiPartGameFiles = item.MultiPartGameFiles;
             dto.MultiPartGameFiles = item.MultiPartGameFiles;
         }
         }
@@ -649,12 +648,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 +765,7 @@ namespace Emby.Server.Implementations.Dto
                 }
                 }
             }
             }
 
 
-            dto.People = list.ToArray();
+            dto.People = list.ToArray(list.Count);
         }
         }
 
 
         /// <summary>
         /// <summary>
@@ -864,11 +863,6 @@ namespace Emby.Server.Implementations.Dto
                 dto.DateCreated = item.DateCreated;
                 dto.DateCreated = item.DateCreated;
             }
             }
 
 
-            if (fields.Contains(ItemFields.DisplayMediaType))
-            {
-                dto.DisplayMediaType = item.DisplayMediaType;
-            }
-
             if (fields.Contains(ItemFields.Settings))
             if (fields.Contains(ItemFields.Settings))
             {
             {
                 dto.LockedFields = item.LockedFields;
                 dto.LockedFields = item.LockedFields;
@@ -894,11 +888,6 @@ namespace Emby.Server.Implementations.Dto
                 dto.Tags = item.Tags;
                 dto.Tags = item.Tags;
             }
             }
 
 
-            if (fields.Contains(ItemFields.Keywords))
-            {
-                dto.Keywords = item.Keywords;
-            }
-
             var hasAspectRatio = item as IHasAspectRatio;
             var hasAspectRatio = item as IHasAspectRatio;
             if (hasAspectRatio != null)
             if (hasAspectRatio != null)
             {
             {
@@ -1003,7 +992,7 @@ namespace Emby.Server.Implementations.Dto
             {
             {
                 dto.RemoteTrailers = hasTrailers != null ?
                 dto.RemoteTrailers = hasTrailers != null ?
                     hasTrailers.RemoteTrailers :
                     hasTrailers.RemoteTrailers :
-                    new List<MediaUrl>();
+                    new MediaUrl[] {};
             }
             }
 
 
             dto.Name = item.Name;
             dto.Name = item.Name;
@@ -1059,12 +1048,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[]{};
                 }
                 }
             }
             }
 
 
@@ -1130,8 +1119,7 @@ namespace Emby.Server.Implementations.Dto
 
 
                 // Include artists that are not in the database yet, e.g., just added via metadata editor
                 // Include artists that are not in the database yet, e.g., just added via metadata editor
                 //var foundArtists = artistItems.Items.Select(i => i.Item1.Name).ToList();
                 //var foundArtists = artistItems.Items.Select(i => i.Item1.Name).ToList();
-                dto.ArtistItems = new List<NameIdPair>();
-                dto.ArtistItems.AddRange(hasArtist.Artists
+                dto.ArtistItems = hasArtist.Artists
                     //.Except(foundArtists, new DistinctNameComparer())
                     //.Except(foundArtists, new DistinctNameComparer())
                     .Select(i =>
                     .Select(i =>
                     {
                     {
@@ -1156,7 +1144,7 @@ namespace Emby.Server.Implementations.Dto
 
 
                         return null;
                         return null;
 
 
-                    }).Where(i => i != null));
+                    }).Where(i => i != null).ToArray();
             }
             }
 
 
             var hasAlbumArtist = item as IHasAlbumArtist;
             var hasAlbumArtist = item as IHasAlbumArtist;
@@ -1182,8 +1170,7 @@ namespace Emby.Server.Implementations.Dto
                 //    })
                 //    })
                 //    .ToList();
                 //    .ToList();
 
 
-                dto.AlbumArtists = new List<NameIdPair>();
-                dto.AlbumArtists.AddRange(hasAlbumArtist.AlbumArtists
+                dto.AlbumArtists = hasAlbumArtist.AlbumArtists
                     //.Except(foundArtists, new DistinctNameComparer())
                     //.Except(foundArtists, new DistinctNameComparer())
                     .Select(i =>
                     .Select(i =>
                     {
                     {
@@ -1208,7 +1195,7 @@ namespace Emby.Server.Implementations.Dto
 
 
                         return null;
                         return null;
 
 
-                    }).Where(i => i != null));
+                    }).Where(i => i != null).ToArray();
             }
             }
 
 
             // Add video info
             // Add video info
@@ -1224,9 +1211,9 @@ namespace Emby.Server.Implementations.Dto
                     dto.HasSubtitles = video.HasSubtitles;
                     dto.HasSubtitles = video.HasSubtitles;
                 }
                 }
 
 
-                if (video.AdditionalParts.Count != 0)
+                if (video.AdditionalParts.Length != 0)
                 {
                 {
-                    dto.PartCount = video.AdditionalParts.Count + 1;
+                    dto.PartCount = video.AdditionalParts.Length + 1;
                 }
                 }
 
 
                 if (fields.Contains(ItemFields.MediaSourceCount))
                 if (fields.Contains(ItemFields.MediaSourceCount))
@@ -1276,7 +1263,7 @@ namespace Emby.Server.Implementations.Dto
             var hasSpecialFeatures = item as IHasSpecialFeatures;
             var hasSpecialFeatures = item as IHasSpecialFeatures;
             if (hasSpecialFeatures != null)
             if (hasSpecialFeatures != null)
             {
             {
-                var specialFeatureCount = hasSpecialFeatures.SpecialFeatureIds.Count;
+                var specialFeatureCount = hasSpecialFeatures.SpecialFeatureIds.Length;
 
 
                 if (specialFeatureCount > 0)
                 if (specialFeatureCount > 0)
                 {
                 {
@@ -1321,15 +1308,6 @@ namespace Emby.Server.Implementations.Dto
 
 
                 Series episodeSeries = null;
                 Series episodeSeries = null;
 
 
-                if (fields.Contains(ItemFields.SeriesGenres))
-                {
-                    episodeSeries = episodeSeries ?? episode.Series;
-                    if (episodeSeries != null)
-                    {
-                        dto.SeriesGenres = episodeSeries.Genres.ToList();
-                    }
-                }
-
                 //if (fields.Contains(ItemFields.SeriesPrimaryImage))
                 //if (fields.Contains(ItemFields.SeriesPrimaryImage))
                 {
                 {
                     episodeSeries = episodeSeries ?? episode.Series;
                     episodeSeries = episodeSeries ?? episode.Series;
@@ -1345,27 +1323,6 @@ namespace Emby.Server.Implementations.Dto
                     if (episodeSeries != null)
                     if (episodeSeries != null)
                     {
                     {
                         dto.SeriesStudio = episodeSeries.Studios.FirstOrDefault();
                         dto.SeriesStudio = episodeSeries.Studios.FirstOrDefault();
-                        if (!string.IsNullOrWhiteSpace(dto.SeriesStudio))
-                        {
-                            try
-                            {
-                                var studio = _libraryManager.GetStudio(dto.SeriesStudio);
-
-                                if (studio != null)
-                                {
-                                    dto.SeriesStudioInfo = new StudioDto
-                                    {
-                                        Name = dto.SeriesStudio,
-                                        Id = studio.Id.ToString("N"),
-                                        PrimaryImageTag = GetImageCacheTag(studio, ImageType.Primary)
-                                    };
-                                }
-                            }
-                            catch (Exception ex)
-                            {
-
-                            }
-                        }
                     }
                     }
                 }
                 }
             }
             }
@@ -1440,9 +1397,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;
                 }
                 }
             }
             }
 
 
@@ -1509,7 +1466,9 @@ namespace Emby.Server.Implementations.Dto
             BaseItem parent = null;
             BaseItem parent = null;
             var isFirst = true;
             var isFirst = true;
 
 
-            while (((!dto.HasLogo && logoLimit > 0) || (!dto.HasArtImage && artLimit > 0) || (!dto.HasThumb && thumbLimit > 0) || parent is Series) &&
+            var imageTags = dto.ImageTags;
+
+            while (((!(imageTags != null && imageTags.ContainsKey(ImageType.Logo)) && logoLimit > 0) || (!(imageTags != null && imageTags.ContainsKey(ImageType.Art)) && artLimit > 0) || (!(imageTags != null && imageTags.ContainsKey(ImageType.Thumb)) && thumbLimit > 0) || parent is Series) &&
                 (parent = parent ?? (isFirst ? GetImageDisplayParent(item, item) ?? owner : parent)) != null)
                 (parent = parent ?? (isFirst ? GetImageDisplayParent(item, item) ?? owner : parent)) != null)
             {
             {
                 if (parent == null)
                 if (parent == null)
@@ -1519,7 +1478,7 @@ namespace Emby.Server.Implementations.Dto
 
 
                 var allImages = parent.ImageInfos;
                 var allImages = parent.ImageInfos;
 
 
-                if (logoLimit > 0 && !dto.HasLogo && dto.ParentLogoItemId == null)
+                if (logoLimit > 0 && !(imageTags != null && imageTags.ContainsKey(ImageType.Logo)) && dto.ParentLogoItemId == null)
                 {
                 {
                     var image = allImages.FirstOrDefault(i => i.Type == ImageType.Logo);
                     var image = allImages.FirstOrDefault(i => i.Type == ImageType.Logo);
 
 
@@ -1529,7 +1488,7 @@ namespace Emby.Server.Implementations.Dto
                         dto.ParentLogoImageTag = GetImageCacheTag(parent, image);
                         dto.ParentLogoImageTag = GetImageCacheTag(parent, image);
                     }
                     }
                 }
                 }
-                if (artLimit > 0 && !dto.HasArtImage && dto.ParentArtItemId == null)
+                if (artLimit > 0 && !(imageTags != null && imageTags.ContainsKey(ImageType.Art)) && dto.ParentArtItemId == null)
                 {
                 {
                     var image = allImages.FirstOrDefault(i => i.Type == ImageType.Art);
                     var image = allImages.FirstOrDefault(i => i.Type == ImageType.Art);
 
 
@@ -1539,7 +1498,7 @@ namespace Emby.Server.Implementations.Dto
                         dto.ParentArtImageTag = GetImageCacheTag(parent, image);
                         dto.ParentArtImageTag = GetImageCacheTag(parent, image);
                     }
                     }
                 }
                 }
-                if (thumbLimit > 0 && !dto.HasThumb && (dto.ParentThumbItemId == null || parent is Series) && !(parent is ICollectionFolder) && !(parent is UserView))
+                if (thumbLimit > 0 && !(imageTags != null && imageTags.ContainsKey(ImageType.Thumb)) && (dto.ParentThumbItemId == null || parent is Series) && !(parent is ICollectionFolder) && !(parent is UserView))
                 {
                 {
                     var image = allImages.FirstOrDefault(i => i.Type == ImageType.Thumb);
                     var image = allImages.FirstOrDefault(i => i.Type == ImageType.Thumb);
 
 
@@ -1549,7 +1508,7 @@ namespace Emby.Server.Implementations.Dto
                         dto.ParentThumbImageTag = GetImageCacheTag(parent, image);
                         dto.ParentThumbImageTag = GetImageCacheTag(parent, image);
                     }
                     }
                 }
                 }
-                if (backdropLimit > 0 && !dto.HasBackdrop)
+                if (backdropLimit > 0 && !((dto.BackdropImageTags != null && dto.BackdropImageTags.Length > 0) || (dto.ParentBackdropImageTags != null && dto.ParentBackdropImageTags.Length > 0)))
                 {
                 {
                     var images = allImages.Where(i => i.Type == ImageType.Backdrop).Take(backdropLimit).ToList();
                     var images = allImages.Where(i => i.Type == ImageType.Backdrop).Take(backdropLimit).ToList();
 
 
@@ -1591,12 +1550,12 @@ namespace Emby.Server.Implementations.Dto
         /// <param name="dto">The dto.</param>
         /// <param name="dto">The dto.</param>
         /// <param name="item">The item.</param>
         /// <param name="item">The item.</param>
         /// <returns>Task.</returns>
         /// <returns>Task.</returns>
-        public void AttachPrimaryImageAspectRatio(IItemDto dto, IHasImages item)
+        public void AttachPrimaryImageAspectRatio(IItemDto dto, IHasMetadata item)
         {
         {
             dto.PrimaryImageAspectRatio = GetPrimaryImageAspectRatio(item);
             dto.PrimaryImageAspectRatio = GetPrimaryImageAspectRatio(item);
         }
         }
 
 
-        public double? GetPrimaryImageAspectRatio(IHasImages item)
+        public double? GetPrimaryImageAspectRatio(IHasMetadata item)
         {
         {
             var imageInfo = item.GetImageInfo(ImageType.Primary, 0);
             var imageInfo = item.GetImageInfo(ImageType.Primary, 0);
 
 

+ 87 - 11
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>
@@ -29,6 +30,7 @@
     <DefineConstants>TRACE</DefineConstants>
     <DefineConstants>TRACE</DefineConstants>
     <ErrorReport>prompt</ErrorReport>
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
     <WarningLevel>4</WarningLevel>
+    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
   </PropertyGroup>
   </PropertyGroup>
   <ItemGroup>
   <ItemGroup>
     <Compile Include="..\SharedVersion.cs">
     <Compile Include="..\SharedVersion.cs">
@@ -40,6 +42,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,9 +56,26 @@
     <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\SqliteFileOrganizationRepository.cs" />
     <Compile Include="Data\SqliteItemRepository.cs" />
     <Compile Include="Data\SqliteItemRepository.cs" />
     <Compile Include="Data\SqliteUserDataRepository.cs" />
     <Compile Include="Data\SqliteUserDataRepository.cs" />
     <Compile Include="Data\SqliteUserRepository.cs" />
     <Compile Include="Data\SqliteUserRepository.cs" />
@@ -64,6 +85,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" />
@@ -79,13 +101,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="FileOrganization\EpisodeFileOrganizer.cs" />
-    <Compile Include="FileOrganization\Extensions.cs" />
-    <Compile Include="FileOrganization\FileOrganizationNotifier.cs" />
-    <Compile Include="FileOrganization\FileOrganizationService.cs" />
-    <Compile Include="FileOrganization\NameUtils.cs" />
-    <Compile Include="FileOrganization\OrganizerScheduledTask.cs" />
-    <Compile Include="FileOrganization\TvFolderOrganizer.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" />
@@ -107,7 +123,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" />
@@ -178,6 +196,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" />
@@ -229,7 +249,6 @@
     <Compile Include="Social\SharingManager.cs" />
     <Compile Include="Social\SharingManager.cs" />
     <Compile Include="Social\SharingRepository.cs" />
     <Compile Include="Social\SharingRepository.cs" />
     <Compile Include="Sorting\AiredEpisodeOrderComparer.cs" />
     <Compile Include="Sorting\AiredEpisodeOrderComparer.cs" />
-    <Compile Include="Sorting\AirTimeComparer.cs" />
     <Compile Include="Sorting\AlbumArtistComparer.cs" />
     <Compile Include="Sorting\AlbumArtistComparer.cs" />
     <Compile Include="Sorting\AlbumComparer.cs" />
     <Compile Include="Sorting\AlbumComparer.cs" />
     <Compile Include="Sorting\AlphanumComparator.cs" />
     <Compile Include="Sorting\AlphanumComparator.cs" />
@@ -257,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" />
@@ -268,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>
@@ -276,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>
@@ -288,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>
@@ -300,6 +363,16 @@
       <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.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="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>
@@ -307,10 +380,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" />
@@ -421,6 +494,9 @@
   <ItemGroup>
   <ItemGroup>
     <EmbeddedResource Include="Localization\Ratings\es.txt" />
     <EmbeddedResource Include="Localization\Ratings\es.txt" />
   </ItemGroup>
   </ItemGroup>
+  <ItemGroup>
+    <EmbeddedResource Include="Localization\Ratings\ro.txt" />
+  </ItemGroup>
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
   <!-- 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.
        Other similar extension points exist, see Microsoft.Common.targets.

+ 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));
             }
             }

+ 0 - 813
Emby.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs

@@ -1,813 +0,0 @@
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Entities.TV;
-using MediaBrowser.Controller.FileOrganization;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.Providers;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Extensions;
-using MediaBrowser.Model.FileOrganization;
-using MediaBrowser.Model.Logging;
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.IO;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-using Emby.Server.Implementations.Library;
-using MediaBrowser.Controller.Dto;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.IO;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Naming.TV;
-using EpisodeInfo = MediaBrowser.Controller.Providers.EpisodeInfo;
-
-namespace Emby.Server.Implementations.FileOrganization
-{
-    public class EpisodeFileOrganizer
-    {
-        private readonly ILibraryMonitor _libraryMonitor;
-        private readonly ILibraryManager _libraryManager;
-        private readonly ILogger _logger;
-        private readonly IFileSystem _fileSystem;
-        private readonly IFileOrganizationService _organizationService;
-        private readonly IServerConfigurationManager _config;
-        private readonly IProviderManager _providerManager;
-
-        private readonly CultureInfo _usCulture = new CultureInfo("en-US");
-
-        public EpisodeFileOrganizer(IFileOrganizationService organizationService, IServerConfigurationManager config, IFileSystem fileSystem, ILogger logger, ILibraryManager libraryManager, ILibraryMonitor libraryMonitor, IProviderManager providerManager)
-        {
-            _organizationService = organizationService;
-            _config = config;
-            _fileSystem = fileSystem;
-            _logger = logger;
-            _libraryManager = libraryManager;
-            _libraryMonitor = libraryMonitor;
-            _providerManager = providerManager;
-        }
-
-        public async Task<FileOrganizationResult> OrganizeEpisodeFile(string path, AutoOrganizeOptions options, bool overwriteExisting, CancellationToken cancellationToken)
-        {
-            _logger.Info("Sorting file {0}", path);
-
-            var result = new FileOrganizationResult
-            {
-                Date = DateTime.UtcNow,
-                OriginalPath = path,
-                OriginalFileName = Path.GetFileName(path),
-                Type = FileOrganizerType.Episode,
-                FileSize = _fileSystem.GetFileInfo(path).Length
-            };
-
-            try
-            {
-                if (_libraryMonitor.IsPathLocked(path))
-                {
-                    result.Status = FileSortingStatus.Failure;
-                    result.StatusMessage = "Path is locked by other processes. Please try again later.";
-                    return result;
-                }
-
-                var namingOptions = ((LibraryManager)_libraryManager).GetNamingOptions();
-                var resolver = new EpisodeResolver(namingOptions, new NullLogger());
-
-                var episodeInfo = resolver.Resolve(path, false) ??
-                    new MediaBrowser.Naming.TV.EpisodeInfo();
-
-                var seriesName = episodeInfo.SeriesName;
-
-                if (!string.IsNullOrEmpty(seriesName))
-                {
-                    var seasonNumber = episodeInfo.SeasonNumber;
-
-                    result.ExtractedSeasonNumber = seasonNumber;
-
-                    // Passing in true will include a few extra regex's
-                    var episodeNumber = episodeInfo.EpisodeNumber;
-
-                    result.ExtractedEpisodeNumber = episodeNumber;
-
-                    var premiereDate = episodeInfo.IsByDate ?
-                        new DateTime(episodeInfo.Year.Value, episodeInfo.Month.Value, episodeInfo.Day.Value) :
-                        (DateTime?)null;
-
-                    if (episodeInfo.IsByDate || (seasonNumber.HasValue && episodeNumber.HasValue))
-                    {
-                        if (episodeInfo.IsByDate)
-                        {
-                            _logger.Debug("Extracted information from {0}. Series name {1}, Date {2}", path, seriesName, premiereDate.Value);
-                        }
-                        else
-                        {
-                            _logger.Debug("Extracted information from {0}. Series name {1}, Season {2}, Episode {3}", path, seriesName, seasonNumber, episodeNumber);
-                        }
-
-                        var endingEpisodeNumber = episodeInfo.EndingEpsiodeNumber;
-
-                        result.ExtractedEndingEpisodeNumber = endingEpisodeNumber;
-
-                        await OrganizeEpisode(path,
-                            seriesName,
-                            seasonNumber,
-                            episodeNumber,
-                            endingEpisodeNumber,
-                            premiereDate,
-                            options,
-                            overwriteExisting,
-                            false,
-                            result,
-                            cancellationToken).ConfigureAwait(false);
-                    }
-                    else
-                    {
-                        var msg = string.Format("Unable to determine episode number from {0}", path);
-                        result.Status = FileSortingStatus.Failure;
-                        result.StatusMessage = msg;
-                        _logger.Warn(msg);
-                    }
-                }
-                else
-                {
-                    var msg = string.Format("Unable to determine series name from {0}", path);
-                    result.Status = FileSortingStatus.Failure;
-                    result.StatusMessage = msg;
-                    _logger.Warn(msg);
-                }
-
-                var previousResult = _organizationService.GetResultBySourcePath(path);
-
-                if (previousResult != null)
-                {
-                    // Don't keep saving the same result over and over if nothing has changed
-                    if (previousResult.Status == result.Status && previousResult.StatusMessage == result.StatusMessage && result.Status != FileSortingStatus.Success)
-                    {
-                        return previousResult;
-                    }
-                }
-
-                await _organizationService.SaveResult(result, CancellationToken.None).ConfigureAwait(false);
-            }
-            catch (Exception ex)
-            {
-                result.Status = FileSortingStatus.Failure;
-                result.StatusMessage = ex.Message;
-            }
-
-            return result;
-        }
-
-        public async Task<FileOrganizationResult> OrganizeWithCorrection(EpisodeFileOrganizationRequest request, AutoOrganizeOptions options, CancellationToken cancellationToken)
-        {
-            var result = _organizationService.GetResult(request.ResultId);
-
-            try
-            {
-                Series series = null;
-
-                if (request.NewSeriesProviderIds.Count > 0)
-                {
-                    // We're having a new series here
-                    SeriesInfo seriesRequest = new SeriesInfo();
-                    seriesRequest.ProviderIds = request.NewSeriesProviderIds;
-
-                    var refreshOptions = new MetadataRefreshOptions(_fileSystem);
-                    series = new Series();
-                    series.Id = Guid.NewGuid();
-                    series.Name = request.NewSeriesName;
-
-                    int year;
-                    if (int.TryParse(request.NewSeriesYear, out year))
-                    {
-                        series.ProductionYear = year;
-                    }
-
-                    var seriesFolderName = series.Name;
-                    if (series.ProductionYear.HasValue)
-                    {
-                        seriesFolderName = string.Format("{0} ({1})", seriesFolderName, series.ProductionYear);
-                    }
-
-                    seriesFolderName = _fileSystem.GetValidFilename(seriesFolderName);
-
-                    series.Path = Path.Combine(request.TargetFolder, seriesFolderName);
-
-                    series.ProviderIds = request.NewSeriesProviderIds;
-
-                    await series.RefreshMetadata(refreshOptions, cancellationToken).ConfigureAwait(false);
-                }
-
-                if (series == null)
-                {
-                    // Existing Series
-                    series = (Series)_libraryManager.GetItemById(new Guid(request.SeriesId));
-                }
-
-                await OrganizeEpisode(result.OriginalPath,
-                    series,
-                    request.SeasonNumber,
-                    request.EpisodeNumber,
-                    request.EndingEpisodeNumber,
-                    null,
-                    options,
-                    true,
-                    request.RememberCorrection,
-                    result,
-                    cancellationToken).ConfigureAwait(false);
-
-                await _organizationService.SaveResult(result, CancellationToken.None).ConfigureAwait(false);
-            }
-            catch (Exception ex)
-            {
-                result.Status = FileSortingStatus.Failure;
-                result.StatusMessage = ex.Message;
-            }
-
-            return result;
-        }
-
-        private Task OrganizeEpisode(string sourcePath,
-            string seriesName,
-            int? seasonNumber,
-            int? episodeNumber,
-            int? endingEpiosdeNumber,
-            DateTime? premiereDate,
-            AutoOrganizeOptions options,
-            bool overwriteExisting,
-            bool rememberCorrection,
-            FileOrganizationResult result,
-            CancellationToken cancellationToken)
-        {
-            var series = GetMatchingSeries(seriesName, result, options);
-
-            if (series == null)
-            {
-                var msg = string.Format("Unable to find series in library matching name {0}", seriesName);
-                result.Status = FileSortingStatus.Failure;
-                result.StatusMessage = msg;
-                _logger.Warn(msg);
-                return Task.FromResult(true);
-            }
-
-            return OrganizeEpisode(sourcePath,
-                series,
-                seasonNumber,
-                episodeNumber,
-                endingEpiosdeNumber,
-                premiereDate,
-                options,
-                overwriteExisting,
-                rememberCorrection,
-                result,
-                cancellationToken);
-        }
-
-        private async Task OrganizeEpisode(string sourcePath,
-            Series series,
-            int? seasonNumber,
-            int? episodeNumber,
-            int? endingEpiosdeNumber,
-            DateTime? premiereDate,
-            AutoOrganizeOptions options,
-            bool overwriteExisting,
-            bool rememberCorrection,
-            FileOrganizationResult result,
-            CancellationToken cancellationToken)
-        {
-            _logger.Info("Sorting file {0} into series {1}", sourcePath, series.Path);
-
-            var originalExtractedSeriesString = result.ExtractedName;
-
-            bool isNew = string.IsNullOrWhiteSpace(result.Id);
-
-            if (isNew)
-            {
-                await _organizationService.SaveResult(result, cancellationToken);
-            }
-
-            if (!_organizationService.AddToInProgressList(result, isNew))
-            {
-                throw new Exception("File is currently processed otherwise. Please try again later.");
-            }
-
-            try
-            {
-                // Proceed to sort the file
-                var newPath = await GetNewPath(sourcePath, series, seasonNumber, episodeNumber, endingEpiosdeNumber, premiereDate, options.TvOptions, cancellationToken).ConfigureAwait(false);
-
-                if (string.IsNullOrEmpty(newPath))
-                {
-                    var msg = string.Format("Unable to sort {0} because target path could not be determined.", sourcePath);
-                    throw new Exception(msg);
-                }
-
-                _logger.Info("Sorting file {0} to new path {1}", sourcePath, newPath);
-                result.TargetPath = newPath;
-
-                var fileExists = _fileSystem.FileExists(result.TargetPath);
-                var otherDuplicatePaths = GetOtherDuplicatePaths(result.TargetPath, series, seasonNumber, episodeNumber, endingEpiosdeNumber);
-
-                if (!overwriteExisting)
-                {
-                    if (options.TvOptions.CopyOriginalFile && fileExists && IsSameEpisode(sourcePath, newPath))
-                    {
-                        var msg = string.Format("File '{0}' already copied to new path '{1}', stopping organization", sourcePath, newPath);
-                        _logger.Info(msg);
-                        result.Status = FileSortingStatus.SkippedExisting;
-                        result.StatusMessage = msg;
-                        return;
-                    }
-
-                    if (fileExists)
-                    {
-                        var msg = string.Format("File '{0}' already exists as '{1}', stopping organization", sourcePath, newPath);
-                        _logger.Info(msg);
-                        result.Status = FileSortingStatus.SkippedExisting;
-                        result.StatusMessage = msg;
-                        result.TargetPath = newPath;
-                        return;
-                    }
-
-                    if (otherDuplicatePaths.Count > 0)
-                    {
-                        var msg = string.Format("File '{0}' already exists as these:'{1}'. Stopping organization", sourcePath, string.Join("', '", otherDuplicatePaths));
-                        _logger.Info(msg);
-                        result.Status = FileSortingStatus.SkippedExisting;
-                        result.StatusMessage = msg;
-                        result.DuplicatePaths = otherDuplicatePaths;
-                        return;
-                    }
-                }
-
-                PerformFileSorting(options.TvOptions, result);
-
-                if (overwriteExisting)
-                {
-                    var hasRenamedFiles = false;
-
-                    foreach (var path in otherDuplicatePaths)
-                    {
-                        _logger.Debug("Removing duplicate episode {0}", path);
-
-                        _libraryMonitor.ReportFileSystemChangeBeginning(path);
-
-                        var renameRelatedFiles = !hasRenamedFiles &&
-                            string.Equals(_fileSystem.GetDirectoryName(path), _fileSystem.GetDirectoryName(result.TargetPath), StringComparison.OrdinalIgnoreCase);
-
-                        if (renameRelatedFiles)
-                        {
-                            hasRenamedFiles = true;
-                        }
-
-                        try
-                        {
-                            DeleteLibraryFile(path, renameRelatedFiles, result.TargetPath);
-                        }
-                        catch (IOException ex)
-                        {
-                            _logger.ErrorException("Error removing duplicate episode", ex, path);
-                        }
-                        finally
-                        {
-                            _libraryMonitor.ReportFileSystemChangeComplete(path, true);
-                        }
-                    }
-                }
-            }
-            catch (Exception ex)
-            {
-                result.Status = FileSortingStatus.Failure;
-                result.StatusMessage = ex.Message;
-                _logger.Warn(ex.Message);
-                return;
-            }
-            finally
-            {
-                _organizationService.RemoveFromInprogressList(result);
-            }
-
-            if (rememberCorrection)
-            {
-                SaveSmartMatchString(originalExtractedSeriesString, series, options);
-            }
-        }
-
-        private void SaveSmartMatchString(string matchString, Series series, AutoOrganizeOptions options)
-        {
-            if (string.IsNullOrEmpty(matchString) || matchString.Length < 3)
-            {
-                return;
-            }
-
-            SmartMatchInfo info = options.SmartMatchInfos.FirstOrDefault(i => string.Equals(i.ItemName, series.Name, StringComparison.OrdinalIgnoreCase));
-
-            if (info == null)
-            {
-                info = new SmartMatchInfo();
-                info.ItemName = series.Name;
-                info.OrganizerType = FileOrganizerType.Episode;
-                info.DisplayName = series.Name;
-                var list = options.SmartMatchInfos.ToList();
-                list.Add(info);
-                options.SmartMatchInfos = list.ToArray();
-            }
-
-            if (!info.MatchStrings.Contains(matchString, StringComparer.OrdinalIgnoreCase))
-            {
-                var list = info.MatchStrings.ToList();
-                list.Add(matchString);
-                info.MatchStrings = list.ToArray();
-                _config.SaveAutoOrganizeOptions(options);
-            }
-        }
-
-        private void DeleteLibraryFile(string path, bool renameRelatedFiles, string targetPath)
-        {
-            _fileSystem.DeleteFile(path);
-
-            if (!renameRelatedFiles)
-            {
-                return;
-            }
-
-            // Now find other files
-            var originalFilenameWithoutExtension = Path.GetFileNameWithoutExtension(path);
-            var directory = _fileSystem.GetDirectoryName(path);
-
-            if (!string.IsNullOrWhiteSpace(originalFilenameWithoutExtension) && !string.IsNullOrWhiteSpace(directory))
-            {
-                // Get all related files, e.g. metadata, images, etc
-                var files = _fileSystem.GetFilePaths(directory)
-                    .Where(i => (Path.GetFileNameWithoutExtension(i) ?? string.Empty).StartsWith(originalFilenameWithoutExtension, StringComparison.OrdinalIgnoreCase))
-                    .ToList();
-
-                var targetFilenameWithoutExtension = Path.GetFileNameWithoutExtension(targetPath);
-
-                foreach (var file in files)
-                {
-                    directory = _fileSystem.GetDirectoryName(file);
-                    var filename = Path.GetFileName(file);
-
-                    filename = filename.Replace(originalFilenameWithoutExtension, targetFilenameWithoutExtension,
-                        StringComparison.OrdinalIgnoreCase);
-
-                    var destination = Path.Combine(directory, filename);
-
-                    _fileSystem.MoveFile(file, destination);
-                }
-            }
-        }
-
-        private List<string> GetOtherDuplicatePaths(string targetPath,
-            Series series,
-            int? seasonNumber,
-            int? episodeNumber,
-            int? endingEpisodeNumber)
-        {
-            // TODO: Support date-naming?
-            if (!seasonNumber.HasValue || !episodeNumber.HasValue)
-            {
-                return new List<string>();
-            }
-
-            var episodePaths = series.GetRecursiveChildren(i => i is Episode)
-                .OfType<Episode>()
-                .Where(i =>
-                {
-                    var locationType = i.LocationType;
-
-                    // Must be file system based and match exactly
-                    if (locationType != LocationType.Remote &&
-                        locationType != LocationType.Virtual &&
-                        i.ParentIndexNumber.HasValue &&
-                        i.ParentIndexNumber.Value == seasonNumber &&
-                        i.IndexNumber.HasValue &&
-                        i.IndexNumber.Value == episodeNumber)
-                    {
-
-                        if (endingEpisodeNumber.HasValue || i.IndexNumberEnd.HasValue)
-                        {
-                            return endingEpisodeNumber.HasValue && i.IndexNumberEnd.HasValue &&
-                                   endingEpisodeNumber.Value == i.IndexNumberEnd.Value;
-                        }
-
-                        return true;
-                    }
-
-                    return false;
-                })
-                .Select(i => i.Path)
-                .ToList();
-
-            var folder = _fileSystem.GetDirectoryName(targetPath);
-            var targetFileNameWithoutExtension = _fileSystem.GetFileNameWithoutExtension(targetPath);
-
-            try
-            {
-                var filesOfOtherExtensions = _fileSystem.GetFilePaths(folder)
-                    .Where(i => _libraryManager.IsVideoFile(i) && string.Equals(_fileSystem.GetFileNameWithoutExtension(i), targetFileNameWithoutExtension, StringComparison.OrdinalIgnoreCase));
-
-                episodePaths.AddRange(filesOfOtherExtensions);
-            }
-            catch (IOException)
-            {
-                // No big deal. Maybe the season folder doesn't already exist.
-            }
-
-            return episodePaths.Where(i => !string.Equals(i, targetPath, StringComparison.OrdinalIgnoreCase))
-                .Distinct(StringComparer.OrdinalIgnoreCase)
-                .ToList();
-        }
-
-        private void PerformFileSorting(TvFileOrganizationOptions options, FileOrganizationResult result)
-        {
-            // We should probably handle this earlier so that we never even make it this far
-            if (string.Equals(result.OriginalPath, result.TargetPath, StringComparison.OrdinalIgnoreCase))
-            {
-                return;
-            }
-
-            _libraryMonitor.ReportFileSystemChangeBeginning(result.TargetPath);
-
-            _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(result.TargetPath));
-
-            var targetAlreadyExists = _fileSystem.FileExists(result.TargetPath);
-
-            try
-            {
-                if (targetAlreadyExists || options.CopyOriginalFile)
-                {
-                    _fileSystem.CopyFile(result.OriginalPath, result.TargetPath, true);
-                }
-                else
-                {
-                    _fileSystem.MoveFile(result.OriginalPath, result.TargetPath);
-                }
-
-                result.Status = FileSortingStatus.Success;
-                result.StatusMessage = string.Empty;
-            }
-            catch (Exception ex)
-            {
-                var errorMsg = string.Format("Failed to move file from {0} to {1}: {2}", result.OriginalPath, result.TargetPath, ex.Message);
-
-                result.Status = FileSortingStatus.Failure;
-                result.StatusMessage = errorMsg;
-                _logger.ErrorException(errorMsg, ex);
-
-                return;
-            }
-            finally
-            {
-                _libraryMonitor.ReportFileSystemChangeComplete(result.TargetPath, true);
-            }
-
-            if (targetAlreadyExists && !options.CopyOriginalFile)
-            {
-                try
-                {
-                    _fileSystem.DeleteFile(result.OriginalPath);
-                }
-                catch (Exception ex)
-                {
-                    _logger.ErrorException("Error deleting {0}", ex, result.OriginalPath);
-                }
-            }
-        }
-
-        private Series GetMatchingSeries(string seriesName, FileOrganizationResult result, AutoOrganizeOptions options)
-        {
-            var parsedName = _libraryManager.ParseName(seriesName);
-
-            var yearInName = parsedName.Year;
-            var nameWithoutYear = parsedName.Name;
-
-            result.ExtractedName = nameWithoutYear;
-            result.ExtractedYear = yearInName;
-
-            var series = _libraryManager.GetItemList(new InternalItemsQuery
-            {
-                IncludeItemTypes = new[] { typeof(Series).Name },
-                Recursive = true,
-                DtoOptions = new DtoOptions(true)
-            })
-                .Cast<Series>()
-                .Select(i => NameUtils.GetMatchScore(nameWithoutYear, yearInName, i))
-                .Where(i => i.Item2 > 0)
-                .OrderByDescending(i => i.Item2)
-                .Select(i => i.Item1)
-                .FirstOrDefault();
-
-            if (series == null)
-            {
-                SmartMatchInfo info = options.SmartMatchInfos.FirstOrDefault(e => e.MatchStrings.Contains(nameWithoutYear, StringComparer.OrdinalIgnoreCase));
-
-                if (info != null)
-                {
-                    series = _libraryManager.GetItemList(new InternalItemsQuery
-                    {
-                        IncludeItemTypes = new[] { typeof(Series).Name },
-                        Recursive = true,
-                        Name = info.ItemName,
-                        DtoOptions = new DtoOptions(true)
-
-                    }).Cast<Series>().FirstOrDefault();
-                }
-            }
-
-            return series;
-        }
-
-        /// <summary>
-        /// Gets the new path.
-        /// </summary>
-        /// <param name="sourcePath">The source path.</param>
-        /// <param name="series">The series.</param>
-        /// <param name="seasonNumber">The season number.</param>
-        /// <param name="episodeNumber">The episode number.</param>
-        /// <param name="endingEpisodeNumber">The ending episode number.</param>
-        /// <param name="premiereDate">The premiere date.</param>
-        /// <param name="options">The options.</param>
-        /// <param name="cancellationToken">The cancellation token.</param>
-        /// <returns>System.String.</returns>
-        private async Task<string> GetNewPath(string sourcePath,
-            Series series,
-            int? seasonNumber,
-            int? episodeNumber,
-            int? endingEpisodeNumber,
-            DateTime? premiereDate,
-            TvFileOrganizationOptions options,
-            CancellationToken cancellationToken)
-        {
-            var episodeInfo = new EpisodeInfo
-            {
-                IndexNumber = episodeNumber,
-                IndexNumberEnd = endingEpisodeNumber,
-                MetadataCountryCode = series.GetPreferredMetadataCountryCode(),
-                MetadataLanguage = series.GetPreferredMetadataLanguage(),
-                ParentIndexNumber = seasonNumber,
-                SeriesProviderIds = series.ProviderIds,
-                PremiereDate = premiereDate
-            };
-
-            var searchResults = await _providerManager.GetRemoteSearchResults<Episode, EpisodeInfo>(new RemoteSearchQuery<EpisodeInfo>
-            {
-                SearchInfo = episodeInfo
-
-            }, cancellationToken).ConfigureAwait(false);
-
-            var episode = searchResults.FirstOrDefault();
-
-            if (episode == null)
-            {
-                var msg = string.Format("No provider metadata found for {0} season {1} episode {2}", series.Name, seasonNumber, episodeNumber);
-                _logger.Warn(msg);
-                throw new Exception(msg);
-            }
-
-            var episodeName = episode.Name;
-
-            //if (string.IsNullOrWhiteSpace(episodeName))
-            //{
-            //    var msg = string.Format("No provider metadata found for {0} season {1} episode {2}", series.Name, seasonNumber, episodeNumber);
-            //    _logger.Warn(msg);
-            //    return null;
-            //}
-
-            seasonNumber = seasonNumber ?? episode.ParentIndexNumber;
-            episodeNumber = episodeNumber ?? episode.IndexNumber;
-
-            var newPath = GetSeasonFolderPath(series, seasonNumber.Value, options);
-
-            var episodeFileName = GetEpisodeFileName(sourcePath, series.Name, seasonNumber.Value, episodeNumber.Value, endingEpisodeNumber, episodeName, options);
-
-            if (string.IsNullOrEmpty(episodeFileName))
-            {
-                // cause failure
-                return string.Empty;
-            }
-
-            newPath = Path.Combine(newPath, episodeFileName);
-
-            return newPath;
-        }
-
-        /// <summary>
-        /// Gets the season folder path.
-        /// </summary>
-        /// <param name="series">The series.</param>
-        /// <param name="seasonNumber">The season number.</param>
-        /// <param name="options">The options.</param>
-        /// <returns>System.String.</returns>
-        private string GetSeasonFolderPath(Series series, int seasonNumber, TvFileOrganizationOptions options)
-        {
-            // If there's already a season folder, use that
-            var season = series
-                .GetRecursiveChildren(i => i is Season && i.LocationType == LocationType.FileSystem && i.IndexNumber.HasValue && i.IndexNumber.Value == seasonNumber)
-                .FirstOrDefault();
-
-            if (season != null)
-            {
-                return season.Path;
-            }
-
-            var path = series.Path;
-
-            if (series.ContainsEpisodesWithoutSeasonFolders)
-            {
-                return path;
-            }
-
-            if (seasonNumber == 0)
-            {
-                return Path.Combine(path, _fileSystem.GetValidFilename(options.SeasonZeroFolderName));
-            }
-
-            var seasonFolderName = options.SeasonFolderPattern
-                .Replace("%s", seasonNumber.ToString(_usCulture))
-                .Replace("%0s", seasonNumber.ToString("00", _usCulture))
-                .Replace("%00s", seasonNumber.ToString("000", _usCulture));
-
-            return Path.Combine(path, _fileSystem.GetValidFilename(seasonFolderName));
-        }
-
-        private string GetEpisodeFileName(string sourcePath, string seriesName, int seasonNumber, int episodeNumber, int? endingEpisodeNumber, string episodeTitle, TvFileOrganizationOptions options)
-        {
-            seriesName = _fileSystem.GetValidFilename(seriesName).Trim();
-
-            if (string.IsNullOrWhiteSpace(episodeTitle))
-            {
-                episodeTitle = string.Empty;
-            }
-            else
-            {
-                episodeTitle = _fileSystem.GetValidFilename(episodeTitle).Trim();
-            }
-
-            var sourceExtension = (Path.GetExtension(sourcePath) ?? string.Empty).TrimStart('.');
-
-            var pattern = endingEpisodeNumber.HasValue ? options.MultiEpisodeNamePattern : options.EpisodeNamePattern;
-
-            if (string.IsNullOrWhiteSpace(pattern))
-            {
-                throw new Exception("GetEpisodeFileName: Configured episode name pattern is empty!");
-            }
-
-            var result = pattern.Replace("%sn", seriesName)
-                .Replace("%s.n", seriesName.Replace(" ", "."))
-                .Replace("%s_n", seriesName.Replace(" ", "_"))
-                .Replace("%s", seasonNumber.ToString(_usCulture))
-                .Replace("%0s", seasonNumber.ToString("00", _usCulture))
-                .Replace("%00s", seasonNumber.ToString("000", _usCulture))
-                .Replace("%ext", sourceExtension)
-                .Replace("%en", "%#1")
-                .Replace("%e.n", "%#2")
-                .Replace("%e_n", "%#3");
-
-            if (endingEpisodeNumber.HasValue)
-            {
-                result = result.Replace("%ed", endingEpisodeNumber.Value.ToString(_usCulture))
-                .Replace("%0ed", endingEpisodeNumber.Value.ToString("00", _usCulture))
-                .Replace("%00ed", endingEpisodeNumber.Value.ToString("000", _usCulture));
-            }
-
-            result = result.Replace("%e", episodeNumber.ToString(_usCulture))
-                .Replace("%0e", episodeNumber.ToString("00", _usCulture))
-                .Replace("%00e", episodeNumber.ToString("000", _usCulture));
-
-            if (result.Contains("%#"))
-            {
-                result = result.Replace("%#1", episodeTitle)
-                    .Replace("%#2", episodeTitle.Replace(" ", "."))
-                    .Replace("%#3", episodeTitle.Replace(" ", "_"));
-            }
-
-            // Finally, call GetValidFilename again in case user customized the episode expression with any invalid filename characters
-            return _fileSystem.GetValidFilename(result).Trim();
-        }
-
-        private bool IsSameEpisode(string sourcePath, string newPath)
-        {
-            try
-            {
-                var sourceFileInfo = _fileSystem.GetFileInfo(sourcePath);
-                var destinationFileInfo = _fileSystem.GetFileInfo(newPath);
-
-                if (sourceFileInfo.Length == destinationFileInfo.Length)
-                {
-                    return true;
-                }
-            }
-            catch (FileNotFoundException)
-            {
-                return false;
-            }
-            catch (IOException)
-            {
-                return false;
-            }
-
-            return false;
-        }
-    }
-}

+ 0 - 33
Emby.Server.Implementations/FileOrganization/Extensions.cs

@@ -1,33 +0,0 @@
-using MediaBrowser.Common.Configuration;
-using MediaBrowser.Model.FileOrganization;
-using System.Collections.Generic;
-
-namespace Emby.Server.Implementations.FileOrganization
-{
-    public static class ConfigurationExtension
-    {
-        public static AutoOrganizeOptions GetAutoOrganizeOptions(this IConfigurationManager manager)
-        {
-            return manager.GetConfiguration<AutoOrganizeOptions>("autoorganize");
-        }
-        public static void SaveAutoOrganizeOptions(this IConfigurationManager manager, AutoOrganizeOptions options)
-        {
-            manager.SaveConfiguration("autoorganize", options);
-        }
-    }
-
-    public class AutoOrganizeOptionsFactory : IConfigurationFactory
-    {
-        public IEnumerable<ConfigurationStore> GetConfigurations()
-        {
-            return new List<ConfigurationStore>
-            {
-                new ConfigurationStore
-                {
-                    Key = "autoorganize",
-                    ConfigurationType = typeof (AutoOrganizeOptions)
-                }
-            };
-        }
-    }
-}

+ 0 - 80
Emby.Server.Implementations/FileOrganization/FileOrganizationNotifier.cs

@@ -1,80 +0,0 @@
-using MediaBrowser.Controller.FileOrganization;
-using MediaBrowser.Controller.Plugins;
-using MediaBrowser.Controller.Session;
-using MediaBrowser.Model.Events;
-using MediaBrowser.Model.FileOrganization;
-using MediaBrowser.Model.Logging;
-using System;
-using System.Threading;
-using MediaBrowser.Model.Tasks;
-
-namespace Emby.Server.Implementations.FileOrganization
-{
-    /// <summary>
-    /// Class SessionInfoWebSocketListener
-    /// </summary>
-    class FileOrganizationNotifier : IServerEntryPoint
-    {
-        private readonly IFileOrganizationService _organizationService;
-        private readonly ISessionManager _sessionManager;
-        private readonly ITaskManager _taskManager;
-
-        public FileOrganizationNotifier(ILogger logger, IFileOrganizationService organizationService, ISessionManager sessionManager, ITaskManager taskManager)
-        {
-            _organizationService = organizationService;
-            _sessionManager = sessionManager;
-            _taskManager = taskManager;
-        }
-
-        public void Run()
-        {
-            _organizationService.ItemAdded += _organizationService_ItemAdded;
-            _organizationService.ItemRemoved += _organizationService_ItemRemoved;
-            _organizationService.ItemUpdated += _organizationService_ItemUpdated;
-            _organizationService.LogReset += _organizationService_LogReset;
-
-            //_taskManager.TaskCompleted += _taskManager_TaskCompleted;
-        }
-
-        private void _organizationService_LogReset(object sender, EventArgs e)
-        {
-            _sessionManager.SendMessageToAdminSessions("AutoOrganize_LogReset", (FileOrganizationResult)null, CancellationToken.None);
-        }
-
-        private void _organizationService_ItemUpdated(object sender, GenericEventArgs<FileOrganizationResult> e)
-        {
-            _sessionManager.SendMessageToAdminSessions("AutoOrganize_ItemUpdated", e.Argument, CancellationToken.None);
-        }
-
-        private void _organizationService_ItemRemoved(object sender, GenericEventArgs<FileOrganizationResult> e)
-        {
-            _sessionManager.SendMessageToAdminSessions("AutoOrganize_ItemRemoved", e.Argument, CancellationToken.None);
-        }
-
-        private void _organizationService_ItemAdded(object sender, GenericEventArgs<FileOrganizationResult> e)
-        {
-            _sessionManager.SendMessageToAdminSessions("AutoOrganize_ItemAdded", e.Argument, CancellationToken.None);
-        }
-
-        //private void _taskManager_TaskCompleted(object sender, TaskCompletionEventArgs e)
-        //{
-        //    var taskWithKey = e.Task.ScheduledTask as IHasKey;
-        //    if (taskWithKey != null && taskWithKey.Key == "AutoOrganize")
-        //    {
-        //        _sessionManager.SendMessageToAdminSessions("AutoOrganize_TaskCompleted", (FileOrganizationResult)null, CancellationToken.None);
-        //    }
-        //}
-
-        public void Dispose()
-        {
-            _organizationService.ItemAdded -= _organizationService_ItemAdded;
-            _organizationService.ItemRemoved -= _organizationService_ItemRemoved;
-            _organizationService.ItemUpdated -= _organizationService_ItemUpdated;
-            _organizationService.LogReset -= _organizationService_LogReset;
-
-            //_taskManager.TaskCompleted -= _taskManager_TaskCompleted;
-        }
-
-
-    }
-}

+ 0 - 283
Emby.Server.Implementations/FileOrganization/FileOrganizationService.cs

@@ -1,283 +0,0 @@
-using MediaBrowser.Common.Extensions;
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.FileOrganization;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.Net;
-using MediaBrowser.Controller.Persistence;
-using MediaBrowser.Controller.Providers;
-using MediaBrowser.Model.FileOrganization;
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Model.Querying;
-using System;
-using System.Collections.Concurrent;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Controller.Session;
-using MediaBrowser.Model.Events;
-using MediaBrowser.Common.Events;
-
-using MediaBrowser.Controller.IO;
-using MediaBrowser.Model.Tasks;
-
-namespace Emby.Server.Implementations.FileOrganization
-{
-    public class FileOrganizationService : IFileOrganizationService
-    {
-        private readonly ITaskManager _taskManager;
-        private readonly IFileOrganizationRepository _repo;
-        private readonly ILogger _logger;
-        private readonly ILibraryMonitor _libraryMonitor;
-        private readonly ILibraryManager _libraryManager;
-        private readonly IServerConfigurationManager _config;
-        private readonly IFileSystem _fileSystem;
-        private readonly IProviderManager _providerManager;
-        private readonly ConcurrentDictionary<string, bool> _inProgressItemIds = new ConcurrentDictionary<string, bool>();
-
-        public event EventHandler<GenericEventArgs<FileOrganizationResult>> ItemAdded;
-        public event EventHandler<GenericEventArgs<FileOrganizationResult>> ItemUpdated;
-        public event EventHandler<GenericEventArgs<FileOrganizationResult>> ItemRemoved;
-        public event EventHandler LogReset;
-
-        public FileOrganizationService(ITaskManager taskManager, IFileOrganizationRepository repo, ILogger logger, ILibraryMonitor libraryMonitor, ILibraryManager libraryManager, IServerConfigurationManager config, IFileSystem fileSystem, IProviderManager providerManager)
-        {
-            _taskManager = taskManager;
-            _repo = repo;
-            _logger = logger;
-            _libraryMonitor = libraryMonitor;
-            _libraryManager = libraryManager;
-            _config = config;
-            _fileSystem = fileSystem;
-            _providerManager = providerManager;
-        }
-
-        public void BeginProcessNewFiles()
-        {
-            _taskManager.CancelIfRunningAndQueue<OrganizerScheduledTask>();
-        }
-
-        public Task SaveResult(FileOrganizationResult result, CancellationToken cancellationToken)
-        {
-            if (result == null || string.IsNullOrEmpty(result.OriginalPath))
-            {
-                throw new ArgumentNullException("result");
-            }
-
-            result.Id = result.OriginalPath.GetMD5().ToString("N");
-
-            return _repo.SaveResult(result, cancellationToken);
-        }
-
-        public QueryResult<FileOrganizationResult> GetResults(FileOrganizationResultQuery query)
-        {
-            var results = _repo.GetResults(query);
-
-            foreach (var result in results.Items)
-            {
-                result.IsInProgress = _inProgressItemIds.ContainsKey(result.Id);
-            }
-
-            return results;
-        }
-
-        public FileOrganizationResult GetResult(string id)
-        {
-            var result = _repo.GetResult(id);
-
-            if (result != null)
-            {
-                result.IsInProgress = _inProgressItemIds.ContainsKey(result.Id);
-            }
-
-            return result;
-        }
-
-        public FileOrganizationResult GetResultBySourcePath(string path)
-        {
-            if (string.IsNullOrEmpty(path))
-            {
-                throw new ArgumentNullException("path");
-            }
-            
-            var id = path.GetMD5().ToString("N");
-
-            return GetResult(id);
-        }
-
-        public async Task DeleteOriginalFile(string resultId)
-        {
-            var result = _repo.GetResult(resultId);
-
-            _logger.Info("Requested to delete {0}", result.OriginalPath);
-
-            if (!AddToInProgressList(result, false))
-            {
-                throw new Exception("Path is currently processed otherwise. Please try again later.");
-            }
-
-            try
-            {
-                _fileSystem.DeleteFile(result.OriginalPath);
-            }
-            catch (Exception ex)
-            {
-                _logger.ErrorException("Error deleting {0}", ex, result.OriginalPath);
-            }
-            finally
-            {
-                RemoveFromInprogressList(result);
-            }
-
-            await _repo.Delete(resultId);
-
-            EventHelper.FireEventIfNotNull(ItemRemoved, this, new GenericEventArgs<FileOrganizationResult>(result), _logger);
-        }
-
-        private AutoOrganizeOptions GetAutoOrganizeOptions()
-        {
-            return _config.GetAutoOrganizeOptions();
-        }
-
-        public async Task PerformOrganization(string resultId)
-        {
-            var result = _repo.GetResult(resultId);
-
-            if (string.IsNullOrEmpty(result.TargetPath))
-            {
-                throw new ArgumentException("No target path available.");
-            }
-
-            var organizer = new EpisodeFileOrganizer(this, _config, _fileSystem, _logger, _libraryManager,
-                _libraryMonitor, _providerManager);
-
-            var organizeResult = await organizer.OrganizeEpisodeFile(result.OriginalPath, GetAutoOrganizeOptions(), true, CancellationToken.None)
-                    .ConfigureAwait(false);
-
-            if (organizeResult.Status != FileSortingStatus.Success)
-            {
-                throw new Exception(result.StatusMessage);
-            }
-        }
-
-        public async Task ClearLog()
-        {
-            await _repo.DeleteAll();
-            EventHelper.FireEventIfNotNull(LogReset, this, EventArgs.Empty, _logger);
-        }
-
-        public async Task PerformEpisodeOrganization(EpisodeFileOrganizationRequest request)
-        {
-            var organizer = new EpisodeFileOrganizer(this, _config, _fileSystem, _logger, _libraryManager,
-                _libraryMonitor, _providerManager);
-
-            var result = await organizer.OrganizeWithCorrection(request, GetAutoOrganizeOptions(), CancellationToken.None).ConfigureAwait(false);
-
-            if (result.Status != FileSortingStatus.Success)
-            {
-                throw new Exception(result.StatusMessage);
-            }
-        }
-
-        public QueryResult<SmartMatchInfo> GetSmartMatchInfos(FileOrganizationResultQuery query)
-        {
-            if (query == null)
-            {
-                throw new ArgumentNullException("query");
-            }
-
-            var options = GetAutoOrganizeOptions();
-
-            var items = options.SmartMatchInfos.Skip(query.StartIndex ?? 0).Take(query.Limit ?? Int32.MaxValue).ToArray();
-
-            return new QueryResult<SmartMatchInfo>()
-            {
-                Items = items,
-                TotalRecordCount = options.SmartMatchInfos.Length
-            };
-        }
-
-        public void DeleteSmartMatchEntry(string itemName, string matchString)
-        {
-            if (string.IsNullOrEmpty(itemName))
-            {
-                throw new ArgumentNullException("itemName");
-            }
-
-            if (string.IsNullOrEmpty(matchString))
-            {
-                throw new ArgumentNullException("matchString");
-            }
-
-            var options = GetAutoOrganizeOptions();
-
-            SmartMatchInfo info = options.SmartMatchInfos.FirstOrDefault(i => string.Equals(i.ItemName, itemName));
-
-            if (info != null && info.MatchStrings.Contains(matchString))
-            {
-                var list = info.MatchStrings.ToList();
-                list.Remove(matchString);
-                info.MatchStrings = list.ToArray();
-
-                if (info.MatchStrings.Length == 0)
-                {
-                    var infos = options.SmartMatchInfos.ToList();
-                    infos.Remove(info);
-                    options.SmartMatchInfos = infos.ToArray();
-                }
-
-                _config.SaveAutoOrganizeOptions(options);
-            }
-        }
-
-        /// <summary>
-        /// Attempts to add a an item to the list of currently processed items.
-        /// </summary>
-        /// <param name="result">The result item.</param>
-        /// <param name="isNewItem">Passing true will notify the client to reload all items, otherwise only a single item will be refreshed.</param>
-        /// <returns>True if the item was added, False if the item is already contained in the list.</returns>
-        public bool AddToInProgressList(FileOrganizationResult result, bool isNewItem)
-        {
-            if (string.IsNullOrWhiteSpace(result.Id))
-            {
-                result.Id = result.OriginalPath.GetMD5().ToString("N");
-            }
-
-            if (!_inProgressItemIds.TryAdd(result.Id, false))
-            {
-                return false;
-            }
-
-            result.IsInProgress = true;
-
-            if (isNewItem)
-            {
-                EventHelper.FireEventIfNotNull(ItemAdded, this, new GenericEventArgs<FileOrganizationResult>(result), _logger);
-            }
-            else
-            {
-                EventHelper.FireEventIfNotNull(ItemUpdated, this, new GenericEventArgs<FileOrganizationResult>(result), _logger);
-            }
-
-            return true;
-        }
-
-        /// <summary>
-        /// Removes an item from the list of currently processed items.
-        /// </summary>
-        /// <param name="result">The result item.</param>
-        /// <returns>True if the item was removed, False if the item was not contained in the list.</returns>
-        public bool RemoveFromInprogressList(FileOrganizationResult result)
-        {
-            bool itemValue;
-            var retval = _inProgressItemIds.TryRemove(result.Id, out itemValue);
-
-            result.IsInProgress = false;
-
-            EventHelper.FireEventIfNotNull(ItemUpdated, this, new GenericEventArgs<FileOrganizationResult>(result), _logger);
-
-            return retval;
-        }
-
-    }
-}

+ 0 - 81
Emby.Server.Implementations/FileOrganization/NameUtils.cs

@@ -1,81 +0,0 @@
-using MediaBrowser.Model.Extensions;
-using MediaBrowser.Controller.Entities;
-using System;
-using System.Globalization;
-using MediaBrowser.Controller.Extensions;
-
-namespace Emby.Server.Implementations.FileOrganization
-{
-    public static class NameUtils
-    {
-        private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
-
-        internal static Tuple<T, int> GetMatchScore<T>(string sortedName, int? year, T series)
-            where T : BaseItem
-        {
-            var score = 0;
-
-            var seriesNameWithoutYear = series.Name;
-            if (series.ProductionYear.HasValue)
-            {
-                seriesNameWithoutYear = seriesNameWithoutYear.Replace(series.ProductionYear.Value.ToString(UsCulture), String.Empty);
-            }
-
-            if (IsNameMatch(sortedName, seriesNameWithoutYear))
-            {
-                score++;
-
-                if (year.HasValue && series.ProductionYear.HasValue)
-                {
-                    if (year.Value == series.ProductionYear.Value)
-                    {
-                        score++;
-                    }
-                    else
-                    {
-                        // Regardless of name, return a 0 score if the years don't match
-                        return new Tuple<T, int>(series, 0);
-                    }
-                }
-            }
-
-            return new Tuple<T, int>(series, score);
-        }
-
-
-        private static bool IsNameMatch(string name1, string name2)
-        {
-            name1 = GetComparableName(name1);
-            name2 = GetComparableName(name2);
-
-            return String.Equals(name1, name2, StringComparison.OrdinalIgnoreCase);
-        }
-
-        private static string GetComparableName(string name)
-        {
-            name = name.RemoveDiacritics();
-
-            name = " " + name + " ";
-
-            name = name.Replace(".", " ")
-            .Replace("_", " ")
-            .Replace(" and ", " ")
-            .Replace(".and.", " ")
-            .Replace("&", " ")
-            .Replace("!", " ")
-            .Replace("(", " ")
-            .Replace(")", " ")
-            .Replace(":", " ")
-            .Replace(",", " ")
-            .Replace("-", " ")
-            .Replace("'", " ")
-            .Replace("[", " ")
-            .Replace("]", " ")
-            .Replace(" a ", String.Empty, StringComparison.OrdinalIgnoreCase)
-            .Replace(" the ", String.Empty, StringComparison.OrdinalIgnoreCase)
-            .Replace(" ", String.Empty);
-
-            return name.Trim();
-        }
-    }
-}

+ 0 - 101
Emby.Server.Implementations/FileOrganization/OrganizerScheduledTask.cs

@@ -1,101 +0,0 @@
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.FileOrganization;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.Providers;
-using MediaBrowser.Model.FileOrganization;
-using MediaBrowser.Model.Logging;
-using System;
-using System.Collections.Generic;
-using System.Threading;
-using System.Threading.Tasks;
-
-using MediaBrowser.Controller.IO;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Model.Tasks;
-
-namespace Emby.Server.Implementations.FileOrganization
-{
-    public class OrganizerScheduledTask : IScheduledTask, IConfigurableScheduledTask
-    {
-        private readonly ILibraryMonitor _libraryMonitor;
-        private readonly ILibraryManager _libraryManager;
-        private readonly ILogger _logger;
-        private readonly IFileSystem _fileSystem;
-        private readonly IServerConfigurationManager _config;
-        private readonly IFileOrganizationService _organizationService;
-        private readonly IProviderManager _providerManager;
-
-        public OrganizerScheduledTask(ILibraryMonitor libraryMonitor, ILibraryManager libraryManager, ILogger logger, IFileSystem fileSystem, IServerConfigurationManager config, IFileOrganizationService organizationService, IProviderManager providerManager)
-        {
-            _libraryMonitor = libraryMonitor;
-            _libraryManager = libraryManager;
-            _logger = logger;
-            _fileSystem = fileSystem;
-            _config = config;
-            _organizationService = organizationService;
-            _providerManager = providerManager;
-        }
-
-        public string Name
-        {
-            get { return "Organize new media files"; }
-        }
-
-        public string Description
-        {
-            get { return "Processes new files available in the configured watch folder."; }
-        }
-
-        public string Category
-        {
-            get { return "Library"; }
-        }
-
-        private AutoOrganizeOptions GetAutoOrganizeOptions()
-        {
-            return _config.GetAutoOrganizeOptions();
-        }
-
-        public async Task Execute(CancellationToken cancellationToken, IProgress<double> progress)
-        {
-            if (GetAutoOrganizeOptions().TvOptions.IsEnabled)
-            {
-                await new TvFolderOrganizer(_libraryManager, _logger, _fileSystem, _libraryMonitor, _organizationService, _config, _providerManager)
-                    .Organize(GetAutoOrganizeOptions(), cancellationToken, progress).ConfigureAwait(false);
-            }
-        }
-
-        /// <summary>
-        /// Creates the triggers that define when the task will run
-        /// </summary>
-        /// <returns>IEnumerable{BaseTaskTrigger}.</returns>
-        public IEnumerable<TaskTriggerInfo> GetDefaultTriggers()
-        {
-            return new[] { 
-            
-                // Every so often
-                new TaskTriggerInfo { Type = TaskTriggerInfo.TriggerInterval, IntervalTicks = TimeSpan.FromMinutes(5).Ticks}
-            };
-        }
-
-        public bool IsHidden
-        {
-            get { return !GetAutoOrganizeOptions().TvOptions.IsEnabled; }
-        }
-
-        public bool IsEnabled
-        {
-            get { return GetAutoOrganizeOptions().TvOptions.IsEnabled; }
-        }
-
-        public bool IsLogged
-        {
-            get { return false; }
-        }
-
-        public string Key
-        {
-            get { return "AutoOrganize"; }
-        }
-    }
-}

+ 0 - 236
Emby.Server.Implementations/FileOrganization/TvFolderOrganizer.cs

@@ -1,236 +0,0 @@
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.FileOrganization;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.Providers;
-using MediaBrowser.Model.FileOrganization;
-using MediaBrowser.Model.Logging;
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-
-using MediaBrowser.Controller.IO;
-using MediaBrowser.Model.IO;
-
-namespace Emby.Server.Implementations.FileOrganization
-{
-    public class TvFolderOrganizer
-    {
-        private readonly ILibraryMonitor _libraryMonitor;
-        private readonly ILibraryManager _libraryManager;
-        private readonly ILogger _logger;
-        private readonly IFileSystem _fileSystem;
-        private readonly IFileOrganizationService _organizationService;
-        private readonly IServerConfigurationManager _config;
-        private readonly IProviderManager _providerManager;
-
-        public TvFolderOrganizer(ILibraryManager libraryManager, ILogger logger, IFileSystem fileSystem, ILibraryMonitor libraryMonitor, IFileOrganizationService organizationService, IServerConfigurationManager config, IProviderManager providerManager)
-        {
-            _libraryManager = libraryManager;
-            _logger = logger;
-            _fileSystem = fileSystem;
-            _libraryMonitor = libraryMonitor;
-            _organizationService = organizationService;
-            _config = config;
-            _providerManager = providerManager;
-        }
-
-        private bool EnableOrganization(FileSystemMetadata fileInfo, TvFileOrganizationOptions options)
-        {
-            var minFileBytes = options.MinFileSizeMb * 1024 * 1024;
-
-            try
-            {
-                return _libraryManager.IsVideoFile(fileInfo.FullName) && fileInfo.Length >= minFileBytes;
-            }
-            catch (Exception ex)
-            {
-                _logger.ErrorException("Error organizing file {0}", ex, fileInfo.Name);
-            }
-
-            return false;
-        }
-
-        private bool IsValidWatchLocation(string path, List<string> libraryFolderPaths)
-        {
-            if (IsPathAlreadyInMediaLibrary(path, libraryFolderPaths))
-            {
-                _logger.Info("Folder {0} is not eligible for auto-organize because it is also part of an Emby library", path);
-                return false;
-            }
-
-            return true;
-        }
-
-        private bool IsPathAlreadyInMediaLibrary(string path, List<string> libraryFolderPaths)
-        {
-            return libraryFolderPaths.Any(i => string.Equals(i, path, StringComparison.Ordinal) || _fileSystem.ContainsSubPath(i, path));
-        }
-
-        public async Task Organize(AutoOrganizeOptions options, CancellationToken cancellationToken, IProgress<double> progress)
-        {
-            var libraryFolderPaths = _libraryManager.GetVirtualFolders().SelectMany(i => i.Locations).ToList();
-
-            var watchLocations = options.TvOptions.WatchLocations
-                .Where(i => IsValidWatchLocation(i, libraryFolderPaths))
-                .ToList();
-
-            var eligibleFiles = watchLocations.SelectMany(GetFilesToOrganize)
-                .OrderBy(_fileSystem.GetCreationTimeUtc)
-                .Where(i => EnableOrganization(i, options.TvOptions))
-                .ToList();
-
-            var processedFolders = new HashSet<string>();
-
-            progress.Report(10);
-
-            if (eligibleFiles.Count > 0)
-            {
-                var numComplete = 0;
-
-                foreach (var file in eligibleFiles)
-                {
-                    cancellationToken.ThrowIfCancellationRequested();
-
-                    var organizer = new EpisodeFileOrganizer(_organizationService, _config, _fileSystem, _logger, _libraryManager,
-                        _libraryMonitor, _providerManager);
-
-                    try
-                    {
-                        var result = await organizer.OrganizeEpisodeFile(file.FullName, options, options.TvOptions.OverwriteExistingEpisodes, cancellationToken).ConfigureAwait(false);
-
-                        if (result.Status == FileSortingStatus.Success && !processedFolders.Contains(file.DirectoryName, StringComparer.OrdinalIgnoreCase))
-                        {
-                            processedFolders.Add(file.DirectoryName);
-                        }
-                    }
-                    catch (OperationCanceledException)
-                    {
-                        break;
-                    }
-                    catch (Exception ex)
-                    {
-                        _logger.ErrorException("Error organizing episode {0}", ex, file.FullName);
-                    }
-
-                    numComplete++;
-                    double percent = numComplete;
-                    percent /= eligibleFiles.Count;
-
-                    progress.Report(10 + 89 * percent);
-                }
-            }
-
-            cancellationToken.ThrowIfCancellationRequested();
-            progress.Report(99);
-
-            foreach (var path in processedFolders)
-            {
-                var deleteExtensions = options.TvOptions.LeftOverFileExtensionsToDelete
-                    .Select(i => i.Trim().TrimStart('.'))
-                    .Where(i => !string.IsNullOrEmpty(i))
-                    .Select(i => "." + i)
-                    .ToList();
-
-                if (deleteExtensions.Count > 0)
-                {
-                    DeleteLeftOverFiles(path, deleteExtensions);
-                }
-
-                if (options.TvOptions.DeleteEmptyFolders)
-                {
-                    if (!IsWatchFolder(path, watchLocations))
-                    {
-                        DeleteEmptyFolders(path);
-                    }
-                }
-            }
-
-            progress.Report(100);
-        }
-
-        /// <summary>
-        /// Gets the files to organize.
-        /// </summary>
-        /// <param name="path">The path.</param>
-        /// <returns>IEnumerable{FileInfo}.</returns>
-        private List<FileSystemMetadata> GetFilesToOrganize(string path)
-        {
-            try
-            {
-                return _fileSystem.GetFiles(path, true)
-                    .ToList();
-            }
-            catch (IOException ex)
-            {
-                _logger.ErrorException("Error getting files from {0}", ex, path);
-
-                return new List<FileSystemMetadata>();
-            }
-        }
-
-        /// <summary>
-        /// Deletes the left over files.
-        /// </summary>
-        /// <param name="path">The path.</param>
-        /// <param name="extensions">The extensions.</param>
-        private void DeleteLeftOverFiles(string path, IEnumerable<string> extensions)
-        {
-            var eligibleFiles = _fileSystem.GetFilePaths(path, extensions.ToArray(), false, true)
-                .ToList();
-
-            foreach (var file in eligibleFiles)
-            {
-                try
-                {
-                    _fileSystem.DeleteFile(file);
-                }
-                catch (Exception ex)
-                {
-                    _logger.ErrorException("Error deleting file {0}", ex, file);
-                }
-            }
-        }
-
-        /// <summary>
-        /// Deletes the empty folders.
-        /// </summary>
-        /// <param name="path">The path.</param>
-        private void DeleteEmptyFolders(string path)
-        {
-            try
-            {
-                foreach (var d in _fileSystem.GetDirectoryPaths(path))
-                {
-                    DeleteEmptyFolders(d);
-                }
-
-                var entries = _fileSystem.GetFileSystemEntryPaths(path);
-
-                if (!entries.Any())
-                {
-                    try
-                    {
-                        _logger.Debug("Deleting empty directory {0}", path);
-                        _fileSystem.DeleteDirectory(path, false);
-                    }
-                    catch (UnauthorizedAccessException) { }
-                    catch (IOException) { }
-                }
-            }
-            catch (UnauthorizedAccessException) { }
-        }
-
-        /// <summary>
-        /// Determines if a given folder path is contained in a folder list
-        /// </summary>
-        /// <param name="path">The folder path to check.</param>
-        /// <param name="watchLocations">A list of folders.</param>
-        private bool IsWatchFolder(string path, IEnumerable<string> watchLocations)
-        {
-            return watchLocations.Contains(path, StringComparer.OrdinalIgnoreCase);
-        }
-    }
-}

+ 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)

+ 48 - 140
Emby.Server.Implementations/HttpServer/HttpResultFactory.cs

@@ -6,19 +6,16 @@ using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
 using System.Globalization;
 using System.Globalization;
 using System.IO;
 using System.IO;
-using System.IO.Compression;
 using System.Net;
 using System.Net;
 using System.Runtime.Serialization;
 using System.Runtime.Serialization;
 using System.Text;
 using System.Text;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
 using System.Xml;
 using System.Xml;
-using Emby.Server.Implementations.HttpServer;
 using Emby.Server.Implementations.Services;
 using Emby.Server.Implementations.Services;
 using MediaBrowser.Model.IO;
 using MediaBrowser.Model.IO;
 using MediaBrowser.Model.Services;
 using MediaBrowser.Model.Services;
 using IRequest = MediaBrowser.Model.Services.IRequest;
 using IRequest = MediaBrowser.Model.Services.IRequest;
 using MimeTypes = MediaBrowser.Model.Net.MimeTypes;
 using MimeTypes = MediaBrowser.Model.Net.MimeTypes;
-using StreamWriter = Emby.Server.Implementations.HttpServer.StreamWriter;
 
 
 namespace Emby.Server.Implementations.HttpServer
 namespace Emby.Server.Implementations.HttpServer
 {
 {
@@ -193,50 +190,37 @@ namespace Emby.Server.Implementations.HttpServer
         /// <returns></returns>
         /// <returns></returns>
         public object ToOptimizedResult<T>(IRequest request, T dto)
         public object ToOptimizedResult<T>(IRequest request, T dto)
         {
         {
-            var compressionType = GetCompressionType(request);
-            if (compressionType == null)
-            {
-                var contentType = request.ResponseContentType;
-
-                switch (GetRealContentType(contentType))
-                {
-                    case "application/xml":
-                    case "text/xml":
-                    case "text/xml; charset=utf-8": //"text/xml; charset=utf-8" also matches xml
-                        return SerializeToXmlString(dto);
-
-                    case "application/json":
-                    case "text/json":
-                        return _jsonSerializer.SerializeToString(dto);
-                }
-            }
+            var contentType = request.ResponseContentType;
 
 
-            // Do not use the memoryStreamFactory here, they don't place nice with compression
-            using (var ms = new MemoryStream())
+            switch (GetRealContentType(contentType))
             {
             {
-                var contentType = request.ResponseContentType;
-                var writerFn = RequestHelper.GetResponseWriter(HttpListenerHost.Instance, contentType);
+                case "application/xml":
+                case "text/xml":
+                case "text/xml; charset=utf-8": //"text/xml; charset=utf-8" also matches xml
+                    return SerializeToXmlString(dto);
 
 
-                writerFn(dto, ms);
+                case "application/json":
+                case "text/json":
+                    return _jsonSerializer.SerializeToString(dto);
+                default:
+                    {
+                        var ms = new MemoryStream();
+                        var writerFn = RequestHelper.GetResponseWriter(HttpListenerHost.Instance, contentType);
 
 
-                ms.Position = 0;
+                        writerFn(dto, ms);
+                        
+                        ms.Position = 0;
 
 
-                var responseHeaders = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
+                        if (string.Equals(request.Verb, "head", StringComparison.OrdinalIgnoreCase))
+                        {
+                            return GetHttpResult(new byte[] { }, contentType, true);
+                        }
 
 
-                return GetCompressedResult(ms, compressionType, responseHeaders, false, request.ResponseContentType).Result;
+                        return GetHttpResult(ms, contentType, true);
+                    }
             }
             }
         }
         }
 
 
-        private static Stream GetCompressionStream(Stream outputStream, string compressionType)
-        {
-            if (compressionType == "deflate")
-                return new DeflateStream(outputStream, CompressionMode.Compress, true);
-            if (compressionType == "gzip")
-                return new GZipStream(outputStream, CompressionMode.Compress, true);
-
-            throw new NotSupportedException(compressionType);
-        }
-
         public static string GetRealContentType(string contentType)
         public static string GetRealContentType(string contentType)
         {
         {
             return contentType == null
             return contentType == null
@@ -568,123 +552,47 @@ namespace Emby.Server.Implementations.HttpServer
             var contentType = options.ContentType;
             var contentType = options.ContentType;
             var responseHeaders = options.ResponseHeaders;
             var responseHeaders = options.ResponseHeaders;
 
 
-            var requestedCompressionType = GetCompressionType(requestContext);
+            //var requestedCompressionType = GetCompressionType(requestContext);
 
 
-            if (!compress || string.IsNullOrEmpty(requestedCompressionType))
-            {
-                var rangeHeader = requestContext.Headers.Get("Range");
-
-                if (!isHeadRequest && !string.IsNullOrWhiteSpace(options.Path))
-                {
-                    return new FileWriter(options.Path, contentType, rangeHeader, _logger, _fileSystem)
-                    {
-                        OnComplete = options.OnComplete,
-                        OnError = options.OnError,
-                        FileShare = options.FileShare
-                    };
-                }
-
-                if (!string.IsNullOrWhiteSpace(rangeHeader))
-                {
-                    var stream = await factoryFn().ConfigureAwait(false);
-
-                    return new RangeRequestWriter(rangeHeader, stream, contentType, isHeadRequest, _logger)
-                    {
-                        OnComplete = options.OnComplete
-                    };
-                }
-                else
-                {
-                    var stream = await factoryFn().ConfigureAwait(false);
-
-                    responseHeaders["Content-Length"] = stream.Length.ToString(UsCulture);
-
-                    if (isHeadRequest)
-                    {
-                        stream.Dispose();
-
-                        return GetHttpResult(new byte[] { }, contentType, true);
-                    }
-
-                    return new StreamWriter(stream, contentType, _logger)
-                    {
-                        OnComplete = options.OnComplete,
-                        OnError = options.OnError
-                    };
-                }
-            }
+            var rangeHeader = requestContext.Headers.Get("Range");
 
 
-            using (var stream = await factoryFn().ConfigureAwait(false))
+            if (!isHeadRequest && !string.IsNullOrWhiteSpace(options.Path))
             {
             {
-                return await GetCompressedResult(stream, requestedCompressionType, responseHeaders, isHeadRequest, contentType).ConfigureAwait(false);
+                return new FileWriter(options.Path, contentType, rangeHeader, _logger, _fileSystem)
+                {
+                    OnComplete = options.OnComplete,
+                    OnError = options.OnError,
+                    FileShare = options.FileShare
+                };
             }
             }
-        }
 
 
-        private async Task<IHasHeaders> GetCompressedResult(Stream stream,
-            string requestedCompressionType,
-            IDictionary<string, string> responseHeaders,
-            bool isHeadRequest,
-            string contentType)
-        {
-            using (var reader = new MemoryStream())
+            if (!string.IsNullOrWhiteSpace(rangeHeader))
             {
             {
-                await stream.CopyToAsync(reader).ConfigureAwait(false);
-
-                reader.Position = 0;
-                var content = reader.ToArray();
+                var stream = await factoryFn().ConfigureAwait(false);
 
 
-                if (content.Length >= 1024)
+                return new RangeRequestWriter(rangeHeader, stream, contentType, isHeadRequest, _logger)
                 {
                 {
-                    content = Compress(content, requestedCompressionType);
-                    responseHeaders["Content-Encoding"] = requestedCompressionType;
-                }
+                    OnComplete = options.OnComplete
+                };
+            }
+            else
+            {
+                var stream = await factoryFn().ConfigureAwait(false);
 
 
-                responseHeaders["Vary"] = "Accept-Encoding";
-                responseHeaders["Content-Length"] = content.Length.ToString(UsCulture);
+                responseHeaders["Content-Length"] = stream.Length.ToString(UsCulture);
 
 
                 if (isHeadRequest)
                 if (isHeadRequest)
                 {
                 {
+                    stream.Dispose();
+
                     return GetHttpResult(new byte[] { }, contentType, true);
                     return GetHttpResult(new byte[] { }, contentType, true);
                 }
                 }
 
 
-                return GetHttpResult(content, contentType, true, responseHeaders);
-            }
-        }
-
-        private byte[] Compress(byte[] bytes, string compressionType)
-        {
-            if (compressionType == "deflate")
-                return Deflate(bytes);
-
-            if (compressionType == "gzip")
-                return GZip(bytes);
-
-            throw new NotSupportedException(compressionType);
-        }
-
-        private byte[] Deflate(byte[] bytes)
-        {
-            // In .NET FX incompat-ville, you can't access compressed bytes without closing DeflateStream
-            // Which means we must use MemoryStream since you have to use ToArray() on a closed Stream
-            using (var ms = new MemoryStream())
-            using (var zipStream = new DeflateStream(ms, CompressionMode.Compress))
-            {
-                zipStream.Write(bytes, 0, bytes.Length);
-                zipStream.Dispose();
-
-                return ms.ToArray();
-            }
-        }
-
-        private byte[] GZip(byte[] buffer)
-        {
-            using (var ms = new MemoryStream())
-            using (var zipStream = new GZipStream(ms, CompressionMode.Compress))
-            {
-                zipStream.Write(buffer, 0, buffer.Length);
-                zipStream.Dispose();
-
-                return ms.ToArray();
+                return new StreamWriter(stream, contentType, _logger)
+                {
+                    OnComplete = options.OnComplete,
+                    OnError = options.OnError
+                };
             }
             }
         }
         }
 
 

+ 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

+ 0 - 92
Emby.Server.Implementations/IO/FileRefresher.cs

@@ -130,14 +130,6 @@ namespace Emby.Server.Implementations.IO
                 paths = _affectedPaths.ToList();
                 paths = _affectedPaths.ToList();
             }
             }
 
 
-            // Extend the timer as long as any of the paths are still being written to.
-            if (paths.Any(IsFileLocked))
-            {
-                Logger.Info("Timer extended.");
-                RestartTimer();
-                return;
-            }
-
             Logger.Debug("Timer stopped.");
             Logger.Debug("Timer stopped.");
 
 
             DisposeTimer();
             DisposeTimer();
@@ -229,90 +221,6 @@ namespace Emby.Server.Implementations.IO
             return item;
             return item;
         }
         }
 
 
-        private bool IsFileLocked(string path)
-        {
-            if (_environmentInfo.OperatingSystem != MediaBrowser.Model.System.OperatingSystem.Windows)
-            {
-                // Causing lockups on linux
-                return false;
-            }
-
-            // Only try to open video files
-            if (!_libraryManager.IsVideoFile(path))
-            {
-                return false;
-            }
-
-            try
-            {
-                var data = _fileSystem.GetFileSystemInfo(path);
-
-                if (!data.Exists
-                    || data.IsDirectory
-
-                    // Opening a writable stream will fail with readonly files
-                    || data.IsReadOnly)
-                {
-                    return false;
-                }
-            }
-            catch (IOException)
-            {
-                return false;
-            }
-            catch (Exception ex)
-            {
-                Logger.ErrorException("Error getting file system info for: {0}", ex, path);
-                return false;
-            }
-
-            // In order to determine if the file is being written to, we have to request write access
-            // But if the server only has readonly access, this is going to cause this entire algorithm to fail
-            // So we'll take a best guess about our access level
-            //var requestedFileAccess = ConfigurationManager.Configuration.SaveLocalMeta
-            //    ? FileAccessMode.ReadWrite
-            //    : FileAccessMode.Read;
-
-            var requestedFileAccess = FileAccessMode.Read;
-            try
-            {
-                using (_fileSystem.GetFileStream(path, FileOpenMode.Open, requestedFileAccess, FileShareMode.ReadWrite))
-                {
-                    //file is not locked
-                    return false;
-                }
-            }
-            catch (DirectoryNotFoundException)
-            {
-                // File may have been deleted
-                return false;
-            }
-            catch (FileNotFoundException)
-            {
-                // File may have been deleted
-                return false;
-            }
-            catch (UnauthorizedAccessException)
-            {
-                Logger.Debug("No write permission for: {0}.", path);
-                return false;
-            }
-            catch (IOException)
-            {
-                //the file is unavailable because it is:
-                //still being written to
-                //or being processed by another thread
-                //or does not exist (has already been processed)
-                Logger.Debug("{0} is locked.", path);
-                return true;
-            }
-            catch (Exception ex)
-            {
-                Logger.ErrorException("Error determining if file is locked: {0}", ex, path);
-                return false;
-            }
-        }
-
         private void DisposeTimer()
         private void DisposeTimer()
         {
         {
             lock (_timerLock)
             lock (_timerLock)

+ 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
     {
     {

+ 17 - 21
Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs

@@ -37,12 +37,12 @@ namespace Emby.Server.Implementations.Images
             ImageProcessor = imageProcessor;
             ImageProcessor = imageProcessor;
         }
         }
 
 
-        protected virtual bool Supports(IHasImages item)
+        protected virtual bool Supports(IHasMetadata item)
         {
         {
             return true;
             return true;
         }
         }
 
 
-        public virtual IEnumerable<ImageType> GetSupportedImages(IHasImages item)
+        public virtual IEnumerable<ImageType> GetSupportedImages(IHasMetadata item)
         {
         {
             return new List<ImageType>
             return new List<ImageType>
             {
             {
@@ -51,7 +51,7 @@ namespace Emby.Server.Implementations.Images
             };
             };
         }
         }
 
 
-        private IEnumerable<ImageType> GetEnabledImages(IHasImages item)
+        private IEnumerable<ImageType> GetEnabledImages(IHasMetadata item)
         {
         {
             //var options = ProviderManager.GetMetadataOptions(item);
             //var options = ProviderManager.GetMetadataOptions(item);
 
 
@@ -84,7 +84,7 @@ namespace Emby.Server.Implementations.Images
             return updateType;
             return updateType;
         }
         }
 
 
-        protected async Task<ItemUpdateType> FetchAsync(IHasImages item, ImageType imageType, MetadataRefreshOptions options, CancellationToken cancellationToken)
+        protected async Task<ItemUpdateType> FetchAsync(IHasMetadata item, ImageType imageType, MetadataRefreshOptions options, CancellationToken cancellationToken)
         {
         {
             var image = item.GetImageInfo(imageType, 0);
             var image = item.GetImageInfo(imageType, 0);
 
 
@@ -106,7 +106,7 @@ namespace Emby.Server.Implementations.Images
             return await FetchToFileInternal(item, items, imageType, cancellationToken).ConfigureAwait(false);
             return await FetchToFileInternal(item, items, imageType, cancellationToken).ConfigureAwait(false);
         }
         }
 
 
-        protected async Task<ItemUpdateType> FetchToFileInternal(IHasImages item,
+        protected async Task<ItemUpdateType> FetchToFileInternal(IHasMetadata item,
             List<BaseItem> itemsWithImages,
             List<BaseItem> itemsWithImages,
             ImageType imageType,
             ImageType imageType,
             CancellationToken cancellationToken)
             CancellationToken cancellationToken)
@@ -132,14 +132,14 @@ namespace Emby.Server.Implementations.Images
             return ItemUpdateType.ImageUpdate;
             return ItemUpdateType.ImageUpdate;
         }
         }
 
 
-        protected abstract List<BaseItem> GetItemsWithImages(IHasImages item);
+        protected abstract List<BaseItem> GetItemsWithImages(IHasMetadata item);
 
 
-        protected string CreateThumbCollage(IHasImages primaryItem, List<BaseItem> items, string outputPath)
+        protected string CreateThumbCollage(IHasMetadata primaryItem, List<BaseItem> items, string outputPath)
         {
         {
             return CreateCollage(primaryItem, items, outputPath, 640, 360);
             return CreateCollage(primaryItem, items, outputPath, 640, 360);
         }
         }
 
 
-        protected virtual IEnumerable<string> GetStripCollageImagePaths(IHasImages primaryItem, IEnumerable<BaseItem> items)
+        protected virtual IEnumerable<string> GetStripCollageImagePaths(IHasMetadata primaryItem, IEnumerable<BaseItem> items)
         {
         {
             return items
             return items
                 .Select(i =>
                 .Select(i =>
@@ -161,22 +161,22 @@ namespace Emby.Server.Implementations.Images
                 .Where(i => !string.IsNullOrWhiteSpace(i));
                 .Where(i => !string.IsNullOrWhiteSpace(i));
         }
         }
 
 
-        protected string CreatePosterCollage(IHasImages primaryItem, List<BaseItem> items, string outputPath)
+        protected string CreatePosterCollage(IHasMetadata primaryItem, List<BaseItem> items, string outputPath)
         {
         {
             return CreateCollage(primaryItem, items, outputPath, 400, 600);
             return CreateCollage(primaryItem, items, outputPath, 400, 600);
         }
         }
 
 
-        protected string CreateSquareCollage(IHasImages primaryItem, List<BaseItem> items, string outputPath)
+        protected string CreateSquareCollage(IHasMetadata primaryItem, List<BaseItem> items, string outputPath)
         {
         {
             return CreateCollage(primaryItem, items, outputPath, 600, 600);
             return CreateCollage(primaryItem, items, outputPath, 600, 600);
         }
         }
 
 
-        protected string CreateThumbCollage(IHasImages primaryItem, List<BaseItem> items, string outputPath, int width, int height)
+        protected string CreateThumbCollage(IHasMetadata primaryItem, List<BaseItem> items, string outputPath, int width, int height)
         {
         {
             return CreateCollage(primaryItem, items, outputPath, width, height);
             return CreateCollage(primaryItem, items, outputPath, width, height);
         }
         }
 
 
-        private string CreateCollage(IHasImages primaryItem, List<BaseItem> items, string outputPath, int width, int height)
+        private string CreateCollage(IHasMetadata primaryItem, List<BaseItem> items, string outputPath, int width, int height)
         {
         {
             FileSystem.CreateDirectory(FileSystem.GetDirectoryName(outputPath));
             FileSystem.CreateDirectory(FileSystem.GetDirectoryName(outputPath));
 
 
@@ -207,7 +207,7 @@ namespace Emby.Server.Implementations.Images
             get { return "Dynamic Image Provider"; }
             get { return "Dynamic Image Provider"; }
         }
         }
 
 
-        protected virtual string CreateImage(IHasImages item,
+        protected virtual string CreateImage(IHasMetadata item,
             List<BaseItem> itemsWithImages,
             List<BaseItem> itemsWithImages,
             string outputPathWithoutExtension,
             string outputPathWithoutExtension,
             ImageType imageType,
             ImageType imageType,
@@ -267,7 +267,7 @@ namespace Emby.Server.Implementations.Images
             return false;
             return false;
         }
         }
 
 
-        protected bool HasChanged(IHasImages item, ImageType type)
+        protected bool HasChanged(IHasMetadata item, ImageType type)
         {
         {
             var image = item.GetImageInfo(type, 0);
             var image = item.GetImageInfo(type, 0);
 
 
@@ -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();
         }
         }
 
 

+ 14 - 36
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)
         {
         {
@@ -1197,6 +1172,8 @@ namespace Emby.Server.Implementations.Library
                 progress.Report(percent * 100);
                 progress.Report(percent * 100);
             }
             }
 
 
+            await ItemRepository.UpdateInheritedValues(cancellationToken).ConfigureAwait(false);
+
             progress.Report(100);
             progress.Report(100);
         }
         }
 
 
@@ -1298,7 +1275,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 +1294,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 +1318,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 +1492,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)
             };
             };
         }
         }
 
 
@@ -2395,8 +2374,7 @@ namespace Emby.Server.Implementations.Library
             var resolver = new EpisodeResolver(GetNamingOptions(),
             var resolver = new EpisodeResolver(GetNamingOptions(),
                 new NullLogger());
                 new NullLogger());
 
 
-            var isFolder = episode.VideoType == VideoType.BluRay || episode.VideoType == VideoType.Dvd ||
-                           episode.VideoType == VideoType.HdDvd;
+            var isFolder = episode.VideoType == VideoType.BluRay || episode.VideoType == VideoType.Dvd;
 
 
             var locationType = episode.LocationType;
             var locationType = episode.LocationType;
 
 
@@ -2593,7 +2571,7 @@ namespace Emby.Server.Implementations.Library
         {
         {
             var namingOptions = GetNamingOptions();
             var namingOptions = GetNamingOptions();
 
 
-            var files = owner.DetectIsInMixedFolder() ? new List<FileSystemMetadata>() : fileSystemChildren.Where(i => i.IsDirectory)
+            var files = owner.IsInMixedFolder ? new List<FileSystemMetadata>() : fileSystemChildren.Where(i => i.IsDirectory)
                 .Where(i => string.Equals(i.Name, BaseItem.TrailerFolderName, StringComparison.OrdinalIgnoreCase))
                 .Where(i => string.Equals(i.Name, BaseItem.TrailerFolderName, StringComparison.OrdinalIgnoreCase))
                 .SelectMany(i => _fileSystem.GetFiles(i.FullName, _videoFileExtensions, false, false))
                 .SelectMany(i => _fileSystem.GetFiles(i.FullName, _videoFileExtensions, false, false))
                 .ToList();
                 .ToList();
@@ -2611,7 +2589,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)
@@ -2632,7 +2610,7 @@ namespace Emby.Server.Implementations.Library
                     return video;
                     return video;
 
 
                     // Sort them so that the list can be easily compared for changes
                     // Sort them so that the list can be easily compared for changes
-                }).OrderBy(i => i.Path).ToList();
+                }).OrderBy(i => i.Path);
         }
         }
 
 
         private static readonly string[] ExtrasSubfolderNames = new[] { "extras", "specials", "shorts", "scenes", "featurettes", "behind the scenes", "deleted scenes", "interviews" };
         private static readonly string[] ExtrasSubfolderNames = new[] { "extras", "specials", "shorts", "scenes", "featurettes", "behind the scenes", "deleted scenes", "interviews" };
@@ -2674,7 +2652,7 @@ namespace Emby.Server.Implementations.Library
                     return video;
                     return video;
 
 
                     // Sort them so that the list can be easily compared for changes
                     // Sort them so that the list can be easily compared for changes
-                }).OrderBy(i => i.Path).ToList();
+                }).OrderBy(i => i.Path);
         }
         }
 
 
         public string GetPathAfterNetworkSubstitution(string path, BaseItem ownerItem)
         public string GetPathAfterNetworkSubstitution(string path, BaseItem ownerItem)
@@ -2857,7 +2835,7 @@ namespace Emby.Server.Implementations.Library
             return ItemRepository.UpdatePeople(item.Id, people);
             return ItemRepository.UpdatePeople(item.Id, people);
         }
         }
 
 
-        public async Task<ItemImageInfo> ConvertImageToLocal(IHasImages item, ItemImageInfo image, int imageIndex)
+        public async Task<ItemImageInfo> ConvertImageToLocal(IHasMetadata item, ItemImageInfo image, int imageIndex)
         {
         {
             foreach (var url in image.Path.Split('|'))
             foreach (var url in image.Path.Split('|'))
             {
             {

+ 4 - 3
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)
             {
             {
@@ -90,7 +91,7 @@ namespace Emby.Server.Implementations.Library
             });
             });
 
 
             var trailerIds = trailers.Select(i => i.Id)
             var trailerIds = trailers.Select(i => i.Id)
-                .ToList();
+                .ToArray();
 
 
             if (!trailerIds.SequenceEqual(item.RemoteTrailerIds))
             if (!trailerIds.SequenceEqual(item.RemoteTrailerIds))
             {
             {

+ 7 - 8
Emby.Server.Implementations/Library/MediaSourceManager.cs

@@ -49,10 +49,9 @@ namespace Emby.Server.Implementations.Library
             _providers = providers.ToArray();
             _providers = providers.ToArray();
         }
         }
 
 
-        public IEnumerable<MediaStream> GetMediaStreams(MediaStreamQuery query)
+        public List<MediaStream> GetMediaStreams(MediaStreamQuery query)
         {
         {
-            var list = _itemRepo.GetMediaStreams(query)
-                .ToList();
+            var list = _itemRepo.GetMediaStreams(query);
 
 
             foreach (var stream in list)
             foreach (var stream in list)
             {
             {
@@ -77,7 +76,7 @@ namespace Emby.Server.Implementations.Library
             return false;
             return false;
         }
         }
 
 
-        public IEnumerable<MediaStream> GetMediaStreams(string mediaSourceId)
+        public List<MediaStream> GetMediaStreams(string mediaSourceId)
         {
         {
             var list = GetMediaStreams(new MediaStreamQuery
             var list = GetMediaStreams(new MediaStreamQuery
             {
             {
@@ -87,7 +86,7 @@ namespace Emby.Server.Implementations.Library
             return GetMediaStreamsForItem(list);
             return GetMediaStreamsForItem(list);
         }
         }
 
 
-        public IEnumerable<MediaStream> GetMediaStreams(Guid itemId)
+        public List<MediaStream> GetMediaStreams(Guid itemId)
         {
         {
             var list = GetMediaStreams(new MediaStreamQuery
             var list = GetMediaStreams(new MediaStreamQuery
             {
             {
@@ -97,7 +96,7 @@ namespace Emby.Server.Implementations.Library
             return GetMediaStreamsForItem(list);
             return GetMediaStreamsForItem(list);
         }
         }
 
 
-        private IEnumerable<MediaStream> GetMediaStreamsForItem(IEnumerable<MediaStream> streams)
+        private List<MediaStream> GetMediaStreamsForItem(IEnumerable<MediaStream> streams)
         {
         {
             var list = streams.ToList();
             var list = streams.ToList();
 
 
@@ -253,7 +252,7 @@ namespace Emby.Server.Implementations.Library
             return sources.FirstOrDefault(i => string.Equals(i.Id, mediaSourceId, StringComparison.OrdinalIgnoreCase));
             return sources.FirstOrDefault(i => string.Equals(i.Id, mediaSourceId, StringComparison.OrdinalIgnoreCase));
         }
         }
 
 
-        public IEnumerable<MediaSourceInfo> GetStaticMediaSources(IHasMediaSources item, bool enablePathSubstitution, User user = null)
+        public List<MediaSourceInfo> GetStaticMediaSources(IHasMediaSources item, bool enablePathSubstitution, User user = null)
         {
         {
             if (item == null)
             if (item == null)
             {
             {
@@ -265,7 +264,7 @@ namespace Emby.Server.Implementations.Library
                 return item.GetMediaSources(enablePathSubstitution);
                 return item.GetMediaSources(enablePathSubstitution);
             }
             }
 
 
-            var sources = item.GetMediaSources(enablePathSubstitution).ToList();
+            var sources = item.GetMediaSources(enablePathSubstitution);
 
 
             if (user != null)
             if (user != null)
             {
             {

+ 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>();
         }
         }
     }
     }
 }
 }

+ 12 - 8
Emby.Server.Implementations/Library/ResolverHelper.cs

@@ -46,7 +46,7 @@ namespace Emby.Server.Implementations.Library
             var fileInfo = directoryService.GetFile(item.Path);
             var fileInfo = directoryService.GetFile(item.Path);
             SetDateCreated(item, fileSystem, fileInfo);
             SetDateCreated(item, fileSystem, fileInfo);
 
 
-            EnsureName(item, fileInfo);
+            EnsureName(item, item.Path, fileInfo);
         }
         }
 
 
         /// <summary>
         /// <summary>
@@ -73,7 +73,7 @@ namespace Emby.Server.Implementations.Library
             item.Id = libraryManager.GetNewItemId(item.Path, item.GetType());
             item.Id = libraryManager.GetNewItemId(item.Path, item.GetType());
 
 
             // Make sure the item has a name
             // Make sure the item has a name
-            EnsureName(item, args.FileInfo);
+            EnsureName(item, item.Path, args.FileInfo);
 
 
             item.IsLocked = item.Path.IndexOf("[dontfetchmeta]", StringComparison.OrdinalIgnoreCase) != -1 ||
             item.IsLocked = item.Path.IndexOf("[dontfetchmeta]", StringComparison.OrdinalIgnoreCase) != -1 ||
                 item.GetParents().Any(i => i.IsLocked);
                 item.GetParents().Any(i => i.IsLocked);
@@ -85,14 +85,14 @@ namespace Emby.Server.Implementations.Library
         /// <summary>
         /// <summary>
         /// Ensures the name.
         /// Ensures the name.
         /// </summary>
         /// </summary>
-        /// <param name="item">The item.</param>
-        /// <param name="fileInfo">The file information.</param>
-        private static void EnsureName(BaseItem item, FileSystemMetadata fileInfo)
+        private static void EnsureName(BaseItem item, string fullPath, FileSystemMetadata fileInfo)
         {
         {
             // If the subclass didn't supply a name, add it here
             // If the subclass didn't supply a name, add it here
-            if (string.IsNullOrEmpty(item.Name) && !string.IsNullOrEmpty(item.Path))
+            if (string.IsNullOrEmpty(item.Name) && !string.IsNullOrEmpty(fullPath))
             {
             {
-                item.Name = GetDisplayName(fileInfo.Name, fileInfo.IsDirectory);
+                var fileName = fileInfo == null ? Path.GetFileName(fullPath) : fileInfo.Name;
+
+                item.Name = GetDisplayName(fileName, fileInfo != null && fileInfo.IsDirectory);
             }
             }
         }
         }
 
 
@@ -170,7 +170,11 @@ namespace Emby.Server.Implementations.Library
 
 
             if (config.UseFileCreationTimeForDateAdded)
             if (config.UseFileCreationTimeForDateAdded)
             {
             {
-                item.DateCreated = fileSystem.GetCreationTimeUtc(info);
+                // directoryService.getFile may return null
+                if (info != null)
+                {
+                    item.DateCreated = fileSystem.GetCreationTimeUtc(info);
+                }
             }
             }
             else
             else
             {
             {

+ 5 - 7
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;
         }
         }
 
 
@@ -178,11 +181,6 @@ namespace Emby.Server.Implementations.Library.Resolvers
                 {
                 {
                     video.VideoType = VideoType.Dvd;
                     video.VideoType = VideoType.Dvd;
                 }
                 }
-                else if (string.Equals(videoInfo.StubType, "hddvd", StringComparison.OrdinalIgnoreCase))
-                {
-                    video.VideoType = VideoType.HdDvd;
-                    video.IsHD = true;
-                }
                 else if (string.Equals(videoInfo.StubType, "bluray", StringComparison.OrdinalIgnoreCase))
                 else if (string.Equals(videoInfo.StubType, "bluray", StringComparison.OrdinalIgnoreCase))
                 {
                 {
                     video.VideoType = VideoType.BluRay;
                     video.VideoType = VideoType.BluRay;
@@ -276,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>

+ 9 - 11
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>
@@ -74,7 +69,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
 
 
             if (string.Equals(collectionType, CollectionType.MusicVideos, StringComparison.OrdinalIgnoreCase))
             if (string.Equals(collectionType, CollectionType.MusicVideos, StringComparison.OrdinalIgnoreCase))
             {
             {
-                return ResolveVideos<MusicVideo>(parent, files, directoryService, false, collectionType);
+                return ResolveVideos<MusicVideo>(parent, files, directoryService, true, collectionType);
             }
             }
 
 
             if (string.Equals(collectionType, CollectionType.HomeVideos, StringComparison.OrdinalIgnoreCase) ||
             if (string.Equals(collectionType, CollectionType.HomeVideos, StringComparison.OrdinalIgnoreCase) ||
@@ -164,8 +159,8 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
                     IsInMixedFolder = isInMixedFolder,
                     IsInMixedFolder = isInMixedFolder,
                     ProductionYear = video.Year,
                     ProductionYear = video.Year,
                     Name = video.Name,
                     Name = video.Name,
-                    AdditionalParts = video.Files.Skip(1).Select(i => i.Path).ToList(),
-                    LocalAlternateVersions = video.AlternateVersions.Select(i => i.Path).ToList()
+                    AdditionalParts = video.Files.Skip(1).Select(i => i.Path).ToArray(),
+                    LocalAlternateVersions = video.AlternateVersions.Select(i => i.Path).ToArray()
                 };
                 };
 
 
                 SetVideoType(videoItem, firstVideo);
                 SetVideoType(videoItem, firstVideo);
@@ -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)
@@ -509,7 +503,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
             {
             {
                 Path = folderPaths[0],
                 Path = folderPaths[0],
 
 
-                AdditionalParts = folderPaths.Skip(1).ToList(),
+                AdditionalParts = folderPaths.Skip(1).ToArray(),
 
 
                 VideoType = videoTypes[0],
                 VideoType = videoTypes[0],
 
 
@@ -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),

+ 1 - 1
Emby.Server.Implementations/Library/UserManager.cs

@@ -122,7 +122,7 @@ namespace Emby.Server.Implementations.Library
         /// <param name="user">The user.</param>
         /// <param name="user">The user.</param>
         private void OnUserDeleted(User user)
         private void OnUserDeleted(User user)
         {
         {
-            EventHelper.QueueEventIfNotNull(UserDeleted, this, new GenericEventArgs<User> { Argument = user }, _logger);
+            EventHelper.FireEventIfNotNull(UserDeleted, this, new GenericEventArgs<User> { Argument = user }, _logger);
         }
         }
         #endregion
         #endregion
 
 

+ 39 - 3
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;
 
 
@@ -269,7 +270,41 @@ namespace Emby.Server.Implementations.Library
                 return new List<BaseItem>();
                 return new List<BaseItem>();
             }
             }
 
 
-            var excludeItemTypes = includeItemTypes.Length == 0 ? new[]
+            var mediaTypes = new List<string>();
+
+            if (includeItemTypes.Length == 0)
+            {
+                foreach (var parent in parents.OfType<ICollectionFolder>())
+                {
+                    switch (parent.CollectionType)
+                    {
+                        case CollectionType.Books:
+                            mediaTypes.Add(MediaType.Book);
+                            break;
+                        case CollectionType.Games:
+                            mediaTypes.Add(MediaType.Game);
+                            break;
+                        case CollectionType.Music:
+                            mediaTypes.Add(MediaType.Audio);
+                            break;
+                        case CollectionType.Photos:
+                            mediaTypes.Add(MediaType.Photo);
+                            mediaTypes.Add(MediaType.Video);
+                            break;
+                        case CollectionType.HomeVideos:
+                            mediaTypes.Add(MediaType.Photo);
+                            mediaTypes.Add(MediaType.Video);
+                            break;
+                        default:
+                            mediaTypes.Add(MediaType.Video);
+                            break;
+                    }
+                }
+
+                mediaTypes = mediaTypes.Distinct().ToList();
+            }
+
+            var excludeItemTypes = includeItemTypes.Length == 0 && mediaTypes.Count == 0 ? new[]
             {
             {
                 typeof(Person).Name,
                 typeof(Person).Name,
                 typeof(Studio).Name,
                 typeof(Studio).Name,
@@ -290,7 +325,8 @@ namespace Emby.Server.Implementations.Library
                 IsVirtualItem = false,
                 IsVirtualItem = false,
                 Limit = limit * 5,
                 Limit = limit * 5,
                 IsPlayed = isPlayed,
                 IsPlayed = isPlayed,
-                DtoOptions = options
+                DtoOptions = options,
+                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)
                     {
                     {

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

@@ -28,12 +28,12 @@ namespace Emby.Server.Implementations.LiveTv
             _appHost = appHost;
             _appHost = appHost;
         }
         }
 
 
-        public IEnumerable<ImageType> GetSupportedImages(IHasImages item)
+        public IEnumerable<ImageType> GetSupportedImages(IHasMetadata item)
         {
         {
             return new[] { ImageType.Primary };
             return new[] { ImageType.Primary };
         }
         }
 
 
-        public async Task<DynamicImageResponse> GetImage(IHasImages item, ImageType type, CancellationToken cancellationToken)
+        public async Task<DynamicImageResponse> GetImage(IHasMetadata item, ImageType type, CancellationToken cancellationToken)
         {
         {
             var liveTvItem = (LiveTvChannel)item;
             var liveTvItem = (LiveTvChannel)item;
 
 
@@ -67,7 +67,7 @@ namespace Emby.Server.Implementations.LiveTv
             get { return "Live TV Service Provider"; }
             get { return "Live TV Service Provider"; }
         }
         }
 
 
-        public bool Supports(IHasImages item)
+        public bool Supports(IHasMetadata item)
         {
         {
             return item is LiveTvChannel;
             return item is LiveTvChannel;
         }
         }

+ 2 - 7
Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs

@@ -4,7 +4,6 @@ using MediaBrowser.Common.Net;
 using MediaBrowser.Common.Security;
 using MediaBrowser.Common.Security;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Drawing;
 using MediaBrowser.Controller.Drawing;
-using MediaBrowser.Controller.FileOrganization;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.LiveTv;
 using MediaBrowser.Controller.LiveTv;
 using MediaBrowser.Controller.MediaEncoding;
 using MediaBrowser.Controller.MediaEncoding;
@@ -36,7 +35,6 @@ using MediaBrowser.Controller.Entities.TV;
 using MediaBrowser.Controller.IO;
 using MediaBrowser.Controller.IO;
 using MediaBrowser.Model.Configuration;
 using MediaBrowser.Model.Configuration;
 using MediaBrowser.Model.Diagnostics;
 using MediaBrowser.Model.Diagnostics;
-using MediaBrowser.Model.FileOrganization;
 using MediaBrowser.Model.System;
 using MediaBrowser.Model.System;
 using MediaBrowser.Model.Threading;
 using MediaBrowser.Model.Threading;
 using MediaBrowser.Model.Extensions;
 using MediaBrowser.Model.Extensions;
@@ -61,7 +59,6 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
         private readonly ILibraryMonitor _libraryMonitor;
         private readonly ILibraryMonitor _libraryMonitor;
         private readonly ILibraryManager _libraryManager;
         private readonly ILibraryManager _libraryManager;
         private readonly IProviderManager _providerManager;
         private readonly IProviderManager _providerManager;
-        private readonly IFileOrganizationService _organizationService;
         private readonly IMediaEncoder _mediaEncoder;
         private readonly IMediaEncoder _mediaEncoder;
         private readonly IProcessFactory _processFactory;
         private readonly IProcessFactory _processFactory;
         private readonly ISystemEvents _systemEvents;
         private readonly ISystemEvents _systemEvents;
@@ -74,7 +71,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
         private readonly ConcurrentDictionary<string, ActiveRecordingInfo> _activeRecordings =
         private readonly ConcurrentDictionary<string, ActiveRecordingInfo> _activeRecordings =
             new ConcurrentDictionary<string, ActiveRecordingInfo>(StringComparer.OrdinalIgnoreCase);
             new ConcurrentDictionary<string, ActiveRecordingInfo>(StringComparer.OrdinalIgnoreCase);
 
 
-        public EmbyTV(IServerApplicationHost appHost, ILogger logger, IJsonSerializer jsonSerializer, IHttpClient httpClient, IServerConfigurationManager config, ILiveTvManager liveTvManager, IFileSystem fileSystem, ILibraryManager libraryManager, ILibraryMonitor libraryMonitor, IProviderManager providerManager, IFileOrganizationService organizationService, IMediaEncoder mediaEncoder, ITimerFactory timerFactory, IProcessFactory processFactory, ISystemEvents systemEvents)
+        public EmbyTV(IServerApplicationHost appHost, ILogger logger, IJsonSerializer jsonSerializer, IHttpClient httpClient, IServerConfigurationManager config, ILiveTvManager liveTvManager, IFileSystem fileSystem, ILibraryManager libraryManager, ILibraryMonitor libraryMonitor, IProviderManager providerManager, IMediaEncoder mediaEncoder, ITimerFactory timerFactory, IProcessFactory processFactory, ISystemEvents systemEvents)
         {
         {
             Current = this;
             Current = this;
 
 
@@ -86,7 +83,6 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
             _libraryManager = libraryManager;
             _libraryManager = libraryManager;
             _libraryMonitor = libraryMonitor;
             _libraryMonitor = libraryMonitor;
             _providerManager = providerManager;
             _providerManager = providerManager;
-            _organizationService = organizationService;
             _mediaEncoder = mediaEncoder;
             _mediaEncoder = mediaEncoder;
             _processFactory = processFactory;
             _processFactory = processFactory;
             _systemEvents = systemEvents;
             _systemEvents = systemEvents;
@@ -1636,7 +1632,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
                     return;
                     return;
                 }
                 }
 
 
-                var episodesToDelete = (librarySeries.GetItems(new InternalItemsQuery
+                var episodesToDelete = (librarySeries.GetItemList(new InternalItemsQuery
                 {
                 {
                     SortBy = new[] { ItemSortBy.DateCreated },
                     SortBy = new[] { ItemSortBy.DateCreated },
                     SortOrder = SortOrder.Descending,
                     SortOrder = SortOrder.Descending,
@@ -1646,7 +1642,6 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
                     DtoOptions = new DtoOptions(true)
                     DtoOptions = new DtoOptions(true)
 
 
                 }))
                 }))
-                    .Items
                     .Where(i => i.LocationType == LocationType.FileSystem && _fileSystem.FileExists(i.Path))
                     .Where(i => i.LocationType == LocationType.FileSystem && _fileSystem.FileExists(i.Path))
                     .Skip(seriesTimer.KeepUpTo - 1)
                     .Skip(seriesTimer.KeepUpTo - 1)
                     .ToList();
                     .ToList();

+ 6 - 3
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";
             }
             }
         }
         }
 
 
@@ -207,9 +207,12 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
                 inputModifier += " -fflags " + string.Join("", flags.ToArray());
                 inputModifier += " -fflags " + string.Join("", flags.ToArray());
             }
             }
 
 
-            if (!string.IsNullOrWhiteSpace(GetEncodingOptions().HardwareAccelerationType))
+            var videoStream = mediaSource.VideoStream;
+            var videoDecoder = videoStream == null ? null : new EncodingHelper(_mediaEncoder, _fileSystem, null).GetVideoDecoder(VideoType.VideoFile, videoStream, GetEncodingOptions());
+
+            if (!string.IsNullOrWhiteSpace(videoDecoder))
             {
             {
-                inputModifier += " -hwaccel auto";
+                inputModifier += " " + videoDecoder;
             }
             }
 
 
             if (mediaSource.ReadAtNativeFramerate)
             if (mediaSource.ReadAtNativeFramerate)

+ 4 - 4
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)
                             };
                             };
@@ -406,7 +406,7 @@ namespace Emby.Server.Implementations.LiveTv
             return dto;
             return dto;
         }
         }
 
 
-        internal string GetImageTag(IHasImages info)
+        internal string GetImageTag(IHasMetadata info)
         {
         {
             try
             try
             {
             {

+ 44 - 35
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>
             {
             {
@@ -1845,6 +1844,9 @@ namespace Emby.Server.Implementations.LiveTv
         public async Task AddInfoToProgramDto(List<Tuple<BaseItem, BaseItemDto>> tuples, List<ItemFields> fields, User user = null)
         public async Task AddInfoToProgramDto(List<Tuple<BaseItem, BaseItemDto>> tuples, List<ItemFields> fields, User user = null)
         {
         {
             var programTuples = new List<Tuple<BaseItemDto, string, string, string>>();
             var programTuples = new List<Tuple<BaseItemDto, string, string, string>>();
+            var hasChannelImage = fields.Contains(ItemFields.ChannelImage);
+            var hasChannelInfo = fields.Contains(ItemFields.ChannelInfo);
+            var hasServiceName = fields.Contains(ItemFields.ServiceName);
 
 
             foreach (var tuple in tuples)
             foreach (var tuple in tuples)
             {
             {
@@ -1887,7 +1889,7 @@ namespace Emby.Server.Implementations.LiveTv
                     dto.IsPremiere = program.IsPremiere;
                     dto.IsPremiere = program.IsPremiere;
                 }
                 }
 
 
-                if (fields.Contains(ItemFields.ChannelInfo))
+                if (hasChannelInfo || hasChannelImage)
                 {
                 {
                     var channel = GetInternalChannel(program.ChannelId);
                     var channel = GetInternalChannel(program.ChannelId);
 
 
@@ -1897,7 +1899,7 @@ namespace Emby.Server.Implementations.LiveTv
                         dto.MediaType = channel.MediaType;
                         dto.MediaType = channel.MediaType;
                         dto.ChannelNumber = channel.Number;
                         dto.ChannelNumber = channel.Number;
 
 
-                        if (channel.HasImage(ImageType.Primary))
+                        if (hasChannelImage && channel.HasImage(ImageType.Primary))
                         {
                         {
                             dto.ChannelPrimaryImageTag = _tvDtoService.GetImageTag(channel);
                             dto.ChannelPrimaryImageTag = _tvDtoService.GetImageTag(channel);
                         }
                         }
@@ -1906,7 +1908,7 @@ namespace Emby.Server.Implementations.LiveTv
 
 
                 var serviceName = program.ServiceName;
                 var serviceName = program.ServiceName;
 
 
-                if (fields.Contains(ItemFields.ServiceName))
+                if (hasServiceName)
                 {
                 {
                     dto.ServiceName = serviceName;
                     dto.ServiceName = serviceName;
                 }
                 }
@@ -1954,7 +1956,7 @@ namespace Emby.Server.Implementations.LiveTv
 
 
             if (dto.MediaSources == null)
             if (dto.MediaSources == null)
             {
             {
-                dto.MediaSources = recording.GetMediaSources(true).ToList();
+                dto.MediaSources = recording.GetMediaSources(true);
             }
             }
 
 
             if (dto.MediaStreams == null)
             if (dto.MediaStreams == null)
@@ -1993,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>
             {
             {
@@ -2081,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>
             {
             {
@@ -2154,7 +2158,7 @@ namespace Emby.Server.Implementations.LiveTv
             await service.CancelTimerAsync(timer.ExternalId, CancellationToken.None).ConfigureAwait(false);
             await service.CancelTimerAsync(timer.ExternalId, CancellationToken.None).ConfigureAwait(false);
             _lastRecordingRefreshTime = DateTime.MinValue;
             _lastRecordingRefreshTime = DateTime.MinValue;
 
 
-            EventHelper.QueueEventIfNotNull(TimerCancelled, this, new GenericEventArgs<TimerEventInfo>
+            EventHelper.FireEventIfNotNull(TimerCancelled, this, new GenericEventArgs<TimerEventInfo>
             {
             {
                 Argument = new TimerEventInfo
                 Argument = new TimerEventInfo
                 {
                 {
@@ -2177,7 +2181,7 @@ namespace Emby.Server.Implementations.LiveTv
             await service.CancelSeriesTimerAsync(timer.ExternalId, CancellationToken.None).ConfigureAwait(false);
             await service.CancelSeriesTimerAsync(timer.ExternalId, CancellationToken.None).ConfigureAwait(false);
             _lastRecordingRefreshTime = DateTime.MinValue;
             _lastRecordingRefreshTime = DateTime.MinValue;
 
 
-            EventHelper.QueueEventIfNotNull(SeriesTimerCancelled, this, new GenericEventArgs<TimerEventInfo>
+            EventHelper.FireEventIfNotNull(SeriesTimerCancelled, this, new GenericEventArgs<TimerEventInfo>
             {
             {
                 Argument = new TimerEventInfo
                 Argument = new TimerEventInfo
                 {
                 {
@@ -2338,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);
 
 
@@ -2347,6 +2351,7 @@ namespace Emby.Server.Implementations.LiveTv
 
 
             var addCurrentProgram = options.AddCurrentProgram;
             var addCurrentProgram = options.AddCurrentProgram;
             var addMediaSources = options.Fields.Contains(ItemFields.MediaSources);
             var addMediaSources = options.Fields.Contains(ItemFields.MediaSources);
+            var addServiceName = options.Fields.Contains(ItemFields.ServiceName);
 
 
             foreach (var tuple in tuples)
             foreach (var tuple in tuples)
             {
             {
@@ -2356,13 +2361,17 @@ namespace Emby.Server.Implementations.LiveTv
                 dto.Number = channel.Number;
                 dto.Number = channel.Number;
                 dto.ChannelNumber = channel.Number;
                 dto.ChannelNumber = channel.Number;
                 dto.ChannelType = channel.ChannelType;
                 dto.ChannelType = channel.ChannelType;
-                dto.ServiceName = channel.ServiceName;
+
+                if (addServiceName)
+                {
+                    dto.ServiceName = channel.ServiceName;
+                }
 
 
                 currentChannelsDict[dto.Id] = dto;
                 currentChannelsDict[dto.Id] = dto;
 
 
                 if (addMediaSources)
                 if (addMediaSources)
                 {
                 {
-                    dto.MediaSources = channel.GetMediaSources(true).ToList();
+                    dto.MediaSources = channel.GetMediaSources(true);
                 }
                 }
 
 
                 if (addCurrentProgram)
                 if (addCurrentProgram)
@@ -2516,7 +2525,7 @@ namespace Emby.Server.Implementations.LiveTv
             _lastRecordingRefreshTime = DateTime.MinValue;
             _lastRecordingRefreshTime = DateTime.MinValue;
             _logger.Info("New recording scheduled");
             _logger.Info("New recording scheduled");
 
 
-            EventHelper.QueueEventIfNotNull(TimerCreated, this, new GenericEventArgs<TimerEventInfo>
+            EventHelper.FireEventIfNotNull(TimerCreated, this, new GenericEventArgs<TimerEventInfo>
             {
             {
                 Argument = new TimerEventInfo
                 Argument = new TimerEventInfo
                 {
                 {
@@ -2558,7 +2567,7 @@ namespace Emby.Server.Implementations.LiveTv
 
 
             _lastRecordingRefreshTime = DateTime.MinValue;
             _lastRecordingRefreshTime = DateTime.MinValue;
 
 
-            EventHelper.QueueEventIfNotNull(SeriesTimerCreated, this, new GenericEventArgs<TimerEventInfo>
+            EventHelper.FireEventIfNotNull(SeriesTimerCreated, this, new GenericEventArgs<TimerEventInfo>
             {
             {
                 Argument = new TimerEventInfo
                 Argument = new TimerEventInfo
                 {
                 {
@@ -2697,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
             };
             };
         }
         }
@@ -2984,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);

+ 3 - 3
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
 {
 {
@@ -78,8 +79,7 @@ namespace Emby.Server.Implementations.LiveTv
             {
             {
                 var hasMediaSources = (IHasMediaSources)item;
                 var hasMediaSources = (IHasMediaSources)item;
 
 
-                sources = _mediaSourceManager.GetStaticMediaSources(hasMediaSources, false)
-                   .ToList();
+                sources = _mediaSourceManager.GetStaticMediaSources(hasMediaSources, false);
 
 
                 forceRequireOpening = true;
                 forceRequireOpening = true;
             }
             }
@@ -103,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/LiveTv/RecordingImageProvider.cs

@@ -19,12 +19,12 @@ namespace Emby.Server.Implementations.LiveTv
             _liveTvManager = liveTvManager;
             _liveTvManager = liveTvManager;
         }
         }
 
 
-        public IEnumerable<ImageType> GetSupportedImages(IHasImages item)
+        public IEnumerable<ImageType> GetSupportedImages(IHasMetadata item)
         {
         {
             return new[] { ImageType.Primary };
             return new[] { ImageType.Primary };
         }
         }
 
 
-        public async Task<DynamicImageResponse> GetImage(IHasImages item, ImageType type, CancellationToken cancellationToken)
+        public async Task<DynamicImageResponse> GetImage(IHasMetadata item, ImageType type, CancellationToken cancellationToken)
         {
         {
             var liveTvItem = (ILiveTvRecording)item;
             var liveTvItem = (ILiveTvRecording)item;
 
 
@@ -58,7 +58,7 @@ namespace Emby.Server.Implementations.LiveTv
             get { return "Live TV Service Provider"; }
             get { return "Live TV Service Provider"; }
         }
         }
 
 
-        public bool Supports(IHasImages item)
+        public bool Supports(IHasMetadata item)
         {
         {
             return item is ILiveTvRecording;
             return item is ILiveTvRecording;
         }
         }

+ 12 - 8
Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs

@@ -1,5 +1,4 @@
-using MediaBrowser.Common.Configuration;
-using MediaBrowser.Common.Extensions;
+using MediaBrowser.Common.Extensions;
 using MediaBrowser.Controller.LiveTv;
 using MediaBrowser.Controller.LiveTv;
 using MediaBrowser.Model.Dto;
 using MediaBrowser.Model.Dto;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Entities;
@@ -11,12 +10,10 @@ using System.Collections.Generic;
 using System.Linq;
 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.Common.Net;
 using MediaBrowser.Common.Net;
 using MediaBrowser.Controller;
 using MediaBrowser.Controller;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.IO;
 using MediaBrowser.Controller.MediaEncoding;
 using MediaBrowser.Controller.MediaEncoding;
 using MediaBrowser.Model.Serialization;
 using MediaBrowser.Model.Serialization;
 using MediaBrowser.Model.System;
 using MediaBrowser.Model.System;
@@ -46,9 +43,16 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
             get { return "M3U Tuner"; }
             get { return "M3U Tuner"; }
         }
         }
 
 
+        private string GetFullChannelIdPrefix(TunerHostInfo info)
+        {
+            return ChannelIdPrefix + info.Url.GetMD5().ToString("N");
+        }
+
         protected override async Task<List<ChannelInfo>> GetChannelsInternal(TunerHostInfo info, CancellationToken cancellationToken)
         protected override async Task<List<ChannelInfo>> GetChannelsInternal(TunerHostInfo info, CancellationToken cancellationToken)
         {
         {
-            var result = await new M3uParser(Logger, FileSystem, _httpClient, _appHost).Parse(info.Url, ChannelIdPrefix, info.Id, !info.EnableTvgId, cancellationToken).ConfigureAwait(false);
+            var channelIdPrefix = GetFullChannelIdPrefix(info);
+
+            var result = await new M3uParser(Logger, FileSystem, _httpClient, _appHost).Parse(info.Url, channelIdPrefix, info.Id, cancellationToken).ConfigureAwait(false);
 
 
             return result.Cast<ChannelInfo>().ToList();
             return result.Cast<ChannelInfo>().ToList();
         }
         }
@@ -87,9 +91,9 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
 
 
         protected override async Task<List<MediaSourceInfo>> GetChannelStreamMediaSources(TunerHostInfo info, string channelId, CancellationToken cancellationToken)
         protected override async Task<List<MediaSourceInfo>> GetChannelStreamMediaSources(TunerHostInfo info, string channelId, CancellationToken cancellationToken)
         {
         {
-            var urlHash = info.Url.GetMD5().ToString("N");
-            var prefix = ChannelIdPrefix + urlHash;
-            if (!channelId.StartsWith(prefix, StringComparison.OrdinalIgnoreCase))
+            var channelIdPrefix = GetFullChannelIdPrefix(info);
+
+            if (!channelId.StartsWith(channelIdPrefix, StringComparison.OrdinalIgnoreCase))
             {
             {
                 return null;
                 return null;
             }
             }

+ 7 - 11
Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs

@@ -32,25 +32,21 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
             _appHost = appHost;
             _appHost = appHost;
         }
         }
 
 
-        public async Task<List<M3UChannel>> Parse(string url, string channelIdPrefix, string tunerHostId, bool enableStreamUrlAsIdentifier, CancellationToken cancellationToken)
+        public async Task<List<M3UChannel>> Parse(string url, string channelIdPrefix, string tunerHostId, CancellationToken cancellationToken)
         {
         {
-            var urlHash = url.GetMD5().ToString("N");
-
             // Read the file and display it line by line.
             // Read the file and display it line by line.
             using (var reader = new StreamReader(await GetListingsStream(url, cancellationToken).ConfigureAwait(false)))
             using (var reader = new StreamReader(await GetListingsStream(url, cancellationToken).ConfigureAwait(false)))
             {
             {
-                return GetChannels(reader, urlHash, channelIdPrefix, tunerHostId, enableStreamUrlAsIdentifier);
+                return GetChannels(reader, channelIdPrefix, tunerHostId);
             }
             }
         }
         }
 
 
         public List<M3UChannel> ParseString(string text, string channelIdPrefix, string tunerHostId)
         public List<M3UChannel> ParseString(string text, string channelIdPrefix, string tunerHostId)
         {
         {
-            var urlHash = "text".GetMD5().ToString("N");
-
             // Read the file and display it line by line.
             // Read the file and display it line by line.
             using (var reader = new StringReader(text))
             using (var reader = new StringReader(text))
             {
             {
-                return GetChannels(reader, urlHash, channelIdPrefix, tunerHostId, false);
+                return GetChannels(reader, channelIdPrefix, tunerHostId);
             }
             }
         }
         }
 
 
@@ -70,7 +66,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
         }
         }
 
 
         const string ExtInfPrefix = "#EXTINF:";
         const string ExtInfPrefix = "#EXTINF:";
-        private List<M3UChannel> GetChannels(TextReader reader, string urlHash, string channelIdPrefix, string tunerHostId, bool enableStreamUrlAsIdentifier)
+        private List<M3UChannel> GetChannels(TextReader reader, string channelIdPrefix, string tunerHostId)
         {
         {
             var channels = new List<M3UChannel>();
             var channels = new List<M3UChannel>();
             string line;
             string line;
@@ -97,13 +93,13 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
                 else if (!string.IsNullOrWhiteSpace(extInf) && !line.StartsWith("#", StringComparison.OrdinalIgnoreCase))
                 else if (!string.IsNullOrWhiteSpace(extInf) && !line.StartsWith("#", StringComparison.OrdinalIgnoreCase))
                 {
                 {
                     var channel = GetChannelnfo(extInf, tunerHostId, line);
                     var channel = GetChannelnfo(extInf, tunerHostId, line);
-                    if (string.IsNullOrWhiteSpace(channel.Id) || enableStreamUrlAsIdentifier)
+                    if (string.IsNullOrWhiteSpace(channel.Id))
                     {
                     {
-                        channel.Id = channelIdPrefix + urlHash + line.GetMD5().ToString("N");
+                        channel.Id = channelIdPrefix + line.GetMD5().ToString("N");
                     }
                     }
                     else
                     else
                     {
                     {
-                        channel.Id = channelIdPrefix + urlHash + channel.Id.GetMD5().ToString("N");
+                        channel.Id = channelIdPrefix + channel.Id.GetMD5().ToString("N");
                     }
                     }
 
 
                     channel.Path = line;
                     channel.Path = line;

+ 1 - 1
Emby.Server.Implementations/Localization/Core/en-US.json

@@ -69,7 +69,7 @@
   "ViewTypeTvResume": "Resume",
   "ViewTypeTvResume": "Resume",
   "ViewTypeTvNextUp": "Next Up",
   "ViewTypeTvNextUp": "Next Up",
   "ViewTypeTvLatest": "Latest",
   "ViewTypeTvLatest": "Latest",
-  "ViewTypeTvShowSeries": "Series",
+  "ViewTypeTvShowSeries": "Shows",
   "ViewTypeTvGenres": "Genres",
   "ViewTypeTvGenres": "Genres",
   "ViewTypeTvFavoriteSeries": "Favorite Series",
   "ViewTypeTvFavoriteSeries": "Favorite Series",
   "ViewTypeTvFavoriteEpisodes": "Favorite Episodes",
   "ViewTypeTvFavoriteEpisodes": "Favorite Episodes",

+ 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 - 0
Emby.Server.Implementations/Localization/Ratings/es.txt

@@ -1,4 +1,5 @@
 ES-A,1
 ES-A,1
+ES-APTA,1
 ES-7,3
 ES-7,3
 ES-12,6
 ES-12,6
 ES-16,8
 ES-16,8

+ 1 - 0
Emby.Server.Implementations/Localization/Ratings/ro.txt

@@ -0,0 +1 @@
+RO-AG,1

+ 1 - 0
Emby.Server.Implementations/Localization/Ratings/us.txt

@@ -1,3 +1,4 @@
+APPROVED,1
 G,1
 G,1
 E,1
 E,1
 EC,1
 EC,1

Alguns arquivos não foram mostrados porque muitos arquivos mudaram nesse diff