diff --git a/Emby.Server.Implementations/Activity/ActivityRepository.cs b/Emby.Server.Implementations/Activity/ActivityRepository.cs index eef9792de4..ba81992acb 100644 --- a/Emby.Server.Implementations/Activity/ActivityRepository.cs +++ b/Emby.Server.Implementations/Activity/ActivityRepository.cs @@ -58,9 +58,9 @@ namespace Emby.Server.Implementations.Activity throw new ArgumentNullException("entry"); } - using (var connection = CreateConnection()) + using (WriteLock.Write()) { - using (WriteLock.Write()) + using (var connection = CreateConnection()) { connection.RunInTransaction(db => { @@ -86,9 +86,9 @@ namespace Emby.Server.Implementations.Activity public QueryResult GetActivityLogEntries(DateTime? minDate, int? startIndex, int? limit) { - using (var connection = CreateConnection(true)) + using (WriteLock.Read()) { - using (WriteLock.Read()) + using (var connection = CreateConnection(true)) { var commandText = BaseActivitySelectText; var whereClauses = new List(); diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs index f017a21dcd..727a9c4bb2 100644 --- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs @@ -664,11 +664,18 @@ namespace Emby.Server.Implementations.Data { var requiresReset = false; - using (var saveItemStatement = db.PrepareStatement(GetSaveItemCommandText())) + var statements = db.PrepareAll(string.Join(";", new string[] { - using (var deleteAncestorsStatement = db.PrepareStatement("delete from AncestorIds where ItemId=@ItemId")) + GetSaveItemCommandText(), + "delete from AncestorIds where ItemId=@ItemId", + "insert into AncestorIds (ItemId, AncestorId, AncestorIdText) values (@ItemId, @AncestorId, @AncestorIdText)" + })).ToList(); + + using (var saveItemStatement = statements[0]) + { + using (var deleteAncestorsStatement = statements[1]) { - using (var updateAncestorsStatement = db.PrepareStatement("insert into AncestorIds (ItemId, AncestorId, AncestorIdText) values (@ItemId, @AncestorId, @AncestorIdText)")) + using (var updateAncestorsStatement = statements[2]) { foreach (var tuple in tuples) { @@ -1115,7 +1122,9 @@ namespace Emby.Server.Implementations.Data return null; } - return string.Join("|", images.Select(ToValueString).ToArray()); + var imageStrings = images.Where(i => !string.IsNullOrWhiteSpace(i.Path)).Select(ToValueString).ToArray(); + + return string.Join("|", imageStrings); } private void DeserializeImages(string value, BaseItem item) @@ -1134,7 +1143,12 @@ namespace Emby.Server.Implementations.Data foreach (var part in parts) { - item.ImageInfos.Add(ItemImageInfoFromValueString(part)); + var image = ItemImageInfoFromValueString(part); + + if (image != null) + { + item.ImageInfos.Add(image); + } } } @@ -1142,7 +1156,14 @@ namespace Emby.Server.Implementations.Data { var delimeter = "*"; - return (image.Path ?? string.Empty) + + var path = image.Path; + + if (path == null) + { + path = string.Empty; + } + + return path + delimeter + image.DateModified.Ticks.ToString(CultureInfo.InvariantCulture) + delimeter + @@ -1155,6 +1176,11 @@ namespace Emby.Server.Implementations.Data { var parts = value.Split(new[] { '*' }, StringSplitOptions.None); + if (parts.Length != 4) + { + return null; + } + var image = new ItemImageInfo(); image.Path = parts[0]; @@ -2576,16 +2602,42 @@ namespace Emby.Server.Implementations.Data } } + var totalRecordCount = 0; + var isReturningZeroItems = query.Limit.HasValue && query.Limit <= 0; + + var statementTexts = new List(); + if (!isReturningZeroItems) + { + statementTexts.Add(commandText); + } + if (query.EnableTotalRecordCount) + { + commandText = string.Empty; + + if (EnableGroupByPresentationUniqueKey(query)) + { + commandText += " select count (distinct PresentationUniqueKey)" + GetFromText(); + } + else + { + commandText += " select count (guid)" + GetFromText(); + } + + commandText += GetJoinUserDataText(query); + commandText += whereTextWithoutPaging; + statementTexts.Add(commandText); + } + using (var connection = CreateConnection(true)) { using (WriteLock.Read()) { - var totalRecordCount = 0; - var isReturningZeroItems = query.Limit.HasValue && query.Limit <= 0; + var statements = connection.PrepareAll(string.Join(";", statementTexts.ToArray())) + .ToList(); if (!isReturningZeroItems) { - using (var statement = connection.PrepareStatement(commandText)) + using (var statement = statements[0]) { if (EnableJoinUserData(query)) { @@ -2608,33 +2660,22 @@ namespace Emby.Server.Implementations.Data } } - commandText = string.Empty; - - if (EnableGroupByPresentationUniqueKey(query)) + if (query.EnableTotalRecordCount) { - commandText += " select count (distinct PresentationUniqueKey)" + GetFromText(); - } - else - { - commandText += " select count (guid)" + GetFromText(); - } - - commandText += GetJoinUserDataText(query); - commandText += whereTextWithoutPaging; - - using (var statement = connection.PrepareStatement(commandText)) - { - if (EnableJoinUserData(query)) + using (var statement = statements[statements.Count - 1]) { - statement.TryBind("@UserId", query.User.Id); + if (EnableJoinUserData(query)) + { + statement.TryBind("@UserId", query.User.Id); + } + + BindSimilarParams(query, statement); + + // Running this again will bind the params + GetWhereClauses(query, statement); + + totalRecordCount = statement.ExecuteQuery().SelectScalarInt().First(); } - - BindSimilarParams(query, statement); - - // Running this again will bind the params - GetWhereClauses(query, statement); - - totalRecordCount = statement.ExecuteQuery().SelectScalarInt().First(); } LogQueryTime("GetItems", commandText, now); @@ -2966,58 +3007,77 @@ namespace Emby.Server.Implementations.Data } var list = new List(); + var isReturningZeroItems = query.Limit.HasValue && query.Limit <= 0; + + var statementTexts = new List(); + if (!isReturningZeroItems) + { + statementTexts.Add(commandText); + } + if (query.EnableTotalRecordCount) + { + commandText = string.Empty; + + if (EnableGroupByPresentationUniqueKey(query)) + { + commandText += " select count (distinct PresentationUniqueKey)" + GetFromText(); + } + else + { + commandText += " select count (guid)" + GetFromText(); + } + + commandText += GetJoinUserDataText(query); + commandText += whereTextWithoutPaging; + statementTexts.Add(commandText); + } using (var connection = CreateConnection(true)) { + var statements = connection.PrepareAll(string.Join(";", statementTexts.ToArray())) + .ToList(); + using (WriteLock.Read()) { var totalRecordCount = 0; - using (var statement = connection.PrepareStatement(commandText)) + if (!isReturningZeroItems) { - if (EnableJoinUserData(query)) + using (var statement = statements[0]) { - statement.TryBind("@UserId", query.User.Id); - } + if (EnableJoinUserData(query)) + { + statement.TryBind("@UserId", query.User.Id); + } - BindSimilarParams(query, statement); + BindSimilarParams(query, statement); - // Running this again will bind the params - GetWhereClauses(query, statement); + // Running this again will bind the params + GetWhereClauses(query, statement); - foreach (var row in statement.ExecuteQuery()) - { - list.Add(row[0].ReadGuid()); + foreach (var row in statement.ExecuteQuery()) + { + list.Add(row[0].ReadGuid()); + } } } - commandText = string.Empty; - - if (EnableGroupByPresentationUniqueKey(query)) + if (query.EnableTotalRecordCount) { - commandText += " select count (distinct PresentationUniqueKey)" + GetFromText(); - } - else - { - commandText += " select count (guid)" + GetFromText(); - } - - commandText += GetJoinUserDataText(query); - commandText += whereTextWithoutPaging; - - using (var statement = connection.PrepareStatement(commandText)) - { - if (EnableJoinUserData(query)) + using (var statement = statements[statements.Count - 1]) { - statement.TryBind("@UserId", query.User.Id); + if (EnableJoinUserData(query)) + { + statement.TryBind("@UserId", query.User.Id); + } + + BindSimilarParams(query, statement); + + // Running this again will bind the params + GetWhereClauses(query, statement); + + totalRecordCount = statement.ExecuteQuery().SelectScalarInt().First(); } - - BindSimilarParams(query, statement); - - // Running this again will bind the params - GetWhereClauses(query, statement); - - totalRecordCount = statement.ExecuteQuery().SelectScalarInt().First(); } LogQueryTime("GetItemIds", commandText, now); @@ -4875,13 +4935,29 @@ namespace Emby.Server.Implementations.Data var list = new List>(); var count = 0; + var statementTexts = new List(); + if (!isReturningZeroItems) + { + statementTexts.Add(commandText); + } + if (query.EnableTotalRecordCount) + { + var countText = "select count (distinct PresentationUniqueKey)" + GetFromText(); + + countText += GetJoinUserDataText(query); + countText += whereText; + statementTexts.Add(countText); + } + using (var connection = CreateConnection(true)) { using (WriteLock.Read()) { + var statements = connection.PrepareAll(string.Join(";", statementTexts.ToArray())).ToList(); + if (!isReturningZeroItems) { - using (var statement = connection.PrepareStatement(commandText)) + using (var statement = statements[0]) { statement.TryBind("@SelectType", returnType); if (EnableJoinUserData(query)) @@ -4919,7 +4995,7 @@ namespace Emby.Server.Implementations.Data commandText += GetJoinUserDataText(query); commandText += whereText; - using (var statement = connection.PrepareStatement(commandText)) + using (var statement = statements[statements.Count - 1]) { statement.TryBind("@SelectType", returnType); if (EnableJoinUserData(query)) diff --git a/Emby.Server.Implementations/Security/AuthenticationRepository.cs b/Emby.Server.Implementations/Security/AuthenticationRepository.cs index dad05718c9..2632b9666a 100644 --- a/Emby.Server.Implementations/Security/AuthenticationRepository.cs +++ b/Emby.Server.Implementations/Security/AuthenticationRepository.cs @@ -70,9 +70,9 @@ namespace Emby.Server.Implementations.Security cancellationToken.ThrowIfCancellationRequested(); - using (var connection = CreateConnection()) + using (WriteLock.Write()) { - using (WriteLock.Write()) + using (var connection = CreateConnection()) { connection.RunInTransaction(db => { @@ -137,78 +137,78 @@ namespace Emby.Server.Implementations.Security throw new ArgumentNullException("query"); } - using (var connection = CreateConnection(true)) + using (WriteLock.Read()) { - var commandText = BaseSelectText; - - var whereClauses = new List(); - - var startIndex = query.StartIndex ?? 0; - - if (!string.IsNullOrWhiteSpace(query.AccessToken)) + using (var connection = CreateConnection(true)) { - whereClauses.Add("AccessToken=@AccessToken"); - } + var commandText = BaseSelectText; - if (!string.IsNullOrWhiteSpace(query.UserId)) - { - whereClauses.Add("UserId=@UserId"); - } + var whereClauses = new List(); - if (!string.IsNullOrWhiteSpace(query.DeviceId)) - { - whereClauses.Add("DeviceId=@DeviceId"); - } + var startIndex = query.StartIndex ?? 0; - if (query.IsActive.HasValue) - { - whereClauses.Add("IsActive=@IsActive"); - } - - if (query.HasUser.HasValue) - { - if (query.HasUser.Value) + if (!string.IsNullOrWhiteSpace(query.AccessToken)) { - whereClauses.Add("UserId not null"); + whereClauses.Add("AccessToken=@AccessToken"); } - else + + if (!string.IsNullOrWhiteSpace(query.UserId)) { - whereClauses.Add("UserId is null"); + whereClauses.Add("UserId=@UserId"); } - } - var whereTextWithoutPaging = whereClauses.Count == 0 ? - string.Empty : - " where " + string.Join(" AND ", whereClauses.ToArray()); + if (!string.IsNullOrWhiteSpace(query.DeviceId)) + { + whereClauses.Add("DeviceId=@DeviceId"); + } - if (startIndex > 0) - { - var pagingWhereText = whereClauses.Count == 0 ? + if (query.IsActive.HasValue) + { + whereClauses.Add("IsActive=@IsActive"); + } + + if (query.HasUser.HasValue) + { + if (query.HasUser.Value) + { + whereClauses.Add("UserId not null"); + } + else + { + whereClauses.Add("UserId is null"); + } + } + + var whereTextWithoutPaging = whereClauses.Count == 0 ? string.Empty : " where " + string.Join(" AND ", whereClauses.ToArray()); - whereClauses.Add(string.Format("Id NOT IN (SELECT Id FROM AccessTokens {0} ORDER BY DateCreated LIMIT {1})", - pagingWhereText, - startIndex.ToString(_usCulture))); - } + if (startIndex > 0) + { + var pagingWhereText = whereClauses.Count == 0 ? + string.Empty : + " where " + string.Join(" AND ", whereClauses.ToArray()); - var whereText = whereClauses.Count == 0 ? - string.Empty : - " where " + string.Join(" AND ", whereClauses.ToArray()); + whereClauses.Add(string.Format("Id NOT IN (SELECT Id FROM AccessTokens {0} ORDER BY DateCreated LIMIT {1})", + pagingWhereText, + startIndex.ToString(_usCulture))); + } - commandText += whereText; + var whereText = whereClauses.Count == 0 ? + string.Empty : + " where " + string.Join(" AND ", whereClauses.ToArray()); - commandText += " ORDER BY DateCreated"; + commandText += whereText; - if (query.Limit.HasValue) - { - commandText += " LIMIT " + query.Limit.Value.ToString(_usCulture); - } + commandText += " ORDER BY DateCreated"; - var list = new List(); + if (query.Limit.HasValue) + { + commandText += " LIMIT " + query.Limit.Value.ToString(_usCulture); + } + + var list = new List(); - using (WriteLock.Read()) - { using (var statement = connection.PrepareStatement(commandText)) { BindAuthenticationQueryParams(query, statement); @@ -244,9 +244,9 @@ namespace Emby.Server.Implementations.Security throw new ArgumentNullException("id"); } - using (var connection = CreateConnection(true)) + using (WriteLock.Read()) { - using (WriteLock.Read()) + using (var connection = CreateConnection(true)) { var commandText = BaseSelectText + " where Id=@Id"; diff --git a/Emby.Server.Implementations/Sync/SyncRepository.cs b/Emby.Server.Implementations/Sync/SyncRepository.cs index 308c3bd00d..d8bec1ce36 100644 --- a/Emby.Server.Implementations/Sync/SyncRepository.cs +++ b/Emby.Server.Implementations/Sync/SyncRepository.cs @@ -516,9 +516,23 @@ namespace Emby.Server.Implementations.Sync commandText += " where " + string.Join(" AND ", whereClauses.ToArray()); } + var statementTexts = new List + { + commandText + }; + + commandText = commandText + .Replace("select ItemId,Status,Progress from SyncJobItems", "select ItemIds,Status,Progress from SyncJobs") + .Replace("'Synced'", "'Completed','CompletedWithError'"); + + statementTexts.Add(commandText); + using (WriteLock.Read()) { - using (var statement = connection.PrepareStatement(commandText)) + var statements = connection.PrepareAll(string.Join(";", statementTexts.ToArray())) + .ToList(); + + using (var statement = statements[0]) { if (!string.IsNullOrWhiteSpace(query.TargetId)) { @@ -532,13 +546,9 @@ namespace Emby.Server.Implementations.Sync LogQueryTime("GetSyncedItemProgresses", commandText, now); } - commandText = commandText - .Replace("select ItemId,Status,Progress from SyncJobItems", "select ItemIds,Status,Progress from SyncJobs") - .Replace("'Synced'", "'Completed','CompletedWithError'"); - now = DateTime.UtcNow; - using (var statement = connection.PrepareStatement(commandText)) + using (var statement = statements[1]) { if (!string.IsNullOrWhiteSpace(query.TargetId)) { diff --git a/MediaBrowser.Api/Playback/Progressive/VideoService.cs b/MediaBrowser.Api/Playback/Progressive/VideoService.cs index 285d09cdcd..7ba1fecfec 100644 --- a/MediaBrowser.Api/Playback/Progressive/VideoService.cs +++ b/MediaBrowser.Api/Playback/Progressive/VideoService.cs @@ -199,7 +199,7 @@ namespace MediaBrowser.Api.Playback.Progressive if (!state.RunTimeTicks.HasValue) { - args += " -fflags +genpts -flags +global_header"; + args += " -flags -global_header"; } return args; diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index d4ddab7b28..4705f03fa0 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -681,6 +681,19 @@ namespace MediaBrowser.Controller.Entities return result.TotalRecordCount; } + public virtual int GetRecursiveChildCount(User user) + { + return GetItems(new InternalItemsQuery(user) + { + Recursive = true, + IsFolder = false, + IsVirtualItem = false, + EnableTotalRecordCount = true, + Limit = 0 + + }).Result.TotalRecordCount; + } + public QueryResult QueryRecursive(InternalItemsQuery query) { var user = query.User; @@ -1404,20 +1417,11 @@ namespace MediaBrowser.Controller.Entities return; } - var allItemsQueryResult = await GetItems(new InternalItemsQuery(user) - { - Recursive = true, - IsFolder = false, - IsVirtualItem = false, - EnableTotalRecordCount = true, - Limit = 0 - - }).ConfigureAwait(false); - var recursiveItemCount = allItemsQueryResult.TotalRecordCount; + var recursiveItemCount = GetRecursiveChildCount(user); if (itemDto != null) { - itemDto.RecursiveItemCount = allItemsQueryResult.TotalRecordCount; + itemDto.RecursiveItemCount = recursiveItemCount; } if (recursiveItemCount > 0 && SupportsPlayedStatus) diff --git a/MediaBrowser.Controller/Entities/TV/Series.cs b/MediaBrowser.Controller/Entities/TV/Series.cs index 69a3a67c81..ef25faf91d 100644 --- a/MediaBrowser.Controller/Entities/TV/Series.cs +++ b/MediaBrowser.Controller/Entities/TV/Series.cs @@ -142,6 +142,24 @@ namespace MediaBrowser.Controller.Entities.TV return result.TotalRecordCount; } + public override int GetRecursiveChildCount(User user) + { + var query = new InternalItemsQuery(user); + + query.AncestorWithPresentationUniqueKey = GetUniqueSeriesKey(this); + if (query.SortBy.Length == 0) + { + query.SortBy = new[] { ItemSortBy.SortName }; + } + if (query.IncludeItemTypes.Length == 0) + { + query.IncludeItemTypes = new[] { typeof(Episode).Name, typeof(Season).Name }; + } + query.IsVirtualItem = false; + query.Limit = 0; + return LibraryManager.GetItemsResult(query).TotalRecordCount; + } + /// /// Gets the user data key. /// @@ -369,7 +387,10 @@ namespace MediaBrowser.Controller.Entities.TV public IEnumerable GetSeasonEpisodes(Season parentSeason, User user) { - var seriesKey = GetUniqueSeriesKey(this); + // add optimization when this setting is not enabled + var seriesKey = ConfigurationManager.Configuration.DisplaySpecialsWithinSeasons ? + GetUniqueSeriesKey(this) : + GetUniqueSeriesKey(parentSeason); var query = new InternalItemsQuery(user) {