diff --git a/Emby.Common.Implementations/Emby.Common.Implementations.csproj b/Emby.Common.Implementations/Emby.Common.Implementations.csproj index 00c90d16e4..879e8e82f9 100644 --- a/Emby.Common.Implementations/Emby.Common.Implementations.csproj +++ b/Emby.Common.Implementations/Emby.Common.Implementations.csproj @@ -32,12 +32,10 @@ - ..\packages\NLog.4.4.11\lib\net45\NLog.dll - True + ..\packages\NLog.4.4.12\lib\net45\NLog.dll - - ..\packages\ServiceStack.Text.4.5.8\lib\net45\ServiceStack.Text.dll - True + + ..\packages\ServiceStack.Text.4.5.12\lib\net45\ServiceStack.Text.dll ..\packages\SharpCompress.0.14.0\lib\net45\SharpCompress.dll diff --git a/Emby.Common.Implementations/Logging/NlogManager.cs b/Emby.Common.Implementations/Logging/NlogManager.cs index f7b723e8bc..4446e2cdb9 100644 --- a/Emby.Common.Implementations/Logging/NlogManager.cs +++ b/Emby.Common.Implementations/Logging/NlogManager.cs @@ -152,13 +152,23 @@ namespace Emby.Common.Implementations.Logging 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"; var logFile = new FileTarget { FileName = path, - Layout = "${longdate} ${level} ${logger}: ${message}" + Layout = "${longdate} ${level} ${logger}: ${message}", + KeepFileOpen = true, + ConcurrentWrites = false }; logFile.Name = "ApplicationLogFile"; diff --git a/Emby.Common.Implementations/Networking/NetworkManager.cs b/Emby.Common.Implementations/Networking/NetworkManager.cs index 2f218656c9..354107bb7a 100644 --- a/Emby.Common.Implementations/Networking/NetworkManager.cs +++ b/Emby.Common.Implementations/Networking/NetworkManager.cs @@ -506,7 +506,7 @@ namespace Emby.Common.Implementations.Networking public async Task GetHostAddressesAsync(string host) { var addresses = await Dns.GetHostAddressesAsync(host).ConfigureAwait(false); - return addresses.Select(ToIpAddressInfo).ToArray(); + return addresses.Select(ToIpAddressInfo).ToArray(addresses.Length); } /// diff --git a/Emby.Common.Implementations/ScheduledTasks/ScheduledTaskWorker.cs b/Emby.Common.Implementations/ScheduledTasks/ScheduledTaskWorker.cs index c373ffddb9..dd840677a3 100644 --- a/Emby.Common.Implementations/ScheduledTasks/ScheduledTaskWorker.cs +++ b/Emby.Common.Implementations/ScheduledTasks/ScheduledTaskWorker.cs @@ -14,6 +14,7 @@ using MediaBrowser.Model.Logging; using MediaBrowser.Model.Serialization; using MediaBrowser.Model.System; using MediaBrowser.Model.Tasks; +using MediaBrowser.Model.Extensions; namespace Emby.Common.Implementations.ScheduledTasks { @@ -274,7 +275,8 @@ namespace Emby.Common.Implementations.ScheduledTasks { get { - return InternalTriggers.Select(i => i.Item1).ToArray(); + var triggers = InternalTriggers; + return triggers.Select(i => i.Item1).ToArray(triggers.Length); } set { @@ -288,7 +290,7 @@ namespace Emby.Common.Implementations.ScheduledTasks SaveTriggers(triggerList); - InternalTriggers = triggerList.Select(i => new Tuple(i, GetTrigger(i))).ToArray(); + InternalTriggers = triggerList.Select(i => new Tuple(i, GetTrigger(i))).ToArray(triggerList.Length); } } diff --git a/Emby.Common.Implementations/packages.config b/Emby.Common.Implementations/packages.config index a255465cc7..a9fc75af68 100644 --- a/Emby.Common.Implementations/packages.config +++ b/Emby.Common.Implementations/packages.config @@ -1,7 +1,7 @@  - - + + \ No newline at end of file diff --git a/Emby.Dlna/ContentDirectory/ControlHandler.cs b/Emby.Dlna/ContentDirectory/ControlHandler.cs index 4d82b6b250..4be2dc945c 100644 --- a/Emby.Dlna/ContentDirectory/ControlHandler.cs +++ b/Emby.Dlna/ContentDirectory/ControlHandler.cs @@ -30,6 +30,7 @@ using MediaBrowser.Controller.Playlists; using MediaBrowser.Controller.TV; using MediaBrowser.Model.Globalization; using MediaBrowser.Model.Xml; +using MediaBrowser.Model.Extensions; namespace Emby.Dlna.ContentDirectory { @@ -457,14 +458,14 @@ namespace Emby.Dlna.ContentDirectory { Limit = limit, StartIndex = startIndex, - SortBy = sortOrders.ToArray(), + SortBy = sortOrders.ToArray(sortOrders.Count), SortOrder = sort.SortOrder, User = user, Recursive = true, IsMissing = false, ExcludeItemTypes = new[] { typeof(Game).Name, typeof(Book).Name }, IsFolder = isFolder, - MediaTypes = mediaTypes.ToArray(), + MediaTypes = mediaTypes.ToArray(mediaTypes.Count), DtoOptions = GetDtoOptions() }); } @@ -508,12 +509,12 @@ namespace Emby.Dlna.ContentDirectory { ItemId = item.Id - }).ToArray(); + }); var result = new QueryResult { - 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); @@ -662,7 +663,7 @@ namespace Emby.Dlna.ContentDirectory return new QueryResult { - Items = list.ToArray(), + Items = list.ToArray(list.Count), TotalRecordCount = list.Count }; } @@ -740,7 +741,7 @@ namespace Emby.Dlna.ContentDirectory return new QueryResult { - Items = list.ToArray(), + Items = list.ToArray(list.Count), TotalRecordCount = list.Count }; } @@ -828,7 +829,7 @@ namespace Emby.Dlna.ContentDirectory return new QueryResult { - Items = list.ToArray(), + Items = list.ToArray(list.Count), TotalRecordCount = list.Count }; } @@ -995,7 +996,7 @@ namespace Emby.Dlna.ContentDirectory var result = new QueryResult { 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); @@ -1013,7 +1014,7 @@ namespace Emby.Dlna.ContentDirectory var result = new QueryResult { 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); @@ -1031,7 +1032,7 @@ namespace Emby.Dlna.ContentDirectory var result = new QueryResult { 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); @@ -1049,7 +1050,7 @@ namespace Emby.Dlna.ContentDirectory var result = new QueryResult { 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); @@ -1068,7 +1069,7 @@ namespace Emby.Dlna.ContentDirectory var result = new QueryResult { 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); @@ -1196,7 +1197,7 @@ namespace Emby.Dlna.ContentDirectory { var serverItems = result .Select(i => new ServerItem(i)) - .ToArray(); + .ToArray(result.Count); return new QueryResult { @@ -1210,7 +1211,7 @@ namespace Emby.Dlna.ContentDirectory var serverItems = result .Items .Select(i => new ServerItem(i)) - .ToArray(); + .ToArray(result.Items.Length); return new QueryResult { @@ -1227,7 +1228,7 @@ namespace Emby.Dlna.ContentDirectory sortOrders.Add(ItemSortBy.SortName); } - query.SortBy = sortOrders.ToArray(); + query.SortBy = sortOrders.ToArray(sortOrders.Count); query.SortOrder = sort.SortOrder; } @@ -1243,8 +1244,7 @@ namespace Emby.Dlna.ContentDirectory 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 { diff --git a/Emby.Dlna/DlnaManager.cs b/Emby.Dlna/DlnaManager.cs index 82975ce22b..847f636198 100644 --- a/Emby.Dlna/DlnaManager.cs +++ b/Emby.Dlna/DlnaManager.cs @@ -18,6 +18,7 @@ using System.Text; using System.Text.RegularExpressions; using MediaBrowser.Model.IO; using MediaBrowser.Model.Reflection; +using MediaBrowser.Model.Extensions; namespace Emby.Dlna { @@ -106,7 +107,6 @@ namespace Emby.Dlna } else { - _logger.Debug("No matching device profile found. The default will need to be used."); LogUnmatchedProfile(deviceInfo); } @@ -220,12 +220,8 @@ namespace Emby.Dlna } 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; diff --git a/Emby.Dlna/PlayTo/Device.cs b/Emby.Dlna/PlayTo/Device.cs index e222980102..ff493e365e 100644 --- a/Emby.Dlna/PlayTo/Device.cs +++ b/Emby.Dlna/PlayTo/Device.cs @@ -15,6 +15,7 @@ using System.Threading.Tasks; using System.Xml.Linq; using Emby.Dlna.Server; using MediaBrowser.Model.Threading; +using MediaBrowser.Model.Extensions; namespace Emby.Dlna.PlayTo { @@ -890,7 +891,7 @@ namespace Emby.Dlna.PlayTo if (room != null && !string.IsNullOrWhiteSpace(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(); if (model != null) diff --git a/Emby.Dlna/Profiles/DefaultProfile.cs b/Emby.Dlna/Profiles/DefaultProfile.cs index 06ce936408..ff025152a7 100644 --- a/Emby.Dlna/Profiles/DefaultProfile.cs +++ b/Emby.Dlna/Profiles/DefaultProfile.cs @@ -1,6 +1,7 @@ using MediaBrowser.Model.Dlna; using System.Linq; using System.Xml.Serialization; +using MediaBrowser.Model.Extensions; namespace Emby.Dlna.Profiles { @@ -164,7 +165,7 @@ namespace Emby.Dlna.Profiles public void AddXmlRootAttribute(string name, string value) { var atts = XmlRootAttributes ?? new XmlAttribute[] { }; - var list = atts.ToList(); + var list = atts.ToList(atts.Length); list.Add(new XmlAttribute { @@ -172,7 +173,7 @@ namespace Emby.Dlna.Profiles Value = value }); - XmlRootAttributes = list.ToArray(); + XmlRootAttributes = list.ToArray(list.Count); } } } diff --git a/Emby.Dlna/Server/DescriptionXmlBuilder.cs b/Emby.Dlna/Server/DescriptionXmlBuilder.cs index 2a4a5792fa..bba4adc5f4 100644 --- a/Emby.Dlna/Server/DescriptionXmlBuilder.cs +++ b/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); diff --git a/Emby.Dlna/Service/BaseControlHandler.cs b/Emby.Dlna/Service/BaseControlHandler.cs index 3092589c12..7cd10bd019 100644 --- a/Emby.Dlna/Service/BaseControlHandler.cs +++ b/Emby.Dlna/Service/BaseControlHandler.cs @@ -11,6 +11,7 @@ using System.Xml; using Emby.Dlna.Didl; using MediaBrowser.Controller.Extensions; using MediaBrowser.Model.Xml; +using MediaBrowser.Model.Extensions; namespace Emby.Dlna.Service { @@ -235,26 +236,29 @@ namespace Emby.Dlna.Service 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) { - 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); } } } diff --git a/Emby.Drawing/ImageProcessor.cs b/Emby.Drawing/ImageProcessor.cs index cc7b77de6d..bd23eba7aa 100644 --- a/Emby.Drawing/ImageProcessor.cs +++ b/Emby.Drawing/ImageProcessor.cs @@ -17,12 +17,10 @@ using System.Threading; using System.Threading.Tasks; using MediaBrowser.Model.IO; using Emby.Drawing.Common; - -using MediaBrowser.Controller.IO; using MediaBrowser.Controller.Library; using MediaBrowser.Model.Net; using MediaBrowser.Model.Threading; -using TagLib; +using MediaBrowser.Model.Extensions; namespace Emby.Drawing { @@ -662,7 +660,7 @@ namespace Emby.Drawing var cacheKeys = imageEnhancers.Select(i => i.GetConfigurationCacheKey(item, imageType)).ToList(); cacheKeys.Add(originalImagePath + dateModified.Ticks); - return string.Join("|", cacheKeys.ToArray()).GetMD5().ToString("N"); + return string.Join("|", cacheKeys.ToArray(cacheKeys.Count)).GetMD5().ToString("N"); } /// diff --git a/Emby.Photos/PhotoProvider.cs b/Emby.Photos/PhotoProvider.cs index 57047cf81e..c3c30ab6d1 100644 --- a/Emby.Photos/PhotoProvider.cs +++ b/Emby.Photos/PhotoProvider.cs @@ -111,7 +111,7 @@ namespace Emby.Photos } item.Genres = image.ImageTag.Genres.ToList(); - item.Tags = image.ImageTag.Keywords.ToList(); + item.Tags = image.ImageTag.Keywords; item.Software = image.ImageTag.Software; if (image.ImageTag.Orientation == TagLib.Image.ImageOrientation.None) diff --git a/Emby.Server.Core/Emby.Server.Core.csproj b/Emby.Server.Core/Emby.Server.Core.csproj deleted file mode 100644 index 063ef6eb90..0000000000 --- a/Emby.Server.Core/Emby.Server.Core.csproj +++ /dev/null @@ -1,176 +0,0 @@ - - - - - Debug - AnyCPU - {776B9F0C-5195-45E3-9A36-1CC1F0D8E0B0} - Library - Properties - Emby.Server.Core - Emby.Server.Core - v4.6 - 512 - - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - true - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - true - - - - ..\packages\Microsoft.IO.RecyclableMemoryStream.1.2.2\lib\net45\Microsoft.IO.RecyclableMemoryStream.dll - True - - - ..\packages\ServiceStack.Text.4.5.8\lib\net45\ServiceStack.Text.dll - True - - - ..\packages\SimpleInjector.4.0.8\lib\net45\SimpleInjector.dll - - - - - - - - - - - - - - Properties\SharedVersion.cs - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {1e37a338-9f57-4b70-bd6d-bb9c591e319b} - Emby.Common.Implementations - - - {805844ab-e92f-45e6-9d99-4f6d48d129a5} - Emby.Dlna - - - {08fff49b-f175-4807-a2b5-73b0ebd9f716} - Emby.Drawing - - - {89ab4548-770d-41fd-a891-8daff44f452c} - Emby.Photos - - - {e383961b-9356-4d5d-8233-9a1079d03055} - Emby.Server.Implementations - - - {4fd51ac5-2c16-4308-a993-c3a84f3b4582} - MediaBrowser.Api - - - {9142eefa-7570-41e1-bfcc-468bb571af2f} - MediaBrowser.Common - - - {17e1f4e6-8abd-4fe5-9ecf-43d4b6087ba2} - MediaBrowser.Controller - - - {7ef9f3e0-697d-42f3-a08f-19deb5f84392} - MediaBrowser.LocalMetadata - - - {0bd82fa6-eb8a-4452-8af5-74f9c3849451} - MediaBrowser.MediaEncoding - - - {7eeeb4bb-f3e8-48fc-b4c5-70f0fff8329b} - MediaBrowser.Model - - - {442b5058-dcaf-4263-bb6a-f21e31120a1b} - MediaBrowser.Providers - - - {2e781478-814d-4a48-9d80-bff206441a65} - MediaBrowser.Server.Implementations - - - {5624b7b5-b5a7-41d8-9f10-cc5611109619} - MediaBrowser.WebDashboard - - - {23499896-b135-4527-8574-c26e926ea99e} - MediaBrowser.XbmcMetadata - - - {cb7f2326-6497-4a3d-ba03-48513b17a7be} - Mono.Nat - - - {4a4402d4-e910-443b-b8fc-2c18286a2ca0} - OpenSubtitlesHandler - - - {1d74413b-e7cf-455b-b021-f52bdf881542} - SocketHttpListener - - - - - - - - - \ No newline at end of file diff --git a/Emby.Server.Core/Properties/AssemblyInfo.cs b/Emby.Server.Core/Properties/AssemblyInfo.cs deleted file mode 100644 index ead0429819..0000000000 --- a/Emby.Server.Core/Properties/AssemblyInfo.cs +++ /dev/null @@ -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.*")] \ No newline at end of file diff --git a/Emby.Server.Core/app.config b/Emby.Server.Core/app.config deleted file mode 100644 index 57ff623921..0000000000 --- a/Emby.Server.Core/app.config +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - diff --git a/Emby.Server.Core/packages.config b/Emby.Server.Core/packages.config deleted file mode 100644 index 6311b55eb2..0000000000 --- a/Emby.Server.Core/packages.config +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs b/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs index 567f139fd8..702917832b 100644 --- a/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs +++ b/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs @@ -18,6 +18,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; using MediaBrowser.Model.Globalization; +using MediaBrowser.Model.Extensions; namespace Emby.Server.Implementations.Activity { @@ -436,7 +437,7 @@ namespace Emby.Server.Implementations.Activity { Name = string.Format(_localization.GetLocalizedString("ScheduledTaskFailedWithName"), task.Name), Type = "ScheduledTaskFailed", - Overview = string.Join(Environment.NewLine, vals.ToArray()), + Overview = string.Join(Environment.NewLine, vals.ToArray(vals.Count)), ShortOverview = runningTime, Severity = LogSeverity.Error }); diff --git a/Emby.Server.Implementations/Activity/ActivityRepository.cs b/Emby.Server.Implementations/Activity/ActivityRepository.cs index e9b6f7a404..7720f8f2fd 100644 --- a/Emby.Server.Implementations/Activity/ActivityRepository.cs +++ b/Emby.Server.Implementations/Activity/ActivityRepository.cs @@ -10,6 +10,7 @@ using MediaBrowser.Model.Activity; using MediaBrowser.Model.Logging; using MediaBrowser.Model.Querying; using SQLitePCL.pretty; +using MediaBrowser.Model.Extensions; namespace Emby.Server.Implementations.Activity { @@ -94,13 +95,13 @@ namespace Emby.Server.Implementations.Activity var whereTextWithoutPaging = whereClauses.Count == 0 ? string.Empty : - " where " + string.Join(" AND ", whereClauses.ToArray()); + " where " + string.Join(" AND ", whereClauses.ToArray(whereClauses.Count)); if (startIndex.HasValue && startIndex.Value > 0) { var pagingWhereText = whereClauses.Count == 0 ? 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})", pagingWhereText, @@ -109,7 +110,7 @@ namespace Emby.Server.Implementations.Activity var whereText = whereClauses.Count == 0 ? string.Empty : - " where " + string.Join(" AND ", whereClauses.ToArray()); + " where " + string.Join(" AND ", whereClauses.ToArray(whereClauses.Count)); commandText += whereText; @@ -154,7 +155,7 @@ namespace Emby.Server.Implementations.Activity result.TotalRecordCount = statement.ExecuteQuery().SelectScalarInt().First(); } - result.Items = list.ToArray(); + result.Items = list.ToArray(list.Count); return result; }, ReadTransactionMode); diff --git a/Emby.Server.Core/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs similarity index 97% rename from Emby.Server.Core/ApplicationHost.cs rename to Emby.Server.Implementations/ApplicationHost.cs index 68cb2a4e32..f1f24660c5 100644 --- a/Emby.Server.Core/ApplicationHost.cs +++ b/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.Configuration; using MediaBrowser.Common.Events; using MediaBrowser.Common.Extensions; -using Emby.Common.Implementations.ScheduledTasks; using MediaBrowser.Common.Net; +using MediaBrowser.Common.Plugins; using MediaBrowser.Common.Progress; +using MediaBrowser.Common.Security; +using MediaBrowser.Common.Updates; using MediaBrowser.Controller; using MediaBrowser.Controller.Channels; using MediaBrowser.Controller.Chapters; @@ -17,6 +58,9 @@ using MediaBrowser.Controller.Dlna; using MediaBrowser.Controller.Drawing; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities.Audio; +using MediaBrowser.Controller.Entities.Movies; +using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.LiveTv; using MediaBrowser.Controller.MediaEncoding; @@ -34,102 +78,47 @@ using MediaBrowser.Controller.Subtitles; using MediaBrowser.Controller.Sync; using MediaBrowser.Controller.TV; using MediaBrowser.LocalMetadata.Savers; -using MediaBrowser.MediaEncoding.BdInfo; -using MediaBrowser.MediaEncoding.Encoder; -using MediaBrowser.MediaEncoding.Subtitles; -using MediaBrowser.Model.Logging; -using MediaBrowser.Model.MediaInfo; -using MediaBrowser.Model.System; -using MediaBrowser.Model.Updates; -using MediaBrowser.Providers.Chapters; -using MediaBrowser.Providers.Manager; -using MediaBrowser.Providers.Subtitles; -using MediaBrowser.WebDashboard.Api; -using MediaBrowser.XbmcMetadata.Providers; -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Globalization; -using System.IO; -using System.Linq; -using System.Net; -using System.Net.Sockets; -using System.Reflection; -using System.Security.Cryptography.X509Certificates; -using System.Threading; -using System.Threading.Tasks; -using Emby.Common.Implementations; -using Emby.Common.Implementations.Archiving; -using Emby.Common.Implementations.IO; -using Emby.Common.Implementations.Reflection; -using Emby.Common.Implementations.Serialization; -using Emby.Common.Implementations.TextEncoding; -using Emby.Common.Implementations.Xml; -using Emby.Photos; -using MediaBrowser.Model.IO; -using MediaBrowser.Api.Playback; -using MediaBrowser.Common.Plugins; -using MediaBrowser.Common.Security; -using MediaBrowser.Common.Updates; -using MediaBrowser.Controller.Entities.Audio; -using MediaBrowser.Controller.Entities.Movies; -using MediaBrowser.Controller.Entities.TV; -using Emby.Dlna; -using Emby.Dlna.ConnectionManager; -using Emby.Dlna.ContentDirectory; -using Emby.Dlna.Main; -using Emby.Dlna.MediaReceiverRegistrar; -using Emby.Dlna.Ssdp; -using Emby.Server.Core; -using Emby.Server.Implementations.Activity; -using Emby.Server.Implementations.Devices; -using Emby.Server.Implementations.FFMpeg; -using Emby.Server.Core.IO; -using Emby.Server.Core.Localization; -using Emby.Server.Implementations.Migrations; -using Emby.Server.Implementations.Security; -using Emby.Server.Implementations.Social; -using Emby.Server.Implementations.Channels; -using Emby.Server.Implementations.Collections; -using Emby.Server.Implementations.Dto; -using Emby.Server.Implementations.IO; -using Emby.Server.Implementations.HttpServer; -using Emby.Server.Implementations.HttpServer.Security; -using Emby.Server.Implementations.Library; -using Emby.Server.Implementations.LiveTv; -using Emby.Server.Implementations.Localization; -using Emby.Server.Implementations.MediaEncoder; -using Emby.Server.Implementations.Notifications; -using Emby.Server.Implementations.Data; -using Emby.Server.Implementations.Playlists; -using Emby.Server.Implementations; -using Emby.Server.Implementations.ServerManager; -using Emby.Server.Implementations.Session; -using Emby.Server.Implementations.TV; -using Emby.Server.Implementations.Updates; using MediaBrowser.Model.Activity; using MediaBrowser.Model.Configuration; +using MediaBrowser.Model.Diagnostics; using MediaBrowser.Model.Dlna; using MediaBrowser.Model.Globalization; +using MediaBrowser.Model.IO; +using MediaBrowser.Model.Logging; +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.Text; +using MediaBrowser.Model.Updates; using MediaBrowser.Model.Xml; +using MediaBrowser.Providers.Chapters; +using MediaBrowser.Providers.Manager; +using MediaBrowser.Providers.Subtitles; +using MediaBrowser.WebDashboard.Api; +using MediaBrowser.XbmcMetadata.Providers; using OpenSubtitlesHandler; using ServiceStack; using SocketHttpListener.Primitives; +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Security.Cryptography.X509Certificates; +using System.Threading; +using System.Threading.Tasks; +using Emby.Server.MediaEncoding.Subtitles; +using MediaBrowser.MediaEncoding.BdInfo; 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 { /// /// Class CompositionRoot @@ -357,13 +346,6 @@ namespace Emby.Server.Core { 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, "*** Error Report ***" + Environment.NewLine); @@ -608,7 +590,7 @@ namespace Emby.Server.Core RegisterSingleInstance(HttpServer, false); 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); var innerProgress = new ActionableProgress(); @@ -884,7 +866,7 @@ namespace Emby.Server.Core probePath = info.ProbePath; 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, encoderPath, probePath, @@ -980,8 +962,6 @@ namespace Emby.Server.Core BaseItem.CollectionManager = CollectionManager; BaseItem.MediaSourceManager = MediaSourceManager; CollectionFolder.XmlSerializer = XmlSerializer; - BaseStreamingService.AppHost = this; - BaseStreamingService.HttpClient = HttpClient; Utilities.CryptographyProvider = CryptographyProvider; AuthenticatedAttribute.AuthService = AuthService; } @@ -1254,7 +1234,7 @@ namespace Emby.Server.Core list.Add(GetAssembly(typeof(InstallationManager))); // MediaEncoding - list.Add(GetAssembly(typeof(MediaEncoder))); + list.Add(GetAssembly(typeof(MediaEncoding.Encoder.MediaEncoder))); // Dlna list.Add(GetAssembly(typeof(DlnaEntryPoint))); @@ -1267,10 +1247,7 @@ namespace Emby.Server.Core list.AddRange(GetAssembliesWithPartsInternal()); - // Include composable parts in the running assembly - list.Add(GetAssembly(typeof(ApplicationHost))); - - return list; + return list.ToList(); } protected abstract List GetAssembliesWithPartsInternal(); diff --git a/Emby.Server.Core/ApplicationPathHelper.cs b/Emby.Server.Implementations/ApplicationPathHelper.cs similarity index 97% rename from Emby.Server.Core/ApplicationPathHelper.cs rename to Emby.Server.Implementations/ApplicationPathHelper.cs index e83d5444aa..262cc526ec 100644 --- a/Emby.Server.Core/ApplicationPathHelper.cs +++ b/Emby.Server.Implementations/ApplicationPathHelper.cs @@ -2,7 +2,7 @@ using System.Configuration; using System.IO; -namespace Emby.Server.Core +namespace Emby.Server.Implementations { public static class ApplicationPathHelper { diff --git a/Emby.Server.Implementations/Channels/ChannelManager.cs b/Emby.Server.Implementations/Channels/ChannelManager.cs index 2adf6a37ca..5e97cd5f5c 100644 --- a/Emby.Server.Implementations/Channels/ChannelManager.cs +++ b/Emby.Server.Implementations/Channels/ChannelManager.cs @@ -159,7 +159,7 @@ namespace Emby.Server.Implementations.Channels all = all.Take(query.Limit.Value).ToList(); } - var returnItems = all.ToArray(); + var returnItems = all.ToArray(all.Count); var result = new QueryResult { @@ -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 { @@ -567,8 +569,9 @@ namespace Emby.Server.Implementations.Channels 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 { @@ -676,12 +679,10 @@ namespace Emby.Server.Implementations.Channels internalItems = internalItems.Take(query.Limit.Value).ToArray(); } - var returnItemArray = internalItems.ToArray(); - return new QueryResult { TotalRecordCount = totalCount, - Items = returnItemArray + Items = internalItems }; } @@ -813,12 +814,10 @@ namespace Emby.Server.Implementations.Channels var internalItems = await Task.WhenAll(itemTasks).ConfigureAwait(false); - var returnItemArray = internalItems.ToArray(); - return new QueryResult { TotalRecordCount = totalCount, - Items = returnItemArray + Items = internalItems }; } @@ -837,8 +836,10 @@ namespace Emby.Server.Implementations.Channels 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 { @@ -989,8 +990,10 @@ namespace Emby.Server.Implementations.Channels 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 { @@ -1191,7 +1194,7 @@ namespace Emby.Server.Implementations.Channels } } - var returnItemArray = all.ToArray(); + var returnItemArray = all.ToArray(all.Count); RefreshIfNeeded(returnItemArray); return new QueryResult @@ -1309,7 +1312,7 @@ namespace Emby.Server.Implementations.Channels { item.Name = info.Name; item.Genres = info.Genres; - item.Studios = info.Studios; + item.Studios = info.Studios.ToArray(info.Studios.Count); item.CommunityRating = info.CommunityRating; item.Overview = info.Overview; item.IndexNumber = info.IndexNumber; @@ -1319,7 +1322,7 @@ namespace Emby.Server.Implementations.Channels item.ProviderIds = info.ProviderIds; item.OfficialRating = info.OfficialRating; item.DateCreated = info.DateCreated ?? DateTime.UtcNow; - item.Tags = info.Tags; + item.Tags = info.Tags.ToArray(info.Tags.Count); item.HomePageUrl = info.HomePageUrl; } else if (info.Type == ChannelItemType.Folder && info.FolderType == ChannelFolderType.Container) diff --git a/Emby.Server.Implementations/Configuration/ServerConfigurationManager.cs b/Emby.Server.Implementations/Configuration/ServerConfigurationManager.cs index 2241e93778..4d9bf0624d 100644 --- a/Emby.Server.Implementations/Configuration/ServerConfigurationManager.cs +++ b/Emby.Server.Implementations/Configuration/ServerConfigurationManager.cs @@ -16,6 +16,7 @@ using MediaBrowser.Model.Events; using MediaBrowser.Model.IO; using MediaBrowser.Model.Logging; using MediaBrowser.Model.Serialization; +using MediaBrowser.Model.Extensions; namespace Emby.Server.Implementations.Configuration { @@ -216,7 +217,7 @@ namespace Emby.Server.Implementations.Configuration 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); - config.MetadataOptions = list.ToArray(); + config.MetadataOptions = list.ToArray(list.Count); } return options; diff --git a/Emby.Server.Core/Cryptography/ASN1.cs b/Emby.Server.Implementations/Cryptography/ASN1.cs similarity index 100% rename from Emby.Server.Core/Cryptography/ASN1.cs rename to Emby.Server.Implementations/Cryptography/ASN1.cs diff --git a/Emby.Server.Core/Cryptography/ASN1Convert.cs b/Emby.Server.Implementations/Cryptography/ASN1Convert.cs similarity index 100% rename from Emby.Server.Core/Cryptography/ASN1Convert.cs rename to Emby.Server.Implementations/Cryptography/ASN1Convert.cs diff --git a/Emby.Server.Core/Cryptography/BitConverterLE.cs b/Emby.Server.Implementations/Cryptography/BitConverterLE.cs similarity index 100% rename from Emby.Server.Core/Cryptography/BitConverterLE.cs rename to Emby.Server.Implementations/Cryptography/BitConverterLE.cs diff --git a/Emby.Server.Core/Cryptography/CertificateGenerator.cs b/Emby.Server.Implementations/Cryptography/CertificateGenerator.cs similarity index 100% rename from Emby.Server.Core/Cryptography/CertificateGenerator.cs rename to Emby.Server.Implementations/Cryptography/CertificateGenerator.cs diff --git a/Emby.Server.Core/Cryptography/CryptoConvert.cs b/Emby.Server.Implementations/Cryptography/CryptoConvert.cs similarity index 100% rename from Emby.Server.Core/Cryptography/CryptoConvert.cs rename to Emby.Server.Implementations/Cryptography/CryptoConvert.cs diff --git a/Emby.Server.Core/Cryptography/PKCS1.cs b/Emby.Server.Implementations/Cryptography/PKCS1.cs similarity index 100% rename from Emby.Server.Core/Cryptography/PKCS1.cs rename to Emby.Server.Implementations/Cryptography/PKCS1.cs diff --git a/Emby.Server.Core/Cryptography/PKCS12.cs b/Emby.Server.Implementations/Cryptography/PKCS12.cs similarity index 100% rename from Emby.Server.Core/Cryptography/PKCS12.cs rename to Emby.Server.Implementations/Cryptography/PKCS12.cs diff --git a/Emby.Server.Core/Cryptography/PKCS7.cs b/Emby.Server.Implementations/Cryptography/PKCS7.cs similarity index 100% rename from Emby.Server.Core/Cryptography/PKCS7.cs rename to Emby.Server.Implementations/Cryptography/PKCS7.cs diff --git a/Emby.Server.Core/Cryptography/PKCS8.cs b/Emby.Server.Implementations/Cryptography/PKCS8.cs similarity index 100% rename from Emby.Server.Core/Cryptography/PKCS8.cs rename to Emby.Server.Implementations/Cryptography/PKCS8.cs diff --git a/Emby.Server.Core/Cryptography/PfxGenerator.cs b/Emby.Server.Implementations/Cryptography/PfxGenerator.cs similarity index 100% rename from Emby.Server.Core/Cryptography/PfxGenerator.cs rename to Emby.Server.Implementations/Cryptography/PfxGenerator.cs diff --git a/Emby.Server.Core/Cryptography/X501Name.cs b/Emby.Server.Implementations/Cryptography/X501Name.cs similarity index 100% rename from Emby.Server.Core/Cryptography/X501Name.cs rename to Emby.Server.Implementations/Cryptography/X501Name.cs diff --git a/Emby.Server.Core/Cryptography/X509Builder.cs b/Emby.Server.Implementations/Cryptography/X509Builder.cs similarity index 100% rename from Emby.Server.Core/Cryptography/X509Builder.cs rename to Emby.Server.Implementations/Cryptography/X509Builder.cs diff --git a/Emby.Server.Core/Cryptography/X509Certificate.cs b/Emby.Server.Implementations/Cryptography/X509Certificate.cs similarity index 100% rename from Emby.Server.Core/Cryptography/X509Certificate.cs rename to Emby.Server.Implementations/Cryptography/X509Certificate.cs diff --git a/Emby.Server.Core/Cryptography/X509CertificateBuilder.cs b/Emby.Server.Implementations/Cryptography/X509CertificateBuilder.cs similarity index 100% rename from Emby.Server.Core/Cryptography/X509CertificateBuilder.cs rename to Emby.Server.Implementations/Cryptography/X509CertificateBuilder.cs diff --git a/Emby.Server.Core/Cryptography/X509CertificateCollection.cs b/Emby.Server.Implementations/Cryptography/X509CertificateCollection.cs similarity index 100% rename from Emby.Server.Core/Cryptography/X509CertificateCollection.cs rename to Emby.Server.Implementations/Cryptography/X509CertificateCollection.cs diff --git a/Emby.Server.Core/Cryptography/X509Extension.cs b/Emby.Server.Implementations/Cryptography/X509Extension.cs similarity index 100% rename from Emby.Server.Core/Cryptography/X509Extension.cs rename to Emby.Server.Implementations/Cryptography/X509Extension.cs diff --git a/Emby.Server.Core/Cryptography/X509Extensions.cs b/Emby.Server.Implementations/Cryptography/X509Extensions.cs similarity index 100% rename from Emby.Server.Core/Cryptography/X509Extensions.cs rename to Emby.Server.Implementations/Cryptography/X509Extensions.cs diff --git a/Emby.Server.Core/Cryptography/X520Attributes.cs b/Emby.Server.Implementations/Cryptography/X520Attributes.cs similarity index 100% rename from Emby.Server.Core/Cryptography/X520Attributes.cs rename to Emby.Server.Implementations/Cryptography/X520Attributes.cs diff --git a/Emby.Server.Implementations/Data/BaseSqliteRepository.cs b/Emby.Server.Implementations/Data/BaseSqliteRepository.cs index 72c0690733..a34c90cb41 100644 --- a/Emby.Server.Implementations/Data/BaseSqliteRepository.cs +++ b/Emby.Server.Implementations/Data/BaseSqliteRepository.cs @@ -136,24 +136,6 @@ namespace Emby.Server.Implementations.Data queries.Add("PRAGMA temp_store = file"); } - ////foreach (var query in queries) - ////{ - //// db.Execute(query); - ////} - - //Logger.Info("synchronous: " + db.Query("PRAGMA synchronous").SelectScalarString().First()); - //Logger.Info("temp_store: " + db.Query("PRAGMA temp_store").SelectScalarString().First()); - - /*if (!string.Equals(_defaultWal, "wal", StringComparison.OrdinalIgnoreCase)) - { - queries.Add("PRAGMA journal_mode=WAL"); - - using (WriteLock.Write()) - { - db.ExecuteAll(string.Join(";", queries.ToArray())); - } - } - else*/ foreach (var query in queries) { db.Execute(query); @@ -212,6 +194,13 @@ namespace Emby.Server.Implementations.Data "pragma temp_store = memory" }); } + else + { + queries.AddRange(new List + { + "pragma temp_store = file" + }); + } db.ExecuteAll(string.Join(";", queries.ToArray())); Logger.Info("PRAGMA synchronous=" + db.Query("PRAGMA synchronous").SelectScalarString().First()); diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs index 44b2cd10bd..23d46e8211 100644 --- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs @@ -31,6 +31,7 @@ using MediaBrowser.Model.Reflection; using SQLitePCL.pretty; using MediaBrowser.Model.System; using MediaBrowser.Model.Threading; +using MediaBrowser.Model.Extensions; namespace Emby.Server.Implementations.Data { @@ -836,7 +837,7 @@ namespace Emby.Server.Implementations.Data saveItemStatement.TryBind("@IsInMixedFolder", item.IsInMixedFolder); - if (item.LockedFields.Count > 0) + if (item.LockedFields.Length > 0) { saveItemStatement.TryBind("@LockedFields", string.Join("|", item.LockedFields.Select(i => i.ToString()).ToArray())); } @@ -845,7 +846,7 @@ namespace Emby.Server.Implementations.Data saveItemStatement.TryBindNull("@LockedFields"); } - if (item.Studios.Count > 0) + if (item.Studios.Length > 0) { saveItemStatement.TryBind("@Studios", string.Join("|", item.Studios.ToArray())); } @@ -865,9 +866,9 @@ namespace Emby.Server.Implementations.Data saveItemStatement.TryBind("@ExternalServiceId", item.ServiceName); - if (item.Tags.Count > 0) + if (item.Tags.Length > 0) { - saveItemStatement.TryBind("@Tags", string.Join("|", item.Tags.ToArray())); + saveItemStatement.TryBind("@Tags", string.Join("|", item.Tags)); } else { @@ -984,16 +985,16 @@ namespace Emby.Server.Implementations.Data saveItemStatement.TryBind("@ProviderIds", SerializeProviderIds(item)); saveItemStatement.TryBind("@Images", SerializeImages(item)); - if (item.ProductionLocations.Count > 0) + if (item.ProductionLocations.Length > 0) { - saveItemStatement.TryBind("@ProductionLocations", string.Join("|", item.ProductionLocations.ToArray())); + saveItemStatement.TryBind("@ProductionLocations", string.Join("|", item.ProductionLocations)); } else { saveItemStatement.TryBindNull("@ProductionLocations"); } - if (item.ThemeSongIds.Count > 0) + if (item.ThemeSongIds.Length > 0) { saveItemStatement.TryBind("@ThemeSongIds", string.Join("|", item.ThemeSongIds.ToArray())); } @@ -1002,7 +1003,7 @@ namespace Emby.Server.Implementations.Data saveItemStatement.TryBindNull("@ThemeSongIds"); } - if (item.ThemeVideoIds.Count > 0) + if (item.ThemeVideoIds.Length > 0) { saveItemStatement.TryBind("@ThemeVideoIds", string.Join("|", item.ThemeVideoIds.ToArray())); } @@ -1089,9 +1090,9 @@ namespace Emby.Server.Implementations.Data private string SerializeImages(BaseItem item) { - var images = item.ImageInfos.ToList(); + var images = item.ImageInfos; - if (images.Count == 0) + if (images.Length == 0) { return null; } @@ -1108,22 +1109,24 @@ namespace Emby.Server.Implementations.Data return; } - if (item.ImageInfos.Count > 0) + if (item.ImageInfos.Length > 0) { return; } var parts = value.Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries); - + var list = new List(); foreach (var part in parts) { var image = ItemImageInfoFromValueString(part); if (image != null) { - item.ImageInfos.Add(image); + list.Add(image); } } + + item.ImageInfos = list.ToArray(list.Count); } public string ToValueString(ItemImageInfo image) @@ -1678,7 +1681,7 @@ namespace Emby.Server.Implementations.Data return parsedValue; } return (MetadataFields?)null; - }).Where(i => i.HasValue).Select(i => i.Value).ToList(); + }).Where(i => i.HasValue).Select(i => i.Value).ToArray(); } index++; } @@ -1687,7 +1690,7 @@ namespace Emby.Server.Implementations.Data { if (!reader.IsDBNull(index)) { - item.Studios = reader.GetString(index).Split('|').Where(i => !string.IsNullOrWhiteSpace(i)).ToList(); + item.Studios = reader.GetString(index).Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries); } index++; } @@ -1696,7 +1699,7 @@ namespace Emby.Server.Implementations.Data { if (!reader.IsDBNull(index)) { - item.Tags = reader.GetString(index).Split('|').Where(i => !string.IsNullOrWhiteSpace(i)).ToList(); + item.Tags = reader.GetString(index).Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries); } index++; } @@ -1873,7 +1876,7 @@ namespace Emby.Server.Implementations.Data { if (!reader.IsDBNull(index)) { - item.ProductionLocations = reader.GetString(index).Split('|').Where(i => !string.IsNullOrWhiteSpace(i)).ToList(); + item.ProductionLocations = reader.GetString(index).Split('|').Where(i => !string.IsNullOrWhiteSpace(i)).ToArray(); } index++; } @@ -1882,7 +1885,7 @@ namespace Emby.Server.Implementations.Data { if (!reader.IsDBNull(index)) { - item.ThemeSongIds = reader.GetString(index).Split('|').Where(i => !string.IsNullOrWhiteSpace(i)).Select(i => new Guid(i)).ToList(); + item.ThemeSongIds = SplitToGuids(reader.GetString(index)); } index++; } @@ -1891,7 +1894,7 @@ namespace Emby.Server.Implementations.Data { if (!reader.IsDBNull(index)) { - item.ThemeVideoIds = reader.GetString(index).Split('|').Where(i => !string.IsNullOrWhiteSpace(i)).Select(i => new Guid(i)).ToList(); + item.ThemeVideoIds = SplitToGuids(reader.GetString(index)); } index++; } @@ -1950,12 +1953,26 @@ namespace Emby.Server.Implementations.Data return item; } + private Guid[] SplitToGuids(string value) + { + var ids = value.Split('|'); + + var result = new Guid[ids.Length]; + + for (var i = 0; i < result.Length; i++) + { + result[i] = new Guid(ids[i]); + } + + return result; + } + /// /// Gets the critic reviews. /// /// The item id. /// Task{IEnumerable{ItemReview}}. - public IEnumerable GetCriticReviews(Guid itemId) + public List GetCriticReviews(Guid itemId) { return new List(); } @@ -2206,7 +2223,7 @@ namespace Emby.Server.Implementations.Data return false; } - private List allFields = Enum.GetNames(typeof(ItemFields)) + private readonly List allFields = Enum.GetNames(typeof(ItemFields)) .Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true)) .ToList(); @@ -2548,11 +2565,11 @@ namespace Emby.Server.Implementations.Data } } - query.ExcludeItemIds = excludeIds.ToArray(); + query.ExcludeItemIds = excludeIds.ToArray(excludeIds.Count); query.ExcludeProviderIds = item.ProviderIds; } - return list.ToArray(); + return list.ToArray(list.Count); } private void BindSimilarParams(InternalItemsQuery query, IStatement statement) @@ -2595,7 +2612,7 @@ namespace Emby.Server.Implementations.Data if (groups.Count > 0) { - return " Group by " + string.Join(",", groups.ToArray()); + return " Group by " + string.Join(",", groups.ToArray(groups.Count)); } return string.Empty; @@ -2632,7 +2649,7 @@ namespace Emby.Server.Implementations.Data var whereText = whereClauses.Count == 0 ? string.Empty : - " where " + string.Join(" AND ", whereClauses.ToArray()); + " where " + string.Join(" AND ", whereClauses.ToArray(whereClauses.Count)); commandText += whereText; @@ -2689,7 +2706,7 @@ namespace Emby.Server.Implementations.Data var whereText = whereClauses.Count == 0 ? string.Empty : - " where " + string.Join(" AND ", whereClauses.ToArray()); + " where " + string.Join(" AND ", whereClauses.ToArray(whereClauses.Count)); commandText += whereText; @@ -2842,7 +2859,7 @@ namespace Emby.Server.Implementations.Data var returnList = GetItemList(query); return new QueryResult { - Items = returnList.ToArray(), + Items = returnList.ToArray(returnList.Count), TotalRecordCount = returnList.Count }; } @@ -2865,7 +2882,7 @@ namespace Emby.Server.Implementations.Data var whereText = whereClauses.Count == 0 ? string.Empty : - " where " + string.Join(" AND ", whereClauses.ToArray()); + " where " + string.Join(" AND ", whereClauses.ToArray(whereClauses.Count)); var whereTextWithoutPaging = whereText; @@ -2926,8 +2943,7 @@ namespace Emby.Server.Implementations.Data return connection.RunInTransaction(db => { var result = new QueryResult(); - var statements = PrepareAllSafe(db, statementTexts) - .ToList(); + var statements = PrepareAllSafe(db, statementTexts); if (!isReturningZeroItems) { @@ -2981,7 +2997,7 @@ namespace Emby.Server.Implementations.Data LogQueryTime("GetItems", commandText, now); - result.Items = list.ToArray(); + result.Items = list.ToArray(list.Count); return result; }, ReadTransactionMode); @@ -3133,7 +3149,7 @@ namespace Emby.Server.Implementations.Data var whereText = whereClauses.Count == 0 ? string.Empty : - " where " + string.Join(" AND ", whereClauses.ToArray()); + " where " + string.Join(" AND ", whereClauses.ToArray(whereClauses.Count)); commandText += whereText; @@ -3204,7 +3220,7 @@ namespace Emby.Server.Implementations.Data var whereText = whereClauses.Count == 0 ? string.Empty : - " where " + string.Join(" AND ", whereClauses.ToArray()); + " where " + string.Join(" AND ", whereClauses.ToArray(whereClauses.Count)); commandText += whereText; @@ -3277,7 +3293,7 @@ namespace Emby.Server.Implementations.Data var returnList = GetItemIdsList(query); return new QueryResult { - Items = returnList.ToArray(), + Items = returnList.ToArray(returnList.Count), TotalRecordCount = returnList.Count }; } @@ -3292,7 +3308,7 @@ namespace Emby.Server.Implementations.Data var whereText = whereClauses.Count == 0 ? string.Empty : - " where " + string.Join(" AND ", whereClauses.ToArray()); + " where " + string.Join(" AND ", whereClauses.ToArray(whereClauses.Count)); var whereTextWithoutPaging = whereText; @@ -3355,8 +3371,7 @@ namespace Emby.Server.Implementations.Data { var result = new QueryResult(); - var statements = PrepareAllSafe(db, statementTexts) - .ToList(); + var statements = PrepareAllSafe(db, statementTexts); if (!isReturningZeroItems) { @@ -3399,7 +3414,7 @@ namespace Emby.Server.Implementations.Data LogQueryTime("GetItemIds", commandText, now); - result.Items = list.ToArray(); + result.Items = list.ToArray(list.Count); return result; }, ReadTransactionMode); @@ -3604,7 +3619,7 @@ namespace Emby.Server.Implementations.Data } if (programAttribtues.Count > 0) { - whereClauses.Add("(" + string.Join(" OR ", programAttribtues.ToArray()) + ")"); + whereClauses.Add("(" + string.Join(" OR ", programAttribtues.ToArray(programAttribtues.Count)) + ")"); } } @@ -5129,9 +5144,9 @@ namespace Emby.Server.Implementations.Data var itemCountColumns = new List>(); - var typesToCount = query.IncludeItemTypes.ToList(); + var typesToCount = query.IncludeItemTypes; - if (typesToCount.Count > 0) + if (typesToCount.Length > 0) { var itemCountColumnQuery = "select group_concat(type, '|')" + GetFromText("B"); @@ -5191,7 +5206,7 @@ namespace Emby.Server.Implementations.Data var whereText = " where Type=@SelectType"; - if (typesToCount.Count == 0) + if (typesToCount.Length == 0) { whereText += " And CleanName In (Select CleanValue from ItemValues where " + typeClause + " AND ItemId in (select guid from TypedBaseItems" + innerWhereText + "))"; } @@ -5269,8 +5284,7 @@ namespace Emby.Server.Implementations.Data var list = new List>(); var result = new QueryResult>(); - var statements = PrepareAllSafe(db, statementTexts) - .ToList(); + var statements = PrepareAllSafe(db, statementTexts); if (!isReturningZeroItems) { @@ -5345,7 +5359,7 @@ namespace Emby.Server.Implementations.Data { result.TotalRecordCount = list.Count; } - result.Items = list.ToArray(); + result.Items = list.ToArray(list.Count); return result; @@ -5354,11 +5368,11 @@ namespace Emby.Server.Implementations.Data } } - private ItemCounts GetItemCounts(IReadOnlyList reader, int countStartColumn, List typesToCount) + private ItemCounts GetItemCounts(IReadOnlyList reader, int countStartColumn, string[] typesToCount) { var counts = new ItemCounts(); - if (typesToCount.Count == 0) + if (typesToCount.Length == 0) { return counts; } diff --git a/Emby.Server.Implementations/Dto/DtoService.cs b/Emby.Server.Implementations/Dto/DtoService.cs index daa5ff642c..098e11720b 100644 --- a/Emby.Server.Implementations/Dto/DtoService.cs +++ b/Emby.Server.Implementations/Dto/DtoService.cs @@ -649,12 +649,12 @@ namespace Emby.Server.Implementations.Dto dto.GameSystem = item.GameSystemName; } - private List GetImageTags(BaseItem item, List images) + private string[] GetImageTags(BaseItem item, List images) { return images .Select(p => GetImageCacheTag(item, p)) .Where(i => i != null) - .ToList(); + .ToArray(); } private string GetImageCacheTag(BaseItem item, ImageType type) @@ -766,7 +766,7 @@ namespace Emby.Server.Implementations.Dto } } - dto.People = list.ToArray(); + dto.People = list.ToArray(list.Count); } /// @@ -1049,12 +1049,12 @@ namespace Emby.Server.Implementations.Dto { if (!string.IsNullOrWhiteSpace(item.Tagline)) { - dto.Taglines = new List { item.Tagline }; + dto.Taglines = new string[] { item.Tagline }; } if (dto.Taglines == null) { - dto.Taglines = new List(); + dto.Taglines = new string[]{}; } } @@ -1430,9 +1430,9 @@ namespace Emby.Server.Implementations.Dto 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; } } diff --git a/Emby.Server.Implementations/Emby.Server.Implementations.csproj b/Emby.Server.Implementations/Emby.Server.Implementations.csproj index ed69c9755b..62f23bb536 100644 --- a/Emby.Server.Implementations/Emby.Server.Implementations.csproj +++ b/Emby.Server.Implementations/Emby.Server.Implementations.csproj @@ -21,6 +21,7 @@ DEBUG;TRACE prompt 4 + true pdbonly @@ -40,6 +41,8 @@ + + @@ -52,6 +55,24 @@ + + + + + + + + + + + + + + + + + + @@ -63,6 +84,7 @@ + @@ -78,6 +100,7 @@ + @@ -99,7 +122,9 @@ + + @@ -170,6 +195,8 @@ + + @@ -249,6 +276,7 @@ + @@ -260,6 +288,26 @@ + + {1e37a338-9f57-4b70-bd6d-bb9c591e319b} + Emby.Common.Implementations + + + {805844ab-e92f-45e6-9d99-4f6d48d129a5} + Emby.Dlna + + + {08fff49b-f175-4807-a2b5-73b0ebd9f716} + Emby.Drawing + + + {89ab4548-770d-41fd-a891-8daff44f452c} + Emby.Photos + + + {4fd51ac5-2c16-4308-a993-c3a84f3b4582} + MediaBrowser.Api + {9142eefa-7570-41e1-bfcc-468bb571af2f} MediaBrowser.Common @@ -268,6 +316,10 @@ {17e1f4e6-8abd-4fe5-9ecf-43d4b6087ba2} MediaBrowser.Controller + + {7ef9f3e0-697d-42f3-a08f-19deb5f84392} + MediaBrowser.LocalMetadata + {7eeeb4bb-f3e8-48fc-b4c5-70f0fff8329b} MediaBrowser.Model @@ -280,10 +332,29 @@ {2e781478-814d-4a48-9d80-bff206441a65} MediaBrowser.Server.Implementations + + {5624b7b5-b5a7-41d8-9f10-cc5611109619} + MediaBrowser.WebDashboard + + + {23499896-b135-4527-8574-c26e926ea99e} + MediaBrowser.XbmcMetadata + + + {cb7f2326-6497-4a3d-ba03-48513b17a7be} + Mono.Nat + + + {4a4402d4-e910-443b-b8fc-2c18286a2ca0} + OpenSubtitlesHandler + {1d74413b-e7cf-455b-b021-f52bdf881542} SocketHttpListener + + ..\ThirdParty\emby\Emby.Server.MediaEncoding.dll + ..\packages\Emby.XmlTv.1.0.9\lib\portable-net45+win8\Emby.XmlTv.dll True @@ -292,6 +363,15 @@ ..\packages\MediaBrowser.Naming.1.0.5\lib\portable-net45+win8\MediaBrowser.Naming.dll True + + ..\packages\Microsoft.IO.RecyclableMemoryStream.1.2.2\lib\net45\Microsoft.IO.RecyclableMemoryStream.dll + + + ..\packages\ServiceStack.Text.4.5.12\lib\net45\ServiceStack.Text.dll + + + ..\packages\SimpleInjector.4.0.8\lib\net45\SimpleInjector.dll + ..\packages\SQLitePCL.pretty.1.1.0\lib\portable-net45+netcore45+wpa81+wp8\SQLitePCL.pretty.dll True @@ -299,10 +379,10 @@ - ..\packages\SQLitePCLRaw.core.1.1.7\lib\net45\SQLitePCLRaw.core.dll - True + ..\packages\SQLitePCLRaw.core.1.1.8\lib\net45\SQLitePCLRaw.core.dll + diff --git a/Emby.Server.Core/EntryPoints/ExternalPortForwarding.cs b/Emby.Server.Implementations/EntryPoints/ExternalPortForwarding.cs similarity index 98% rename from Emby.Server.Core/EntryPoints/ExternalPortForwarding.cs rename to Emby.Server.Implementations/EntryPoints/ExternalPortForwarding.cs index 2c7e6a4870..c96799b2f8 100644 --- a/Emby.Server.Core/EntryPoints/ExternalPortForwarding.cs +++ b/Emby.Server.Implementations/EntryPoints/ExternalPortForwarding.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Globalization; using System.Net; +using System.Threading.Tasks; using MediaBrowser.Common.Net; using MediaBrowser.Controller; using MediaBrowser.Controller.Configuration; @@ -11,9 +12,9 @@ using MediaBrowser.Model.Events; using MediaBrowser.Model.Logging; using MediaBrowser.Model.Threading; 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 { @@ -50,7 +51,7 @@ namespace Emby.Server.Core.EntryPoints values.Add(config.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) diff --git a/Emby.Server.Implementations/EntryPoints/UsageEntryPoint.cs b/Emby.Server.Implementations/EntryPoints/UsageEntryPoint.cs index 9fbe06673f..99d39ffe02 100644 --- a/Emby.Server.Implementations/EntryPoints/UsageEntryPoint.cs +++ b/Emby.Server.Implementations/EntryPoints/UsageEntryPoint.cs @@ -12,6 +12,7 @@ using System.Threading; using System.Threading.Tasks; using MediaBrowser.Controller; using MediaBrowser.Controller.Configuration; +using MediaBrowser.Model.Extensions; namespace Emby.Server.Implementations.EntryPoints { @@ -58,7 +59,7 @@ namespace Emby.Server.Implementations.EntryPoints session.ApplicationVersion }; - var key = string.Join("_", keys.ToArray()).GetMD5(); + var key = string.Join("_", keys.ToArray(keys.Count)).GetMD5(); _apps.GetOrAdd(key, guid => GetNewClientInfo(session)); } diff --git a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs index 05f78eba95..f150e47859 100644 --- a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs +++ b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs @@ -125,13 +125,6 @@ namespace Emby.Server.Implementations.HttpServer return _appHost.CreateInstance(type); } - private ServiceController CreateServiceController() - { - var types = _restServices.Select(r => r.GetType()).ToArray(); - - return new ServiceController(() => types); - } - /// /// Applies the request filters. Returns whether or not the request has been handled /// and no more processing should be done. @@ -186,7 +179,7 @@ namespace Emby.Server.Implementations.HttpServer attributes.Sort((x, y) => x.Priority - y.Priority); - return attributes.ToArray(); + return attributes.ToArray(attributes.Count); } /// @@ -697,11 +690,13 @@ namespace Emby.Server.Implementations.HttpServer { _restServices.AddRange(services); - ServiceController = CreateServiceController(); + ServiceController = new ServiceController(); _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().ToList(); foreach (var filter in requestFilters) @@ -741,7 +736,7 @@ namespace Emby.Server.Implementations.HttpServer }); } - return routes.ToArray(); + return routes.ToArray(routes.Count); } public Func GetParseFn(Type propertyType) diff --git a/Emby.Server.Implementations/HttpServer/LoggerUtils.cs b/Emby.Server.Implementations/HttpServer/LoggerUtils.cs index f0e75eea48..de30dc30a8 100644 --- a/Emby.Server.Implementations/HttpServer/LoggerUtils.cs +++ b/Emby.Server.Implementations/HttpServer/LoggerUtils.cs @@ -4,6 +4,7 @@ using System.Globalization; using System.Linq; using MediaBrowser.Model.Services; using SocketHttpListener.Net; +using MediaBrowser.Model.Extensions; namespace Emby.Server.Implementations.HttpServer { @@ -29,7 +30,7 @@ namespace Emby.Server.Implementations.HttpServer } 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); } diff --git a/Emby.Server.Implementations/HttpServer/SocketSharp/HttpUtility.cs b/Emby.Server.Implementations/HttpServer/SocketSharp/HttpUtility.cs index 4fbe0ed946..4e8dd73626 100644 --- a/Emby.Server.Implementations/HttpServer/SocketSharp/HttpUtility.cs +++ b/Emby.Server.Implementations/HttpServer/SocketSharp/HttpUtility.cs @@ -3,6 +3,7 @@ using System.Collections; using System.Collections.Generic; using System.Text; using MediaBrowser.Model.Services; +using MediaBrowser.Model.Extensions; namespace Emby.Server.Implementations.HttpServer.SocketSharp { @@ -585,7 +586,7 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp WriteCharBytes(bytes, ch, e); } - byte[] buf = bytes.ToArray(); + byte[] buf = bytes.ToArray(bytes.Count); bytes = null; return e.GetString(buf, 0, buf.Length); diff --git a/Emby.Server.Core/HttpServerFactory.cs b/Emby.Server.Implementations/HttpServerFactory.cs similarity index 97% rename from Emby.Server.Core/HttpServerFactory.cs rename to Emby.Server.Implementations/HttpServerFactory.cs index e16cbea0e3..b1d78e6f42 100644 --- a/Emby.Server.Core/HttpServerFactory.cs +++ b/Emby.Server.Implementations/HttpServerFactory.cs @@ -1,9 +1,7 @@ using System; using System.IO; using System.Net.Security; -using System.Net.Sockets; using System.Security.Cryptography.X509Certificates; -using System.Threading; using System.Threading.Tasks; using Emby.Common.Implementations.Net; using Emby.Server.Implementations.HttpServer; @@ -21,7 +19,7 @@ using MediaBrowser.Model.Text; using ServiceStack.Text.Jsv; using SocketHttpListener.Primitives; -namespace Emby.Server.Core +namespace Emby.Server.Implementations { /// /// Class ServerFactory diff --git a/Emby.Server.Core/IO/LibraryMonitor.cs b/Emby.Server.Implementations/IO/LibraryMonitor.cs similarity index 99% rename from Emby.Server.Core/IO/LibraryMonitor.cs rename to Emby.Server.Implementations/IO/LibraryMonitor.cs index ebc5e5e558..c452c01be3 100644 --- a/Emby.Server.Core/IO/LibraryMonitor.cs +++ b/Emby.Server.Implementations/IO/LibraryMonitor.cs @@ -13,9 +13,8 @@ using MediaBrowser.Model.Logging; using MediaBrowser.Model.System; using MediaBrowser.Model.Tasks; using MediaBrowser.Model.Threading; -using Emby.Server.Implementations.IO; -namespace Emby.Server.Core.IO +namespace Emby.Server.Implementations.IO { public class LibraryMonitor : ILibraryMonitor { diff --git a/Emby.Server.Core/IO/MemoryStreamProvider.cs b/Emby.Server.Implementations/IO/MemoryStreamProvider.cs similarity index 97% rename from Emby.Server.Core/IO/MemoryStreamProvider.cs rename to Emby.Server.Implementations/IO/MemoryStreamProvider.cs index f6dd1ecbc2..eca76203c5 100644 --- a/Emby.Server.Core/IO/MemoryStreamProvider.cs +++ b/Emby.Server.Implementations/IO/MemoryStreamProvider.cs @@ -2,7 +2,7 @@ using MediaBrowser.Model.IO; using Microsoft.IO; -namespace Emby.Server.Core.IO +namespace Emby.Server.Implementations.IO { public class RecyclableMemoryStreamProvider : IMemoryStreamFactory { diff --git a/Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs b/Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs index 8e6f63f722..3f9ea79c6a 100644 --- a/Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs +++ b/Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs @@ -293,20 +293,16 @@ namespace Emby.Server.Implementations.Images return true; } - protected List GetFinalItems(List items) + protected List GetFinalItems(IEnumerable items) { return GetFinalItems(items, 4); } - protected virtual List GetFinalItems(List items, int limit) + protected virtual List GetFinalItems(IEnumerable items, int limit) { - // Rotate the images once every x days - var random = DateTime.Now.DayOfYear % MaxImageAgeDays; - return items - .OrderBy(i => (random + string.Empty + items.IndexOf(i)).GetMD5()) + .OrderBy(i => Guid.NewGuid()) .Take(limit) - .OrderBy(i => i.Name) .ToList(); } diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index 5c7dc2507c..271dac1538 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -136,14 +136,6 @@ namespace Emby.Server.Implementations.Library /// The configuration manager. private IServerConfigurationManager ConfigurationManager { get; set; } - /// - /// 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. - /// - /// The by reference items. - private ConcurrentDictionary ByReferenceItems { get; set; } - private readonly Func _libraryMonitorFactory; private readonly Func _providerManagerFactory; private readonly Func _userviewManager; @@ -186,7 +178,6 @@ namespace Emby.Server.Implementations.Library _fileSystem = fileSystem; _providerManagerFactory = providerManagerFactory; _userviewManager = userviewManager; - ByReferenceItems = new ConcurrentDictionary(); _libraryItemsCache = new ConcurrentDictionary(); ConfigurationManager.ConfigurationUpdated += ConfigurationUpdated; @@ -560,22 +551,6 @@ namespace Emby.Server.Implementations.Library return key.GetMD5(); } - /// - /// Ensure supplied item has only one instance throughout - /// - /// The item. - /// The proper instance to the item - 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, Folder parent = null) { @@ -1298,7 +1273,7 @@ namespace Emby.Server.Implementations.Library return item; } - public IEnumerable GetItemList(InternalItemsQuery query, bool allowExternalContent) + public List GetItemList(InternalItemsQuery query, bool allowExternalContent) { if (query.Recursive && query.ParentId.HasValue) { @@ -1317,7 +1292,7 @@ namespace Emby.Server.Implementations.Library return ItemRepository.GetItemList(query); } - public IEnumerable GetItemList(InternalItemsQuery query) + public List GetItemList(InternalItemsQuery query) { return GetItemList(query, true); } @@ -1341,7 +1316,7 @@ namespace Emby.Server.Implementations.Library return ItemRepository.GetCount(query); } - public IEnumerable GetItemList(InternalItemsQuery query, List parents) + public List GetItemList(InternalItemsQuery query, List parents) { SetTopParentIdsOrAncestors(query, parents); @@ -1515,9 +1490,11 @@ namespace Emby.Server.Implementations.Library return ItemRepository.GetItems(query); } + var list = ItemRepository.GetItemList(query); + return new QueryResult { - Items = ItemRepository.GetItemList(query).ToArray() + Items = list.ToArray(list.Count) }; } @@ -2610,7 +2587,7 @@ namespace Emby.Server.Implementations.Library var resolvers = new IItemResolver[] { - new GenericVideoResolver(this) + new GenericVideoResolver(this, _fileSystem) }; return ResolvePaths(files, directoryService, null, new LibraryOptions(), null, resolvers) diff --git a/Emby.Server.Implementations/Library/LocalTrailerPostScanTask.cs b/Emby.Server.Implementations/Library/LocalTrailerPostScanTask.cs index e64980dff8..83bee89e05 100644 --- a/Emby.Server.Implementations/Library/LocalTrailerPostScanTask.cs +++ b/Emby.Server.Implementations/Library/LocalTrailerPostScanTask.cs @@ -3,6 +3,7 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; using MediaBrowser.Model.Entities; using System; +using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -45,7 +46,7 @@ namespace Emby.Server.Implementations.Library Recursive = true, DtoOptions = new DtoOptions(false) - }).ToArray(); + }); var numComplete = 0; @@ -64,7 +65,7 @@ namespace Emby.Server.Implementations.Library progress.Report(100); } - private async Task AssignTrailers(IHasTrailers item, BaseItem[] channelTrailers) + private async Task AssignTrailers(IHasTrailers item, IEnumerable channelTrailers) { if (item is Game) { diff --git a/Emby.Server.Implementations/Library/MusicManager.cs b/Emby.Server.Implementations/Library/MusicManager.cs index f0d07cc3c4..7f77170ad6 100644 --- a/Emby.Server.Implementations/Library/MusicManager.cs +++ b/Emby.Server.Implementations/Library/MusicManager.cs @@ -19,27 +19,27 @@ namespace Emby.Server.Implementations.Library _libraryManager = libraryManager; } - public IEnumerable public class EpisodeResolver : BaseVideoResolver { - public EpisodeResolver(ILibraryManager libraryManager) : base(libraryManager) - { - } - /// /// Resolves the specified args. /// @@ -76,5 +73,9 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV return null; } + + public EpisodeResolver(ILibraryManager libraryManager, IFileSystem fileSystem) : base(libraryManager, fileSystem) + { + } } } diff --git a/Emby.Server.Implementations/Library/Resolvers/VideoResolver.cs b/Emby.Server.Implementations/Library/Resolvers/VideoResolver.cs index b5e1bf5f74..5c7a528f54 100644 --- a/Emby.Server.Implementations/Library/Resolvers/VideoResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/VideoResolver.cs @@ -1,6 +1,7 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Resolvers; +using MediaBrowser.Model.IO; namespace Emby.Server.Implementations.Library.Resolvers { @@ -9,11 +10,6 @@ namespace Emby.Server.Implementations.Library.Resolvers /// public class VideoResolver : BaseVideoResolver /// IEnumerable{CultureDto}. - public IEnumerable GetCultures() + public List GetCultures() { var type = GetType(); var path = type.Namespace + ".iso6392.txt"; @@ -169,14 +169,14 @@ namespace Emby.Server.Implementations.Localization return list.Where(i => !string.IsNullOrWhiteSpace(i.Name) && !string.IsNullOrWhiteSpace(i.DisplayName) && !string.IsNullOrWhiteSpace(i.ThreeLetterISOLanguageName) && - !string.IsNullOrWhiteSpace(i.TwoLetterISOLanguageName)); + !string.IsNullOrWhiteSpace(i.TwoLetterISOLanguageName)).ToList(); } /// /// Gets the countries. /// /// IEnumerable{CountryInfo}. - public IEnumerable GetCountries() + public List GetCountries() { var type = GetType(); var path = type.Namespace + ".countries.json"; diff --git a/Emby.Server.Core/Localization/TextLocalizer.cs b/Emby.Server.Implementations/Localization/TextLocalizer.cs similarity index 95% rename from Emby.Server.Core/Localization/TextLocalizer.cs rename to Emby.Server.Implementations/Localization/TextLocalizer.cs index 1e8ccbbfa8..5188a959e3 100644 --- a/Emby.Server.Core/Localization/TextLocalizer.cs +++ b/Emby.Server.Implementations/Localization/TextLocalizer.cs @@ -3,9 +3,8 @@ using System.Globalization; using System.Linq; using System.Text; using System.Text.RegularExpressions; -using Emby.Server.Implementations.Localization; -namespace Emby.Server.Core.Localization +namespace Emby.Server.Implementations.Localization { public class TextLocalizer : ITextLocalizer { diff --git a/Emby.Server.Core/Logging/ConsoleLogger.cs b/Emby.Server.Implementations/Logging/ConsoleLogger.cs similarity index 65% rename from Emby.Server.Core/Logging/ConsoleLogger.cs rename to Emby.Server.Implementations/Logging/ConsoleLogger.cs index 01eca7b7e4..51199f08ae 100644 --- a/Emby.Server.Core/Logging/ConsoleLogger.cs +++ b/Emby.Server.Implementations/Logging/ConsoleLogger.cs @@ -1,10 +1,7 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; using MediaBrowser.Model.Logging; -namespace Emby.Server.Core.Logging +namespace Emby.Server.Implementations.Logging { public class ConsoleLogger : IConsoleLogger { diff --git a/Emby.Server.Implementations/Notifications/SqliteNotificationsRepository.cs b/Emby.Server.Implementations/Notifications/SqliteNotificationsRepository.cs index 40752db800..ff152c9e9c 100644 --- a/Emby.Server.Implementations/Notifications/SqliteNotificationsRepository.cs +++ b/Emby.Server.Implementations/Notifications/SqliteNotificationsRepository.cs @@ -12,6 +12,7 @@ using MediaBrowser.Model.IO; using MediaBrowser.Model.Logging; using MediaBrowser.Model.Notifications; using SQLitePCL.pretty; +using MediaBrowser.Model.Extensions; namespace Emby.Server.Implementations.Notifications { @@ -83,13 +84,13 @@ namespace Emby.Server.Implementations.Notifications clauses.Add("UserId=?"); paramList.Add(query.UserId.ToGuidBlob()); - var whereClause = " where " + string.Join(" And ", clauses.ToArray()); + var whereClause = " where " + string.Join(" And ", clauses.ToArray(clauses.Count)); using (WriteLock.Read()) { using (var connection = CreateConnection(true)) { - result.TotalRecordCount = connection.Query("select count(Id) from Notifications" + whereClause, paramList.ToArray()).SelectScalarInt().First(); + result.TotalRecordCount = connection.Query("select count(Id) from Notifications" + whereClause, paramList.ToArray(paramList.Count)).SelectScalarInt().First(); var commandText = string.Format("select Id,UserId,Date,Name,Description,Url,Level,IsRead,Category,RelatedId from Notifications{0} order by IsRead asc, Date desc", whereClause); @@ -110,12 +111,12 @@ namespace Emby.Server.Implementations.Notifications var resultList = new List(); - foreach (var row in connection.Query(commandText, paramList.ToArray())) + foreach (var row in connection.Query(commandText, paramList.ToArray(paramList.Count))) { resultList.Add(GetNotification(row)); } - result.Notifications = resultList.ToArray(); + result.Notifications = resultList.ToArray(resultList.Count); } } @@ -280,7 +281,7 @@ namespace Emby.Server.Implementations.Notifications public async Task MarkRead(IEnumerable notificationIdList, string userId, bool isRead, CancellationToken cancellationToken) { var list = notificationIdList.ToList(); - var idArray = list.Select(i => new Guid(i)).ToArray(); + var idArray = list.Select(i => new Guid(i)).ToArray(list.Count); await MarkReadInternal(idArray, userId, isRead, cancellationToken).ConfigureAwait(false); @@ -290,7 +291,7 @@ namespace Emby.Server.Implementations.Notifications { NotificationsMarkedRead(this, new NotificationReadEventArgs { - IdList = list.ToArray(), + IdList = list.ToArray(list.Count), IsRead = isRead, UserId = userId }); diff --git a/Emby.Server.Implementations/Notifications/WebSocketNotifier.cs b/Emby.Server.Implementations/Notifications/WebSocketNotifier.cs index 0239ee3365..0d89ba84f3 100644 --- a/Emby.Server.Implementations/Notifications/WebSocketNotifier.cs +++ b/Emby.Server.Implementations/Notifications/WebSocketNotifier.cs @@ -2,6 +2,7 @@ using MediaBrowser.Controller.Notifications; using MediaBrowser.Controller.Plugins; using System.Linq; +using MediaBrowser.Model.Extensions; namespace Emby.Server.Implementations.Notifications { @@ -33,7 +34,7 @@ namespace Emby.Server.Implementations.Notifications list.Add(e.UserId); list.Add(e.IsRead.ToString().ToLower()); - var msg = string.Join("|", list.ToArray()); + var msg = string.Join("|", list.ToArray(list.Count)); _serverManager.SendWebSocketMessage("NotificationsMarkedRead", msg); } diff --git a/Emby.Server.Implementations/Photos/PhotoAlbumImageProvider.cs b/Emby.Server.Implementations/Photos/PhotoAlbumImageProvider.cs index e232854251..f7c65f63d7 100644 --- a/Emby.Server.Implementations/Photos/PhotoAlbumImageProvider.cs +++ b/Emby.Server.Implementations/Photos/PhotoAlbumImageProvider.cs @@ -21,7 +21,7 @@ namespace Emby.Server.Implementations.Photos protected override List GetItemsWithImages(IHasMetadata item) { var photoAlbum = (PhotoAlbum)item; - var items = GetFinalItems(photoAlbum.Children.ToList()); + var items = GetFinalItems(photoAlbum.Children); return items; } diff --git a/Emby.Server.Implementations/Playlists/PlaylistImageProvider.cs b/Emby.Server.Implementations/Playlists/PlaylistImageProvider.cs index f5d0e314e8..c2e8603396 100644 --- a/Emby.Server.Implementations/Playlists/PlaylistImageProvider.cs +++ b/Emby.Server.Implementations/Playlists/PlaylistImageProvider.cs @@ -65,8 +65,7 @@ namespace Emby.Server.Implementations.Playlists return null; }) .Where(i => i != null) - .DistinctBy(i => i.Id) - .ToList(); + .DistinctBy(i => i.Id); return GetFinalItems(items); } @@ -93,7 +92,7 @@ namespace Emby.Server.Implementations.Playlists ImageTypes = new[] { ImageType.Primary }, DtoOptions = new DtoOptions(false) - }).ToList(); + }); return GetFinalItems(items); } @@ -125,7 +124,7 @@ namespace Emby.Server.Implementations.Playlists ImageTypes = new[] { ImageType.Primary }, DtoOptions = new DtoOptions(false) - }).ToList(); + }); return GetFinalItems(items); } diff --git a/Emby.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs b/Emby.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs index 967e7ddd86..91ae2afd1c 100644 --- a/Emby.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs +++ b/Emby.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs @@ -15,6 +15,7 @@ using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Tasks; +using MediaBrowser.Model.Extensions; namespace Emby.Server.Implementations.ScheduledTasks { @@ -142,7 +143,7 @@ namespace Emby.Server.Implementations.ScheduledTasks _fileSystem.CreateDirectory(parentPath); - _fileSystem.WriteAllText(failHistoryPath, string.Join("|", previouslyFailedImages.ToArray())); + _fileSystem.WriteAllText(failHistoryPath, string.Join("|", previouslyFailedImages.ToArray(previouslyFailedImages.Count))); } numComplete++; diff --git a/Emby.Server.Implementations/Security/AuthenticationRepository.cs b/Emby.Server.Implementations/Security/AuthenticationRepository.cs index 9ec0af6bb5..d512ff4fb9 100644 --- a/Emby.Server.Implementations/Security/AuthenticationRepository.cs +++ b/Emby.Server.Implementations/Security/AuthenticationRepository.cs @@ -11,6 +11,7 @@ using MediaBrowser.Controller.Security; using MediaBrowser.Model.Logging; using MediaBrowser.Model.Querying; using SQLitePCL.pretty; +using MediaBrowser.Model.Extensions; namespace Emby.Server.Implementations.Security { @@ -174,13 +175,13 @@ namespace Emby.Server.Implementations.Security var whereTextWithoutPaging = whereClauses.Count == 0 ? string.Empty : - " where " + string.Join(" AND ", whereClauses.ToArray()); + " where " + string.Join(" AND ", whereClauses.ToArray(whereClauses.Count)); if (startIndex > 0) { var pagingWhereText = whereClauses.Count == 0 ? string.Empty : - " where " + string.Join(" AND ", whereClauses.ToArray()); + " where " + string.Join(" AND ", whereClauses.ToArray(whereClauses.Count)); whereClauses.Add(string.Format("Id NOT IN (SELECT Id FROM AccessTokens {0} ORDER BY DateCreated LIMIT {1})", pagingWhereText, @@ -189,7 +190,7 @@ namespace Emby.Server.Implementations.Security var whereText = whereClauses.Count == 0 ? string.Empty : - " where " + string.Join(" AND ", whereClauses.ToArray()); + " where " + string.Join(" AND ", whereClauses.ToArray(whereClauses.Count)); commandText += whereText; @@ -236,7 +237,7 @@ namespace Emby.Server.Implementations.Security } } - result.Items = list.ToArray(); + result.Items = list.ToArray(list.Count); return result; }, ReadTransactionMode); diff --git a/Emby.Server.Implementations/Services/ServiceController.cs b/Emby.Server.Implementations/Services/ServiceController.cs index 1c530144c9..4ad56411ad 100644 --- a/Emby.Server.Implementations/Services/ServiceController.cs +++ b/Emby.Server.Implementations/Services/ServiceController.cs @@ -15,17 +15,15 @@ namespace Emby.Server.Implementations.Services public class ServiceController { public static ServiceController Instance; - private readonly Func> _resolveServicesFn; - public ServiceController(Func> resolveServicesFn) + public ServiceController() { Instance = this; - _resolveServicesFn = resolveServicesFn; } - public void Init(HttpListenerHost appHost) + public void Init(HttpListenerHost appHost, Type[] serviceTypes) { - foreach (var serviceType in _resolveServicesFn()) + foreach (var serviceType in serviceTypes) { RegisterService(appHost, serviceType); } diff --git a/Emby.Server.Implementations/Services/ServiceExec.cs b/Emby.Server.Implementations/Services/ServiceExec.cs index e0b5e69c09..4a2199c89d 100644 --- a/Emby.Server.Implementations/Services/ServiceExec.cs +++ b/Emby.Server.Implementations/Services/ServiceExec.cs @@ -5,6 +5,7 @@ using System.Linq.Expressions; using System.Reflection; using System.Threading.Tasks; using MediaBrowser.Model.Services; +using MediaBrowser.Model.Extensions; namespace Emby.Server.Implementations.Services { @@ -123,7 +124,7 @@ namespace Emby.Server.Implementations.Services } if (reqFilters.Count > 0) - actionCtx.RequestFilters = reqFilters.OrderBy(i => i.Priority).ToArray(); + actionCtx.RequestFilters = reqFilters.OrderBy(i => i.Priority).ToArray(reqFilters.Count); actions.Add(actionCtx); } diff --git a/Emby.Server.Implementations/Services/ServicePath.cs b/Emby.Server.Implementations/Services/ServicePath.cs index 255b209192..da5e74f1fb 100644 --- a/Emby.Server.Implementations/Services/ServicePath.cs +++ b/Emby.Server.Implementations/Services/ServicePath.cs @@ -5,6 +5,7 @@ using System.Linq; using System.Reflection; using System.Text; using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Extensions; namespace Emby.Server.Implementations.Services { @@ -142,13 +143,13 @@ namespace Emby.Server.Implementations.Services } } - var components = componentsList.ToArray(); + var components = componentsList.ToArray(componentsList.Count); this.TotalComponentsCount = components.Length; this.literalsToMatch = new string[this.TotalComponentsCount]; this.variablesNames = new string[this.TotalComponentsCount]; this.isWildcard = new bool[this.TotalComponentsCount]; - this.componentsWithSeparators = hasSeparators.ToArray(); + this.componentsWithSeparators = hasSeparators.ToArray(hasSeparators.Count); this.PathComponentsCount = this.componentsWithSeparators.Length; string firstLiteralMatch = null; @@ -268,7 +269,7 @@ namespace Emby.Server.Implementations.Services propertyInfos.InsertRange(0, newPropertyInfos); } - return propertyInfos.ToArray(); + return propertyInfos.ToArray(propertyInfos.Count); } return GetTypesPublicProperties(type) @@ -285,7 +286,7 @@ namespace Emby.Server.Implementations.Services if (mi != null && mi.IsStatic) continue; pis.Add(pi); } - return pis.ToArray(); + return pis.ToArray(pis.Count); } @@ -450,7 +451,7 @@ namespace Emby.Server.Implementations.Services } } - withPathInfoParts = totalComponents.ToArray(); + withPathInfoParts = totalComponents.ToArray(totalComponents.Count); return true; } diff --git a/Emby.Server.Implementations/Session/SessionManager.cs b/Emby.Server.Implementations/Session/SessionManager.cs index 763ca9f24c..0b39cfc477 100644 --- a/Emby.Server.Implementations/Session/SessionManager.cs +++ b/Emby.Server.Implementations/Session/SessionManager.cs @@ -32,6 +32,7 @@ using System.Threading.Tasks; using MediaBrowser.Controller.Net; using MediaBrowser.Model.Querying; using MediaBrowser.Model.Threading; +using MediaBrowser.Model.Extensions; namespace Emby.Server.Implementations.Session { @@ -1000,7 +1001,7 @@ namespace Emby.Server.Implementations.Session command.PlayCommand = PlayCommand.PlayNow; } - command.ItemIds = items.Select(i => i.Id.ToString("N")).ToArray(); + command.ItemIds = items.Select(i => i.Id.ToString("N")).ToArray(items.Count); if (user != null) { @@ -1033,7 +1034,7 @@ namespace Emby.Server.Implementations.Session if (episodes.Count > 0) { - command.ItemIds = episodes.Select(i => i.Id.ToString("N")).ToArray(); + command.ItemIds = episodes.Select(i => i.Id.ToString("N")).ToArray(episodes.Count); } } } diff --git a/Emby.Server.Implementations/Social/SharingRepository.cs b/Emby.Server.Implementations/Social/SharingRepository.cs index 46e9205bb2..a2a1f879a2 100644 --- a/Emby.Server.Implementations/Social/SharingRepository.cs +++ b/Emby.Server.Implementations/Social/SharingRepository.cs @@ -8,6 +8,7 @@ using MediaBrowser.Common.Configuration; using MediaBrowser.Model.Logging; using MediaBrowser.Model.Social; using SQLitePCL.pretty; +using MediaBrowser.Model.Extensions; namespace Emby.Server.Implementations.Social { @@ -86,7 +87,7 @@ namespace Emby.Server.Implementations.Social var paramList = new List(); paramList.Add(id.ToGuidBlob()); - foreach (var row in connection.Query(commandText, paramList.ToArray())) + foreach (var row in connection.Query(commandText, paramList.ToArray(paramList.Count))) { return GetSocialShareInfo(row); } diff --git a/Emby.Server.Core/SystemEvents.cs b/Emby.Server.Implementations/SystemEvents.cs similarity index 97% rename from Emby.Server.Core/SystemEvents.cs rename to Emby.Server.Implementations/SystemEvents.cs index 8d5cd4ad8c..dfff92f1ef 100644 --- a/Emby.Server.Core/SystemEvents.cs +++ b/Emby.Server.Implementations/SystemEvents.cs @@ -3,7 +3,7 @@ using MediaBrowser.Common.Events; using MediaBrowser.Model.Logging; using MediaBrowser.Model.System; -namespace MediaBrowser.Server.Startup.Common +namespace Emby.Server.Implementations { public class SystemEvents : ISystemEvents { diff --git a/Emby.Server.Implementations/UserViews/CollectionFolderImageProvider.cs b/Emby.Server.Implementations/UserViews/CollectionFolderImageProvider.cs index ac5bd128aa..98e0c4080a 100644 --- a/Emby.Server.Implementations/UserViews/CollectionFolderImageProvider.cs +++ b/Emby.Server.Implementations/UserViews/CollectionFolderImageProvider.cs @@ -91,7 +91,7 @@ namespace Emby.Server.Implementations.UserViews }).DistinctBy(i => i.Id); - return GetFinalItems(items.Where(i => i.HasImage(ImageType.Primary) || i.HasImage(ImageType.Thumb)).ToList(), 8); + return GetFinalItems(items.Where(i => i.HasImage(ImageType.Primary) || i.HasImage(ImageType.Thumb)), 8); } protected override bool Supports(IHasMetadata item) @@ -149,7 +149,7 @@ namespace Emby.Server.Implementations.UserViews DtoOptions = new DtoOptions(false) }); - return GetFinalItems(items.Where(i => i.HasImage(ImageType.Primary) || i.HasImage(ImageType.Thumb)).ToList(), 8); + return GetFinalItems(items.Where(i => i.HasImage(ImageType.Primary) || i.HasImage(ImageType.Thumb)), 8); } protected override bool Supports(IHasMetadata item) diff --git a/Emby.Server.Implementations/UserViews/DynamicImageProvider.cs b/Emby.Server.Implementations/UserViews/DynamicImageProvider.cs index 6805080aa6..885dfec58b 100644 --- a/Emby.Server.Implementations/UserViews/DynamicImageProvider.cs +++ b/Emby.Server.Implementations/UserViews/DynamicImageProvider.cs @@ -62,9 +62,9 @@ namespace Emby.Server.Implementations.UserViews IsMovie = true, DtoOptions = new DtoOptions(false) - }).ToList(); + }); - return GetFinalItems(programs).ToList(); + return GetFinalItems(programs); } if (string.Equals(view.ViewType, SpecialFolder.MovieGenre, StringComparison.OrdinalIgnoreCase) || @@ -133,10 +133,10 @@ namespace Emby.Server.Implementations.UserViews if (isUsingCollectionStrip) { - return GetFinalItems(items.Where(i => i.HasImage(ImageType.Primary) || i.HasImage(ImageType.Thumb)).ToList(), 8); + return GetFinalItems(items.Where(i => i.HasImage(ImageType.Primary) || i.HasImage(ImageType.Thumb)), 8); } - return GetFinalItems(items.Where(i => i.HasImage(ImageType.Primary)).ToList()); + return GetFinalItems(items.Where(i => i.HasImage(ImageType.Primary))); } protected override bool Supports(IHasMetadata item) diff --git a/Emby.Server.Implementations/packages.config b/Emby.Server.Implementations/packages.config index 03336c936a..c86812ee00 100644 --- a/Emby.Server.Implementations/packages.config +++ b/Emby.Server.Implementations/packages.config @@ -2,6 +2,9 @@ + + + - + \ No newline at end of file diff --git a/MediaBrowser.Api/ApiEntryPoint.cs b/MediaBrowser.Api/ApiEntryPoint.cs index 34d0bd413a..21552617da 100644 --- a/MediaBrowser.Api/ApiEntryPoint.cs +++ b/MediaBrowser.Api/ApiEntryPoint.cs @@ -1,27 +1,15 @@ -using MediaBrowser.Api.Playback; -using MediaBrowser.Common.Configuration; +using System; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Net; using MediaBrowser.Controller.Plugins; using MediaBrowser.Controller.Session; -using MediaBrowser.Model.Configuration; -using MediaBrowser.Model.Logging; -using MediaBrowser.Model.Session; -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; - -using MediaBrowser.Controller.MediaEncoding; -using MediaBrowser.Controller.Net; using MediaBrowser.Model.Diagnostics; using MediaBrowser.Model.IO; -using MediaBrowser.Model.Dto; +using MediaBrowser.Model.Logging; using MediaBrowser.Model.Threading; +using System.Collections.Generic; +using System.Threading; namespace MediaBrowser.Api { @@ -53,11 +41,6 @@ namespace MediaBrowser.Api public readonly ITimerFactory TimerFactory; public readonly IProcessFactory ProcessFactory; - /// - /// The active transcoding jobs - /// - private readonly List _activeTranscodingJobs = new List(); - private readonly Dictionary _transcodingLocks = new Dictionary(); @@ -81,39 +64,21 @@ namespace MediaBrowser.Api ResultFactory = resultFactory; Instance = this; - _sessionManager.PlaybackProgress += _sessionManager_PlaybackProgress; - _sessionManager.PlaybackStart += _sessionManager_PlaybackStart; } - public SemaphoreSlim GetTranscodingLock(string outputPath) + public static string[] Split(string value, char separator, bool removeEmpty) { - lock (_transcodingLocks) + if (string.IsNullOrWhiteSpace(value)) { - SemaphoreSlim result; - if (!_transcodingLocks.TryGetValue(outputPath, out result)) - { - result = new SemaphoreSlim(1, 1); - _transcodingLocks[outputPath] = result; - } - - return result; + return new string[] { }; } - } - private void _sessionManager_PlaybackStart(object sender, PlaybackProgressEventArgs e) - { - if (!string.IsNullOrWhiteSpace(e.PlaySessionId)) + if (removeEmpty) { - PingTranscodingJob(e.PlaySessionId, e.IsPaused); + return value.Split(new[] { separator }, StringSplitOptions.RemoveEmptyEntries); } - } - void _sessionManager_PlaybackProgress(object sender, PlaybackProgressEventArgs e) - { - if (!string.IsNullOrWhiteSpace(e.PlaySessionId)) - { - PingTranscodingJob(e.PlaySessionId, e.IsPaused); - } + return value.Split(separator); } /// @@ -121,41 +86,6 @@ namespace MediaBrowser.Api /// public void Run() { - try - { - DeleteEncodedMediaCache(); - } - catch (FileNotFoundException) - { - // Don't clutter the log - } - catch (IOException) - { - // Don't clutter the log - } - catch (Exception ex) - { - Logger.ErrorException("Error deleting encoded media cache", ex); - } - } - - public EncodingOptions GetEncodingOptions() - { - return _config.GetConfiguration("encoding"); - } - - /// - /// Deletes the encoded media cache. - /// - private void DeleteEncodedMediaCache() - { - var path = _config.ApplicationPaths.TranscodingTempPath; - - foreach (var file in _fileSystem.GetFilePaths(path, true) - .ToList()) - { - _fileSystem.DeleteFile(file); - } } /// @@ -163,660 +93,6 @@ namespace MediaBrowser.Api /// public void Dispose() { - Dispose(true); - GC.SuppressFinalize(this); - } - - /// - /// Releases unmanaged and - optionally - managed resources. - /// - /// true to release both managed and unmanaged resources; false to release only unmanaged resources. - protected virtual void Dispose(bool dispose) - { - var list = _activeTranscodingJobs.ToList(); - var jobCount = list.Count; - - Parallel.ForEach(list, j => KillTranscodingJob(j, false, path => true)); - - // Try to allow for some time to kill the ffmpeg processes and delete the partial stream files - if (jobCount > 0) - { - var task = Task.Delay(1000); - Task.WaitAll(task); - } - } - - /// - /// Called when [transcode beginning]. - /// - /// The path. - /// The play session identifier. - /// The live stream identifier. - /// The transcoding job identifier. - /// The type. - /// The process. - /// The device id. - /// The state. - /// The cancellation token source. - /// TranscodingJob. - public TranscodingJob OnTranscodeBeginning(string path, - string playSessionId, - string liveStreamId, - string transcodingJobId, - TranscodingJobType type, - IProcess process, - string deviceId, - StreamState state, - CancellationTokenSource cancellationTokenSource) - { - lock (_activeTranscodingJobs) - { - var job = new TranscodingJob(Logger, TimerFactory) - { - Type = type, - Path = path, - Process = process, - ActiveRequestCount = 1, - DeviceId = deviceId, - CancellationTokenSource = cancellationTokenSource, - Id = transcodingJobId, - PlaySessionId = playSessionId, - LiveStreamId = liveStreamId, - MediaSource = state.MediaSource - }; - - _activeTranscodingJobs.Add(job); - - ReportTranscodingProgress(job, state, null, null, null, null, null); - - return job; - } - } - - public void ReportTranscodingProgress(TranscodingJob job, StreamState state, TimeSpan? transcodingPosition, float? framerate, double? percentComplete, long? bytesTranscoded, int? bitRate) - { - var ticks = transcodingPosition.HasValue ? transcodingPosition.Value.Ticks : (long?)null; - - if (job != null) - { - job.Framerate = framerate; - job.CompletionPercentage = percentComplete; - job.TranscodingPositionTicks = ticks; - job.BytesTranscoded = bytesTranscoded; - job.BitRate = bitRate; - } - - var deviceId = state.Request.DeviceId; - - if (!string.IsNullOrWhiteSpace(deviceId)) - { - var audioCodec = state.ActualOutputAudioCodec; - var videoCodec = state.ActualOutputVideoCodec; - - _sessionManager.ReportTranscodingInfo(deviceId, new TranscodingInfo - { - Bitrate = bitRate ?? state.TotalOutputBitrate, - AudioCodec = audioCodec, - VideoCodec = videoCodec, - Container = state.OutputContainer, - Framerate = framerate, - CompletionPercentage = percentComplete, - Width = state.OutputWidth, - Height = state.OutputHeight, - AudioChannels = state.OutputAudioChannels, - IsAudioDirect = string.Equals(state.OutputAudioCodec, "copy", StringComparison.OrdinalIgnoreCase), - IsVideoDirect = string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase), - TranscodeReasons = state.TranscodeReasons - }); - } - } - - /// - /// - /// The progressive - /// - /// Called when [transcode failed to start]. - /// - /// The path. - /// The type. - /// The state. - public void OnTranscodeFailedToStart(string path, TranscodingJobType type, StreamState state) - { - lock (_activeTranscodingJobs) - { - var job = _activeTranscodingJobs.FirstOrDefault(j => j.Type == type && string.Equals(j.Path, path, StringComparison.OrdinalIgnoreCase)); - - if (job != null) - { - _activeTranscodingJobs.Remove(job); - } - } - - lock (_transcodingLocks) - { - _transcodingLocks.Remove(path); - } - - if (!string.IsNullOrWhiteSpace(state.Request.DeviceId)) - { - _sessionManager.ClearTranscodingInfo(state.Request.DeviceId); - } - } - - /// - /// Determines whether [has active transcoding job] [the specified path]. - /// - /// The path. - /// The type. - /// true if [has active transcoding job] [the specified path]; otherwise, false. - public bool HasActiveTranscodingJob(string path, TranscodingJobType type) - { - return GetTranscodingJob(path, type) != null; - } - - public TranscodingJob GetTranscodingJob(string path, TranscodingJobType type) - { - lock (_activeTranscodingJobs) - { - return _activeTranscodingJobs.FirstOrDefault(j => j.Type == type && string.Equals(j.Path, path, StringComparison.OrdinalIgnoreCase)); - } - } - - public TranscodingJob GetTranscodingJob(string playSessionId) - { - lock (_activeTranscodingJobs) - { - return _activeTranscodingJobs.FirstOrDefault(j => string.Equals(j.PlaySessionId, playSessionId, StringComparison.OrdinalIgnoreCase)); - } - } - - /// - /// Called when [transcode begin request]. - /// - /// The path. - /// The type. - public TranscodingJob OnTranscodeBeginRequest(string path, TranscodingJobType type) - { - lock (_activeTranscodingJobs) - { - var job = _activeTranscodingJobs.FirstOrDefault(j => j.Type == type && string.Equals(j.Path, path, StringComparison.OrdinalIgnoreCase)); - - if (job == null) - { - return null; - } - - OnTranscodeBeginRequest(job); - - return job; - } - } - - public void OnTranscodeBeginRequest(TranscodingJob job) - { - job.ActiveRequestCount++; - - if (string.IsNullOrWhiteSpace(job.PlaySessionId) || job.Type == TranscodingJobType.Progressive) - { - job.StopKillTimer(); - } - } - - public void OnTranscodeEndRequest(TranscodingJob job) - { - job.ActiveRequestCount--; - //Logger.Debug("OnTranscodeEndRequest job.ActiveRequestCount={0}", job.ActiveRequestCount); - if (job.ActiveRequestCount <= 0) - { - PingTimer(job, false); - } - } - internal void PingTranscodingJob(string playSessionId, bool? isUserPaused) - { - if (string.IsNullOrEmpty(playSessionId)) - { - throw new ArgumentNullException("playSessionId"); - } - - //Logger.Debug("PingTranscodingJob PlaySessionId={0} isUsedPaused: {1}", playSessionId, isUserPaused); - - List jobs; - - lock (_activeTranscodingJobs) - { - // This is really only needed for HLS. - // Progressive streams can stop on their own reliably - jobs = _activeTranscodingJobs.Where(j => string.Equals(playSessionId, j.PlaySessionId, StringComparison.OrdinalIgnoreCase)).ToList(); - } - - foreach (var job in jobs) - { - if (isUserPaused.HasValue) - { - //Logger.Debug("Setting job.IsUserPaused to {0}. jobId: {1}", isUserPaused, job.Id); - job.IsUserPaused = isUserPaused.Value; - } - PingTimer(job, true); - } - } - - private void PingTimer(TranscodingJob job, bool isProgressCheckIn) - { - if (job.HasExited) - { - job.StopKillTimer(); - return; - } - - var timerDuration = 10000; - - if (job.Type != TranscodingJobType.Progressive) - { - timerDuration = 60000; - } - - job.PingTimeout = timerDuration; - job.LastPingDate = DateTime.UtcNow; - - // Don't start the timer for playback checkins with progressive streaming - if (job.Type != TranscodingJobType.Progressive || !isProgressCheckIn) - { - job.StartKillTimer(OnTranscodeKillTimerStopped); - } - else - { - job.ChangeKillTimerIfStarted(); - } - } - - /// - /// Called when [transcode kill timer stopped]. - /// - /// The state. - private void OnTranscodeKillTimerStopped(object state) - { - var job = (TranscodingJob)state; - - if (!job.HasExited && job.Type != TranscodingJobType.Progressive) - { - var timeSinceLastPing = (DateTime.UtcNow - job.LastPingDate).TotalMilliseconds; - - if (timeSinceLastPing < job.PingTimeout) - { - job.StartKillTimer(OnTranscodeKillTimerStopped, job.PingTimeout); - return; - } - } - - Logger.Info("Transcoding kill timer stopped for JobId {0} PlaySessionId {1}. Killing transcoding", job.Id, job.PlaySessionId); - - KillTranscodingJob(job, true, path => true); - } - - /// - /// Kills the single transcoding job. - /// - /// The device id. - /// The play session identifier. - /// The delete files. - /// Task. - internal void KillTranscodingJobs(string deviceId, string playSessionId, Func deleteFiles) - { - KillTranscodingJobs(j => - { - if (!string.IsNullOrWhiteSpace(playSessionId)) - { - return string.Equals(playSessionId, j.PlaySessionId, StringComparison.OrdinalIgnoreCase); - } - - return string.Equals(deviceId, j.DeviceId, StringComparison.OrdinalIgnoreCase); - - }, deleteFiles); - } - - /// - /// Kills the transcoding jobs. - /// - /// The kill job. - /// The delete files. - /// Task. - private void KillTranscodingJobs(Func killJob, Func deleteFiles) - { - var jobs = new List(); - - lock (_activeTranscodingJobs) - { - // This is really only needed for HLS. - // Progressive streams can stop on their own reliably - jobs.AddRange(_activeTranscodingJobs.Where(killJob)); - } - - if (jobs.Count == 0) - { - return; - } - - foreach (var job in jobs) - { - KillTranscodingJob(job, false, deleteFiles); - } - } - - /// - /// Kills the transcoding job. - /// - /// The job. - /// if set to true [close live stream]. - /// The delete. - private async void KillTranscodingJob(TranscodingJob job, bool closeLiveStream, Func delete) - { - job.DisposeKillTimer(); - - Logger.Debug("KillTranscodingJob - JobId {0} PlaySessionId {1}. Killing transcoding", job.Id, job.PlaySessionId); - - lock (_activeTranscodingJobs) - { - _activeTranscodingJobs.Remove(job); - - if (!job.CancellationTokenSource.IsCancellationRequested) - { - job.CancellationTokenSource.Cancel(); - } - } - - lock (_transcodingLocks) - { - _transcodingLocks.Remove(job.Path); - } - - lock (job.ProcessLock) - { - if (job.TranscodingThrottler != null) - { - job.TranscodingThrottler.Stop(); - } - - var process = job.Process; - - var hasExited = job.HasExited; - - if (!hasExited) - { - try - { - Logger.Info("Stopping ffmpeg process with q command for {0}", job.Path); - - //process.Kill(); - process.StandardInput.WriteLine("q"); - - // Need to wait because killing is asynchronous - if (!process.WaitForExit(5000)) - { - Logger.Info("Killing ffmpeg process for {0}", job.Path); - process.Kill(); - } - } - catch (Exception ex) - { - Logger.ErrorException("Error killing transcoding job for {0}", ex, job.Path); - } - } - } - - if (delete(job.Path)) - { - DeletePartialStreamFiles(job.Path, job.Type, 0, 1500); - } - - if (closeLiveStream && !string.IsNullOrWhiteSpace(job.LiveStreamId)) - { - try - { - await _mediaSourceManager.CloseLiveStream(job.LiveStreamId).ConfigureAwait(false); - } - catch (Exception ex) - { - Logger.ErrorException("Error closing live stream for {0}", ex, job.Path); - } - } - } - - private async void DeletePartialStreamFiles(string path, TranscodingJobType jobType, int retryCount, int delayMs) - { - if (retryCount >= 10) - { - return; - } - - Logger.Info("Deleting partial stream file(s) {0}", path); - - await Task.Delay(delayMs).ConfigureAwait(false); - - try - { - if (jobType == TranscodingJobType.Progressive) - { - DeleteProgressivePartialStreamFiles(path); - } - else - { - DeleteHlsPartialStreamFiles(path); - } - } - catch (FileNotFoundException) - { - - } - catch (IOException) - { - //Logger.ErrorException("Error deleting partial stream file(s) {0}", ex, path); - - DeletePartialStreamFiles(path, jobType, retryCount + 1, 500); - } - catch - { - //Logger.ErrorException("Error deleting partial stream file(s) {0}", ex, path); - } - } - - /// - /// Deletes the progressive partial stream files. - /// - /// The output file path. - private void DeleteProgressivePartialStreamFiles(string outputFilePath) - { - _fileSystem.DeleteFile(outputFilePath); - } - - /// - /// Deletes the HLS partial stream files. - /// - /// The output file path. - private void DeleteHlsPartialStreamFiles(string outputFilePath) - { - var directory = _fileSystem.GetDirectoryName(outputFilePath); - var name = Path.GetFileNameWithoutExtension(outputFilePath); - - var filesToDelete = _fileSystem.GetFilePaths(directory) - .Where(f => f.IndexOf(name, StringComparison.OrdinalIgnoreCase) != -1) - .ToList(); - - Exception e = null; - - foreach (var file in filesToDelete) - { - try - { - //Logger.Debug("Deleting HLS file {0}", file); - _fileSystem.DeleteFile(file); - } - catch (FileNotFoundException) - { - - } - catch (IOException ex) - { - e = ex; - //Logger.ErrorException("Error deleting HLS file {0}", ex, file); - } - } - - if (e != null) - { - throw e; - } - } - } - - /// - /// Class TranscodingJob - /// - public class TranscodingJob - { - /// - /// Gets or sets the play session identifier. - /// - /// The play session identifier. - public string PlaySessionId { get; set; } - /// - /// Gets or sets the live stream identifier. - /// - /// The live stream identifier. - public string LiveStreamId { get; set; } - - public bool IsLiveOutput { get; set; } - - /// - /// Gets or sets the path. - /// - /// The path. - public MediaSourceInfo MediaSource { get; set; } - public string Path { get; set; } - /// - /// Gets or sets the type. - /// - /// The type. - public TranscodingJobType Type { get; set; } - /// - /// Gets or sets the process. - /// - /// The process. - public IProcess Process { get; set; } - public ILogger Logger { get; private set; } - /// - /// Gets or sets the active request count. - /// - /// The active request count. - public int ActiveRequestCount { get; set; } - /// - /// Gets or sets the kill timer. - /// - /// The kill timer. - private ITimer KillTimer { get; set; } - - private readonly ITimerFactory _timerFactory; - - public string DeviceId { get; set; } - - public CancellationTokenSource CancellationTokenSource { get; set; } - - public object ProcessLock = new object(); - - public bool HasExited { get; set; } - public bool IsUserPaused { get; set; } - - public string Id { get; set; } - - public float? Framerate { get; set; } - public double? CompletionPercentage { get; set; } - - public long? BytesDownloaded { get; set; } - public long? BytesTranscoded { get; set; } - public int? BitRate { get; set; } - - public long? TranscodingPositionTicks { get; set; } - public long? DownloadPositionTicks { get; set; } - - public TranscodingThrottler TranscodingThrottler { get; set; } - - private readonly object _timerLock = new object(); - - public DateTime LastPingDate { get; set; } - public int PingTimeout { get; set; } - - public TranscodingJob(ILogger logger, ITimerFactory timerFactory) - { - Logger = logger; - _timerFactory = timerFactory; - } - - public void StopKillTimer() - { - lock (_timerLock) - { - if (KillTimer != null) - { - KillTimer.Change(Timeout.Infinite, Timeout.Infinite); - } - } - } - - public void DisposeKillTimer() - { - lock (_timerLock) - { - if (KillTimer != null) - { - KillTimer.Dispose(); - KillTimer = null; - } - } - } - - public void StartKillTimer(Action callback) - { - StartKillTimer(callback, PingTimeout); - } - - public void StartKillTimer(Action callback, int intervalMs) - { - if (HasExited) - { - return; - } - - lock (_timerLock) - { - if (KillTimer == null) - { - //Logger.Debug("Starting kill timer at {0}ms. JobId {1} PlaySessionId {2}", intervalMs, Id, PlaySessionId); - KillTimer = _timerFactory.Create(callback, this, intervalMs, Timeout.Infinite); - } - else - { - //Logger.Debug("Changing kill timer to {0}ms. JobId {1} PlaySessionId {2}", intervalMs, Id, PlaySessionId); - KillTimer.Change(intervalMs, Timeout.Infinite); - } - } - } - - public void ChangeKillTimerIfStarted() - { - if (HasExited) - { - return; - } - - lock (_timerLock) - { - if (KillTimer != null) - { - var intervalMs = PingTimeout; - - //Logger.Debug("Changing kill timer to {0}ms. JobId {1} PlaySessionId {2}", intervalMs, Id, PlaySessionId); - KillTimer.Change(intervalMs, Timeout.Infinite); - } - } } } } diff --git a/MediaBrowser.Api/FilterService.cs b/MediaBrowser.Api/FilterService.cs index 5d81e9ea56..41b17e535d 100644 --- a/MediaBrowser.Api/FilterService.cs +++ b/MediaBrowser.Api/FilterService.cs @@ -63,7 +63,7 @@ namespace MediaBrowser.Api var result = ((Folder)item).GetItemList(GetItemsQuery(request, user)); - return ToOptimizedResult(GetFilters(result.ToArray())); + return ToOptimizedResult(GetFilters(result)); } private QueryFilters GetFilters(BaseItem[] items) diff --git a/MediaBrowser.Api/GamesService.cs b/MediaBrowser.Api/GamesService.cs index 2d161ccfd5..0ce57a16a8 100644 --- a/MediaBrowser.Api/GamesService.cs +++ b/MediaBrowser.Api/GamesService.cs @@ -12,6 +12,7 @@ using System.Linq; using System.Threading.Tasks; using MediaBrowser.Model.Querying; using MediaBrowser.Model.Services; +using MediaBrowser.Model.Extensions; namespace MediaBrowser.Api { @@ -227,11 +228,13 @@ namespace MediaBrowser.Api SimilarTo = item, DtoOptions = dtoOptions - }).ToList(); + }); + + var returnList = (await _dtoService.GetBaseItemDtos(itemsResult, dtoOptions, user).ConfigureAwait(false)); var result = new QueryResult { - Items = (await _dtoService.GetBaseItemDtos(itemsResult, dtoOptions, user).ConfigureAwait(false)).ToArray(), + Items = returnList.ToArray(returnList.Count), TotalRecordCount = itemsResult.Count }; diff --git a/MediaBrowser.Api/Images/ImageService.cs b/MediaBrowser.Api/Images/ImageService.cs index a360e11833..318360336a 100644 --- a/MediaBrowser.Api/Images/ImageService.cs +++ b/MediaBrowser.Api/Images/ImageService.cs @@ -279,13 +279,16 @@ namespace MediaBrowser.Api.Images var itemImages = item.ImageInfos; - foreach (var image in itemImages.Where(i => !item.AllowsMultipleImages(i.Type))) + foreach (var image in itemImages) { - var info = GetImageInfo(item, image, null); - - if (info != null) + if (!item.AllowsMultipleImages(image.Type)) { - list.Add(info); + var info = GetImageInfo(item, image, null); + + if (info != null) + { + list.Add(info); + } } } diff --git a/MediaBrowser.Api/ItemUpdateService.cs b/MediaBrowser.Api/ItemUpdateService.cs index 19220cdec0..a4b6c39562 100644 --- a/MediaBrowser.Api/ItemUpdateService.cs +++ b/MediaBrowser.Api/ItemUpdateService.cs @@ -66,8 +66,8 @@ namespace MediaBrowser.Api { ParentalRatingOptions = _localizationManager.GetParentalRatings().ToList(), ExternalIdInfos = _providerManager.GetExternalIdInfos(item).ToList(), - Countries = _localizationManager.GetCountries().ToList(), - Cultures = _localizationManager.GetCultures().ToList() + Countries = _localizationManager.GetCountries(), + Cultures = _localizationManager.GetCultures() }; if (!item.IsVirtualItem && !(item is ICollectionFolder) && !(item is UserView) && !(item is AggregateFolder) && !(item is LiveTvChannel) && !(item is IItemByName) && @@ -269,7 +269,7 @@ namespace MediaBrowser.Api if (request.Studios != null) { - item.Studios = request.Studios.Select(x => x.Name).ToList(); + item.Studios = request.Studios.Select(x => x.Name).ToArray(); } if (request.DateCreated.HasValue) @@ -285,7 +285,7 @@ namespace MediaBrowser.Api if (request.ProductionLocations != null) { - item.ProductionLocations = request.ProductionLocations.ToList(); + item.ProductionLocations = request.ProductionLocations; } item.PreferredMetadataCountryCode = request.PreferredMetadataCountryCode; diff --git a/MediaBrowser.Api/Library/LibraryService.cs b/MediaBrowser.Api/Library/LibraryService.cs index 3bb119cbae..7dd1afaf45 100644 --- a/MediaBrowser.Api/Library/LibraryService.cs +++ b/MediaBrowser.Api/Library/LibraryService.cs @@ -29,6 +29,7 @@ using MediaBrowser.Model.Globalization; using MediaBrowser.Model.Services; using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Progress; +using MediaBrowser.Model.Extensions; namespace MediaBrowser.Api.Library { @@ -460,22 +461,22 @@ namespace MediaBrowser.Api.Library EnableImages = false } - }).ToArray(); + }); if (!string.IsNullOrWhiteSpace(request.ImdbId)) { - movies = movies.Where(i => string.Equals(request.ImdbId, i.GetProviderId(MetadataProviders.Imdb), StringComparison.OrdinalIgnoreCase)).ToArray(); + movies = movies.Where(i => string.Equals(request.ImdbId, i.GetProviderId(MetadataProviders.Imdb), StringComparison.OrdinalIgnoreCase)).ToList(); } else if (!string.IsNullOrWhiteSpace(request.TmdbId)) { - movies = movies.Where(i => string.Equals(request.TmdbId, i.GetProviderId(MetadataProviders.Tmdb), StringComparison.OrdinalIgnoreCase)).ToArray(); + movies = movies.Where(i => string.Equals(request.TmdbId, i.GetProviderId(MetadataProviders.Tmdb), StringComparison.OrdinalIgnoreCase)).ToList(); } else { - movies = new BaseItem[] { }; + movies = new List(); } - if (movies.Length > 0) + if (movies.Count > 0) { foreach (var item in movies) { @@ -732,7 +733,8 @@ namespace MediaBrowser.Api.Library { DeleteFileLocation = true }); - }).ToArray(); + + }).ToArray(ids.Length); Task.WaitAll(tasks); } @@ -758,7 +760,7 @@ namespace MediaBrowser.Api.Library { var reviews = _itemRepo.GetCriticReviews(new Guid(request.Id)); - var reviewsArray = reviews.ToArray(); + var reviewsArray = reviews.ToArray(reviews.Count); var result = new QueryResult { @@ -833,7 +835,7 @@ namespace MediaBrowser.Api.Library throw new ResourceNotFoundException("Item not found."); } - while (item.ThemeSongIds.Count == 0 && request.InheritFromParent && item.GetParent() != null) + while (item.ThemeSongIds.Length == 0 && request.InheritFromParent && item.GetParent() != null) { item = item.GetParent(); } @@ -882,7 +884,7 @@ namespace MediaBrowser.Api.Library throw new ResourceNotFoundException("Item not found."); } - while (item.ThemeVideoIds.Count == 0 && request.InheritFromParent && item.GetParent() != null) + while (item.ThemeVideoIds.Length == 0 && request.InheritFromParent && item.GetParent() != null) { item = item.GetParent(); } diff --git a/MediaBrowser.Api/LiveTv/LiveTvService.cs b/MediaBrowser.Api/LiveTv/LiveTvService.cs index 837a0f6a6b..09d4cdfa96 100644 --- a/MediaBrowser.Api/LiveTv/LiveTvService.cs +++ b/MediaBrowser.Api/LiveTv/LiveTvService.cs @@ -16,13 +16,12 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using MediaBrowser.Model.IO; -using MediaBrowser.Api.Playback.Progressive; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities.TV; -using MediaBrowser.Controller.IO; using MediaBrowser.Model.Services; using MediaBrowser.Model.System; +using MediaBrowser.Model.Extensions; namespace MediaBrowser.Api.LiveTv { @@ -734,7 +733,7 @@ namespace MediaBrowser.Api.LiveTv outputHeaders["Content-Type"] = Model.Net.MimeTypes.GetMimeType(path); - return new ProgressiveFileCopier(_fileSystem, path, outputHeaders, null, Logger, _environment, CancellationToken.None) + return new ProgressiveFileCopier(_fileSystem, path, outputHeaders, Logger, _environment, CancellationToken.None) { AllowEndOfFile = false }; @@ -753,7 +752,7 @@ namespace MediaBrowser.Api.LiveTv outputHeaders["Content-Type"] = Model.Net.MimeTypes.GetMimeType("file." + request.Container); - return new ProgressiveFileCopier(directStreamProvider, outputHeaders, null, Logger, _environment, CancellationToken.None) + return new ProgressiveFileCopier(directStreamProvider, outputHeaders, Logger, _environment, CancellationToken.None) { AllowEndOfFile = false }; @@ -921,7 +920,9 @@ namespace MediaBrowser.Api.LiveTv options.AddCurrentProgram = request.AddCurrentProgram; - var returnArray = (await _dtoService.GetBaseItemDtos(channelResult.Items, options, user).ConfigureAwait(false)).ToArray(); + var returnList = (await _dtoService.GetBaseItemDtos(channelResult.Items, options, user) + .ConfigureAwait(false)); + var returnArray = returnList.ToArray(returnList.Count); var result = new QueryResult { @@ -962,7 +963,7 @@ namespace MediaBrowser.Api.LiveTv { var query = new ProgramQuery { - ChannelIds = (request.ChannelIds ?? string.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToArray(), + ChannelIds = ApiEntryPoint.Split(request.ChannelIds, ',', true), UserId = request.UserId, HasAired = request.HasAired, EnableTotalRecordCount = request.EnableTotalRecordCount diff --git a/MediaBrowser.Api/Playback/Progressive/ProgressiveStreamWriter.cs b/MediaBrowser.Api/LiveTv/ProgressiveFileCopier.cs similarity index 59% rename from MediaBrowser.Api/Playback/Progressive/ProgressiveStreamWriter.cs rename to MediaBrowser.Api/LiveTv/ProgressiveFileCopier.cs index d84d889fa8..20466c5f63 100644 --- a/MediaBrowser.Api/Playback/Progressive/ProgressiveStreamWriter.cs +++ b/MediaBrowser.Api/LiveTv/ProgressiveFileCopier.cs @@ -1,23 +1,19 @@ -using MediaBrowser.Model.Logging; -using System; +using System; +using System.Collections.Generic; using System.IO; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Model.IO; -using MediaBrowser.Controller.Net; -using System.Collections.Generic; - -using MediaBrowser.Controller.IO; using MediaBrowser.Controller.Library; +using MediaBrowser.Model.IO; +using MediaBrowser.Model.Logging; using MediaBrowser.Model.Services; using MediaBrowser.Model.System; -namespace MediaBrowser.Api.Playback.Progressive +namespace MediaBrowser.Api.LiveTv { public class ProgressiveFileCopier : IAsyncStreamWriter, IHasHeaders { private readonly IFileSystem _fileSystem; - private readonly TranscodingJob _job; private readonly ILogger _logger; private readonly string _path; private readonly CancellationToken _cancellationToken; @@ -32,22 +28,20 @@ namespace MediaBrowser.Api.Playback.Progressive private readonly IDirectStreamProvider _directStreamProvider; private readonly IEnvironmentInfo _environment; - public ProgressiveFileCopier(IFileSystem fileSystem, string path, Dictionary outputHeaders, TranscodingJob job, ILogger logger, IEnvironmentInfo environment, CancellationToken cancellationToken) + public ProgressiveFileCopier(IFileSystem fileSystem, string path, Dictionary outputHeaders, ILogger logger, IEnvironmentInfo environment, CancellationToken cancellationToken) { _fileSystem = fileSystem; _path = path; _outputHeaders = outputHeaders; - _job = job; _logger = logger; _cancellationToken = cancellationToken; _environment = environment; } - public ProgressiveFileCopier(IDirectStreamProvider directStreamProvider, Dictionary outputHeaders, TranscodingJob job, ILogger logger, IEnvironmentInfo environment, CancellationToken cancellationToken) + public ProgressiveFileCopier(IDirectStreamProvider directStreamProvider, Dictionary outputHeaders, ILogger logger, IEnvironmentInfo environment, CancellationToken cancellationToken) { _directStreamProvider = directStreamProvider; _outputHeaders = outputHeaders; - _job = job; _logger = logger; _cancellationToken = cancellationToken; _environment = environment; @@ -77,61 +71,48 @@ namespace MediaBrowser.Api.Playback.Progressive { cancellationToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, _cancellationToken).Token; - try + if (_directStreamProvider != null) { - if (_directStreamProvider != null) - { - await _directStreamProvider.CopyToAsync(outputStream, cancellationToken).ConfigureAwait(false); - return; - } - - var eofCount = 0; - - // use non-async filestream along with read due to https://github.com/dotnet/corefx/issues/6039 - var allowAsyncFileRead = _environment.OperatingSystem != OperatingSystem.Windows; - - using (var inputStream = GetInputStream(allowAsyncFileRead)) - { - if (StartPosition > 0) - { - inputStream.Position = StartPosition; - } - - while (eofCount < 20 || !AllowEndOfFile) - { - int bytesRead; - if (allowAsyncFileRead) - { - bytesRead = await CopyToInternalAsync(inputStream, outputStream, cancellationToken).ConfigureAwait(false); - } - else - { - bytesRead = await CopyToInternalAsyncWithSyncRead(inputStream, outputStream, cancellationToken).ConfigureAwait(false); - } - - //var position = fs.Position; - //_logger.Debug("Streamed {0} bytes to position {1} from file {2}", bytesRead, position, path); - - if (bytesRead == 0) - { - if (_job == null || _job.HasExited) - { - eofCount++; - } - await Task.Delay(100, cancellationToken).ConfigureAwait(false); - } - else - { - eofCount = 0; - } - } - } + await _directStreamProvider.CopyToAsync(outputStream, cancellationToken).ConfigureAwait(false); + return; } - finally + + var eofCount = 0; + + // use non-async filestream along with read due to https://github.com/dotnet/corefx/issues/6039 + var allowAsyncFileRead = _environment.OperatingSystem != OperatingSystem.Windows; + + using (var inputStream = GetInputStream(allowAsyncFileRead)) { - if (_job != null) + if (StartPosition > 0) { - ApiEntryPoint.Instance.OnTranscodeEndRequest(_job); + inputStream.Position = StartPosition; + } + + while (eofCount < 20 || !AllowEndOfFile) + { + int bytesRead; + if (allowAsyncFileRead) + { + bytesRead = await CopyToInternalAsync(inputStream, outputStream, cancellationToken).ConfigureAwait(false); + } + else + { + bytesRead = await CopyToInternalAsyncWithSyncRead(inputStream, outputStream, cancellationToken).ConfigureAwait(false); + } + + //var position = fs.Position; + //_logger.Debug("Streamed {0} bytes to position {1} from file {2}", bytesRead, position, path); + + if (bytesRead == 0) + { + eofCount++; + await Task.Delay(100, cancellationToken).ConfigureAwait(false); + } + else + { + eofCount = 0; + } } } } @@ -152,11 +133,6 @@ namespace MediaBrowser.Api.Playback.Progressive _bytesWritten += bytesRead; totalBytesRead += bytesRead; - - if (_job != null) - { - _job.BytesDownloaded = Math.Max(_job.BytesDownloaded ?? _bytesWritten, _bytesWritten); - } } } @@ -179,11 +155,6 @@ namespace MediaBrowser.Api.Playback.Progressive _bytesWritten += bytesRead; totalBytesRead += bytesRead; - - if (_job != null) - { - _job.BytesDownloaded = Math.Max(_job.BytesDownloaded ?? _bytesWritten, _bytesWritten); - } } } diff --git a/MediaBrowser.Api/LocalizationService.cs b/MediaBrowser.Api/LocalizationService.cs index 90b963149b..eee340a874 100644 --- a/MediaBrowser.Api/LocalizationService.cs +++ b/MediaBrowser.Api/LocalizationService.cs @@ -85,7 +85,7 @@ namespace MediaBrowser.Api /// System.Object. public object Get(GetCountries request) { - var result = _localization.GetCountries().ToList(); + var result = _localization.GetCountries(); return ToOptimizedResult(result); } @@ -97,7 +97,7 @@ namespace MediaBrowser.Api /// System.Object. public object Get(GetCultures request) { - var result = _localization.GetCultures().ToList(); + var result = _localization.GetCultures(); return ToOptimizedResult(result); } diff --git a/MediaBrowser.Api/MediaBrowser.Api.csproj b/MediaBrowser.Api/MediaBrowser.Api.csproj index 88889e5e76..810b0f6b27 100644 --- a/MediaBrowser.Api/MediaBrowser.Api.csproj +++ b/MediaBrowser.Api/MediaBrowser.Api.csproj @@ -48,9 +48,7 @@ - - - + @@ -101,18 +99,6 @@ - - - - - - - - - - - - @@ -126,7 +112,6 @@ - @@ -136,7 +121,6 @@ - diff --git a/MediaBrowser.Api/Movies/MoviesService.cs b/MediaBrowser.Api/Movies/MoviesService.cs index e20fa2cca1..43d8f3ecf9 100644 --- a/MediaBrowser.Api/Movies/MoviesService.cs +++ b/MediaBrowser.Api/Movies/MoviesService.cs @@ -158,17 +158,19 @@ namespace MediaBrowser.Api.Movies var itemsResult = _libraryManager.GetItemList(new InternalItemsQuery(user) { Limit = request.Limit, - IncludeItemTypes = itemTypes.ToArray(), + IncludeItemTypes = itemTypes.ToArray(itemTypes.Count), IsMovie = true, SimilarTo = item, EnableGroupByMetadataKey = true, DtoOptions = dtoOptions - }).ToList(); + }); + + var returnList = await _dtoService.GetBaseItemDtos(itemsResult, dtoOptions, user).ConfigureAwait(false); var result = new QueryResult { - Items = (await _dtoService.GetBaseItemDtos(itemsResult, dtoOptions, user).ConfigureAwait(false)).ToArray(), + Items = returnList.ToArray(returnList.Count), TotalRecordCount = itemsResult.Count }; @@ -200,7 +202,7 @@ namespace MediaBrowser.Api.Movies DtoOptions = dtoOptions }; - var recentlyPlayedMovies = _libraryManager.GetItemList(query).ToList(); + var recentlyPlayedMovies = _libraryManager.GetItemList(query); var itemTypes = new List { typeof(Movie).Name }; if (_config.Configuration.EnableExternalContentInSuggestions) @@ -211,19 +213,19 @@ namespace MediaBrowser.Api.Movies var likedMovies = _libraryManager.GetItemList(new InternalItemsQuery(user) { - IncludeItemTypes = itemTypes.ToArray(), + IncludeItemTypes = itemTypes.ToArray(itemTypes.Count), IsMovie = true, SortBy = new[] { ItemSortBy.Random }, SortOrder = SortOrder.Descending, Limit = 10, IsFavoriteOrLiked = true, - ExcludeItemIds = recentlyPlayedMovies.Select(i => i.Id.ToString("N")).ToArray(), + ExcludeItemIds = recentlyPlayedMovies.Select(i => i.Id.ToString("N")).ToArray(recentlyPlayedMovies.Count), EnableGroupByMetadataKey = true, ParentId = parentIdGuid, Recursive = true, DtoOptions = dtoOptions - }).ToList(); + }); var mostRecentMovies = recentlyPlayedMovies.Take(6).ToList(); // Get recently played directors @@ -300,7 +302,7 @@ namespace MediaBrowser.Api.Movies // Account for duplicates by imdb id, since the database doesn't support this yet Limit = itemLimit + 2, PersonTypes = new[] { PersonType.Director }, - IncludeItemTypes = itemTypes.ToArray(), + IncludeItemTypes = itemTypes.ToArray(itemTypes.Count), IsMovie = true, EnableGroupByMetadataKey = true, DtoOptions = dtoOptions @@ -311,12 +313,14 @@ namespace MediaBrowser.Api.Movies if (items.Count > 0) { + var returnItems = _dtoService.GetBaseItemDtos(items, dtoOptions, user).Result; + yield return new RecommendationDto { BaselineItemName = name, CategoryId = name.GetMD5().ToString("N"), RecommendationType = type, - Items = _dtoService.GetBaseItemDtos(items, dtoOptions, user).Result.ToArray() + Items = returnItems.ToArray(returnItems.Count) }; } } @@ -338,7 +342,7 @@ namespace MediaBrowser.Api.Movies Person = name, // Account for duplicates by imdb id, since the database doesn't support this yet Limit = itemLimit + 2, - IncludeItemTypes = itemTypes.ToArray(), + IncludeItemTypes = itemTypes.ToArray(itemTypes.Count), IsMovie = true, EnableGroupByMetadataKey = true, DtoOptions = dtoOptions @@ -349,12 +353,14 @@ namespace MediaBrowser.Api.Movies if (items.Count > 0) { + var returnItems = _dtoService.GetBaseItemDtos(items, dtoOptions, user).Result; + yield return new RecommendationDto { BaselineItemName = name, CategoryId = name.GetMD5().ToString("N"), RecommendationType = type, - Items = _dtoService.GetBaseItemDtos(items, dtoOptions, user).Result.ToArray() + Items = returnItems.ToArray(returnItems.Count) }; } } @@ -374,28 +380,30 @@ namespace MediaBrowser.Api.Movies var similar = _libraryManager.GetItemList(new InternalItemsQuery(user) { Limit = itemLimit, - IncludeItemTypes = itemTypes.ToArray(), + IncludeItemTypes = itemTypes.ToArray(itemTypes.Count), IsMovie = true, SimilarTo = item, EnableGroupByMetadataKey = true, DtoOptions = dtoOptions - }).ToList(); + }); if (similar.Count > 0) { + var returnItems = _dtoService.GetBaseItemDtos(similar, dtoOptions, user).Result; + yield return new RecommendationDto { BaselineItemName = item.Name, CategoryId = item.Id.ToString("N"), RecommendationType = type, - Items = _dtoService.GetBaseItemDtos(similar, dtoOptions, user).Result.ToArray() + Items = returnItems.ToArray(returnItems.Count) }; } } } - private IEnumerable GetActors(IEnumerable items) + private IEnumerable GetActors(List items) { var people = _libraryManager.GetPeople(new InternalPeopleQuery { @@ -406,7 +414,7 @@ namespace MediaBrowser.Api.Movies MaxListOrder = 3 }); - var itemIds = items.Select(i => i.Id).ToList(); + var itemIds = items.Select(i => i.Id).ToList(items.Count); return people .Where(i => itemIds.Contains(i.ItemId)) @@ -414,7 +422,7 @@ namespace MediaBrowser.Api.Movies .DistinctNames(); } - private IEnumerable GetDirectors(IEnumerable items) + private IEnumerable GetDirectors(List items) { var people = _libraryManager.GetPeople(new InternalPeopleQuery { @@ -424,7 +432,7 @@ namespace MediaBrowser.Api.Movies } }); - var itemIds = items.Select(i => i.Id).ToList(); + var itemIds = items.Select(i => i.Id).ToList(items.Count); return people .Where(i => itemIds.Contains(i.ItemId)) diff --git a/MediaBrowser.Api/Music/InstantMixService.cs b/MediaBrowser.Api/Music/InstantMixService.cs index 3cb29de072..b0f086ec5b 100644 --- a/MediaBrowser.Api/Music/InstantMixService.cs +++ b/MediaBrowser.Api/Music/InstantMixService.cs @@ -9,6 +9,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using MediaBrowser.Model.Services; +using MediaBrowser.Model.Extensions; namespace MediaBrowser.Api.Music { @@ -180,16 +181,19 @@ namespace MediaBrowser.Api.Music return GetResult(items, user, request, dtoOptions); } - private async Task GetResult(IEnumerable