From ef6b90b8e6e6c317fcda85a392c79324f91250db Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Tue, 25 Oct 2016 15:02:04 -0400 Subject: make controller project portable --- MediaBrowser.Controller/Library/ILibraryManager.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'MediaBrowser.Controller/Library/ILibraryManager.cs') diff --git a/MediaBrowser.Controller/Library/ILibraryManager.cs b/MediaBrowser.Controller/Library/ILibraryManager.cs index 975c596594..acdd9a0423 100644 --- a/MediaBrowser.Controller/Library/ILibraryManager.cs +++ b/MediaBrowser.Controller/Library/ILibraryManager.cs @@ -10,10 +10,12 @@ using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; -using CommonIO; +using MediaBrowser.Common.IO; using MediaBrowser.Controller.Configuration; +using MediaBrowser.Controller.IO; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Dto; +using MediaBrowser.Model.IO; namespace MediaBrowser.Controller.Library { -- cgit v1.2.3 From f275d7f3d2f40f5e4cbe2f97df6dbd9be8ec37fe Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Mon, 21 Nov 2016 03:54:53 -0500 Subject: reduce library queries --- .../EnvironmentInfo/EnvironmentInfo.cs | 5 ++ Emby.Server.Core/ApplicationHost.cs | 2 +- .../Activity/ActivityRepository.cs | 5 +- .../Data/BaseSqliteRepository.cs | 37 +++++++-- .../Data/SqliteDisplayPreferencesRepository.cs | 5 +- .../Data/SqliteFileOrganizationRepository.cs | 5 +- .../Data/SqliteItemRepository.cs | 96 +++++++++++----------- .../Data/SqliteUserDataRepository.cs | 5 +- .../Data/SqliteUserRepository.cs | 5 +- Emby.Server.Implementations/Dto/DtoService.cs | 16 +++- .../Library/LibraryManager.cs | 31 +++---- .../Library/UserViewManager.cs | 30 ++++--- .../LiveTv/LiveTvManager.cs | 2 +- .../Notifications/SqliteNotificationsRepository.cs | 11 ++- .../Security/AuthenticationRepository.cs | 5 +- .../Social/SharingRepository.cs | 5 +- Emby.Server.Implementations/Sync/SyncRepository.cs | 5 +- Emby.Server.Implementations/TV/TVSeriesManager.cs | 4 +- MediaBrowser.Api/Library/LibraryService.cs | 2 +- MediaBrowser.Api/Movies/MoviesService.cs | 17 +--- MediaBrowser.Controller/Entities/Audio/Audio.cs | 6 ++ MediaBrowser.Controller/Entities/BaseItem.cs | 22 ++++- MediaBrowser.Controller/Entities/Folder.cs | 39 +++++---- .../Entities/InternalItemsQuery.cs | 1 - MediaBrowser.Controller/Entities/TV/Episode.cs | 6 ++ MediaBrowser.Controller/Entities/TV/Season.cs | 6 ++ MediaBrowser.Controller/Entities/TV/Series.cs | 1 - .../Entities/UserViewBuilder.cs | 10 +-- MediaBrowser.Controller/Library/ILibraryManager.cs | 5 +- MediaBrowser.Controller/TV/ITVSeriesManager.cs | 2 +- MediaBrowser.Model/System/IEnvironmentInfo.cs | 1 + MediaBrowser.Providers/Manager/MetadataService.cs | 14 ++-- 32 files changed, 230 insertions(+), 176 deletions(-) (limited to 'MediaBrowser.Controller/Library/ILibraryManager.cs') diff --git a/Emby.Common.Implementations/EnvironmentInfo/EnvironmentInfo.cs b/Emby.Common.Implementations/EnvironmentInfo/EnvironmentInfo.cs index c040e39313..ebd596dc41 100644 --- a/Emby.Common.Implementations/EnvironmentInfo/EnvironmentInfo.cs +++ b/Emby.Common.Implementations/EnvironmentInfo/EnvironmentInfo.cs @@ -105,5 +105,10 @@ namespace Emby.Common.Implementations.EnvironmentInfo { return null; } + + public string StackTrace + { + get { return Environment.StackTrace; } + } } } diff --git a/Emby.Server.Core/ApplicationHost.cs b/Emby.Server.Core/ApplicationHost.cs index 55a8510337..d481380805 100644 --- a/Emby.Server.Core/ApplicationHost.cs +++ b/Emby.Server.Core/ApplicationHost.cs @@ -551,7 +551,7 @@ namespace Emby.Server.Core DisplayPreferencesRepository = displayPreferencesRepo; RegisterSingleInstance(DisplayPreferencesRepository); - var itemRepo = new SqliteItemRepository(ServerConfigurationManager, JsonSerializer, LogManager.GetLogger("SqliteItemRepository"), MemoryStreamFactory, assemblyInfo, FileSystemManager); + var itemRepo = new SqliteItemRepository(ServerConfigurationManager, JsonSerializer, LogManager.GetLogger("SqliteItemRepository"), MemoryStreamFactory, assemblyInfo, FileSystemManager, EnvironmentInfo); ItemRepository = itemRepo; RegisterSingleInstance(ItemRepository); diff --git a/Emby.Server.Implementations/Activity/ActivityRepository.cs b/Emby.Server.Implementations/Activity/ActivityRepository.cs index 8a7573d666..eef9792de4 100644 --- a/Emby.Server.Implementations/Activity/ActivityRepository.cs +++ b/Emby.Server.Implementations/Activity/ActivityRepository.cs @@ -29,10 +29,9 @@ namespace Emby.Server.Implementations.Activity { connection.ExecuteAll(string.Join(";", new[] { + "PRAGMA page_size=4096", "pragma default_temp_store = memory", - "pragma default_synchronous=Normal", - "pragma temp_store = memory", - "pragma synchronous=Normal", + "pragma temp_store = memory" })); string[] queries = { diff --git a/Emby.Server.Implementations/Data/BaseSqliteRepository.cs b/Emby.Server.Implementations/Data/BaseSqliteRepository.cs index 382c7f2457..d4226ec256 100644 --- a/Emby.Server.Implementations/Data/BaseSqliteRepository.cs +++ b/Emby.Server.Implementations/Data/BaseSqliteRepository.cs @@ -40,6 +40,8 @@ namespace Emby.Server.Implementations.Data private static bool _versionLogged; + private string _defaultWal; + protected SQLiteDatabaseConnection CreateConnection(bool isReadOnly = false, Action onConnect = null) { if (!_versionLogged) @@ -51,6 +53,15 @@ namespace Emby.Server.Implementations.Data ConnectionFlags connectionFlags; + if (isReadOnly) + { + //Logger.Info("Opening read connection"); + } + else + { + //Logger.Info("Opening write connection"); + } + isReadOnly = false; if (isReadOnly) @@ -70,12 +81,16 @@ namespace Emby.Server.Implementations.Data var db = SQLite3.Open(DbFilePath, connectionFlags, null); + if (string.IsNullOrWhiteSpace(_defaultWal)) + { + _defaultWal = db.Query("PRAGMA journal_mode").SelectScalarString().First(); + } + var queries = new List { + "PRAGMA default_temp_store=memory", "pragma temp_store = memory", - "PRAGMA page_size=4096", - "PRAGMA journal_mode=WAL", - "pragma synchronous=Normal", + "PRAGMA journal_mode=WAL" //"PRAGMA cache size=-10000" }; @@ -90,13 +105,19 @@ namespace Emby.Server.Implementations.Data //// db.Execute(query); ////} - using (WriteLock.Write()) - { - db.ExecuteAll(string.Join(";", queries.ToArray())); + //Logger.Info("synchronous: " + db.Query("PRAGMA synchronous").SelectScalarString().First()); + //Logger.Info("temp_store: " + db.Query("PRAGMA temp_store").SelectScalarString().First()); - if (onConnect != null) + //if (!string.Equals(_defaultWal, "wal", StringComparison.OrdinalIgnoreCase) || onConnect != null) + { + using (WriteLock.Write()) { - onConnect(db); + db.ExecuteAll(string.Join(";", queries.ToArray())); + + if (onConnect != null) + { + onConnect(db); + } } } diff --git a/Emby.Server.Implementations/Data/SqliteDisplayPreferencesRepository.cs b/Emby.Server.Implementations/Data/SqliteDisplayPreferencesRepository.cs index ab927ce867..17afbcfa91 100644 --- a/Emby.Server.Implementations/Data/SqliteDisplayPreferencesRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteDisplayPreferencesRepository.cs @@ -56,10 +56,9 @@ namespace Emby.Server.Implementations.Data { connection.ExecuteAll(string.Join(";", new[] { + "PRAGMA page_size=4096", "pragma default_temp_store = memory", - "pragma default_synchronous=Normal", - "pragma temp_store = memory", - "pragma synchronous=Normal", + "pragma temp_store = memory" })); string[] queries = { diff --git a/Emby.Server.Implementations/Data/SqliteFileOrganizationRepository.cs b/Emby.Server.Implementations/Data/SqliteFileOrganizationRepository.cs index a716823299..efc0ee2ed0 100644 --- a/Emby.Server.Implementations/Data/SqliteFileOrganizationRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteFileOrganizationRepository.cs @@ -33,10 +33,9 @@ namespace Emby.Server.Implementations.Data { connection.ExecuteAll(string.Join(";", new[] { + "PRAGMA page_size=4096", "pragma default_temp_store = memory", - "pragma default_synchronous=Normal", - "pragma temp_store = memory", - "pragma synchronous=Normal", + "pragma temp_store = memory" })); string[] queries = { diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs index 754af96407..bc1eca06a9 100644 --- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs @@ -29,6 +29,7 @@ using MediaBrowser.Server.Implementations.Devices; using MediaBrowser.Server.Implementations.Playlists; using MediaBrowser.Model.Reflection; using SQLitePCL.pretty; +using MediaBrowser.Model.System; namespace Emby.Server.Implementations.Data { @@ -66,14 +67,14 @@ namespace Emby.Server.Implementations.Data private readonly string _criticReviewsPath; - public const int LatestSchemaVersion = 109; private readonly IMemoryStreamFactory _memoryStreamProvider; private readonly IFileSystem _fileSystem; + private readonly IEnvironmentInfo _environmentInfo; /// /// Initializes a new instance of the class. /// - public SqliteItemRepository(IServerConfigurationManager config, IJsonSerializer jsonSerializer, ILogger logger, IMemoryStreamFactory memoryStreamProvider, IAssemblyInfo assemblyInfo, IFileSystem fileSystem) + public SqliteItemRepository(IServerConfigurationManager config, IJsonSerializer jsonSerializer, ILogger logger, IMemoryStreamFactory memoryStreamProvider, IAssemblyInfo assemblyInfo, IFileSystem fileSystem, IEnvironmentInfo environmentInfo) : base(logger) { if (config == null) @@ -89,6 +90,7 @@ namespace Emby.Server.Implementations.Data _jsonSerializer = jsonSerializer; _memoryStreamProvider = memoryStreamProvider; _fileSystem = fileSystem; + _environmentInfo = environmentInfo; _typeMapper = new TypeMapper(assemblyInfo); _criticReviewsPath = Path.Combine(_config.ApplicationPaths.DataPath, "critic-reviews"); @@ -129,10 +131,9 @@ namespace Emby.Server.Implementations.Data _connection.ExecuteAll(string.Join(";", new[] { - "pragma default_temp_store = memory", - "pragma default_synchronous=Normal", - "pragma temp_store = memory", - "pragma synchronous=Normal", + "PRAGMA page_size=4096", + "PRAGMA default_temp_store=memory", + "PRAGMA temp_store=memory" })); var createMediaStreamsTableCommand @@ -193,7 +194,6 @@ namespace Emby.Server.Implementations.Data AddColumn(db, "TypedBaseItems", "ProductionYear", "INT", existingColumnNames); AddColumn(db, "TypedBaseItems", "ParentId", "GUID", existingColumnNames); AddColumn(db, "TypedBaseItems", "Genres", "Text", existingColumnNames); - AddColumn(db, "TypedBaseItems", "SchemaVersion", "INT", existingColumnNames); AddColumn(db, "TypedBaseItems", "SortName", "Text", existingColumnNames); AddColumn(db, "TypedBaseItems", "RunTimeTicks", "BIGINT", existingColumnNames); @@ -205,7 +205,6 @@ namespace Emby.Server.Implementations.Data AddColumn(db, "TypedBaseItems", "DateModified", "DATETIME", existingColumnNames); AddColumn(db, "TypedBaseItems", "ForcedSortName", "Text", existingColumnNames); - AddColumn(db, "TypedBaseItems", "IsOffline", "BIT", existingColumnNames); AddColumn(db, "TypedBaseItems", "LocationType", "Text", existingColumnNames); AddColumn(db, "TypedBaseItems", "IsSeries", "BIT", existingColumnNames); @@ -381,7 +380,6 @@ namespace Emby.Server.Implementations.Data "data", "StartDate", "EndDate", - "IsOffline", "ChannelId", "IsMovie", "IsSports", @@ -529,7 +527,6 @@ namespace Emby.Server.Implementations.Data "ParentId", "Genres", "InheritedParentalRatingValue", - "SchemaVersion", "SortName", "RunTimeTicks", "OfficialRatingDescription", @@ -539,7 +536,6 @@ namespace Emby.Server.Implementations.Data "DateCreated", "DateModified", "ForcedSortName", - "IsOffline", "LocationType", "PreferredMetadataLanguage", "PreferredMetadataCountryCode", @@ -790,7 +786,6 @@ namespace Emby.Server.Implementations.Data } saveItemStatement.TryBind("@InheritedParentalRatingValue", item.GetInheritedParentalRatingValue() ?? 0); - saveItemStatement.TryBind("@SchemaVersion", LatestSchemaVersion); saveItemStatement.TryBind("@SortName", item.SortName); saveItemStatement.TryBind("@RunTimeTicks", item.RunTimeTicks); @@ -803,7 +798,6 @@ namespace Emby.Server.Implementations.Data saveItemStatement.TryBind("@DateModified", item.DateModified); saveItemStatement.TryBind("@ForcedSortName", item.ForcedSortName); - saveItemStatement.TryBind("@IsOffline", item.IsOffline); saveItemStatement.TryBind("@LocationType", item.LocationType.ToString()); saveItemStatement.TryBind("@PreferredMetadataLanguage", item.PreferredMetadataLanguage); @@ -1182,7 +1176,7 @@ namespace Emby.Server.Implementations.Data } CheckDisposed(); - + //Logger.Info("Retrieving item {0}", id.ToString("N")); using (var connection = CreateConnection(true)) { using (WriteLock.Read()) @@ -1369,64 +1363,72 @@ namespace Emby.Server.Implementations.Data if (!reader.IsDBNull(4)) { - item.IsOffline = reader.GetBoolean(4); + item.ChannelId = reader.GetString(4); } - if (!reader.IsDBNull(5)) - { - item.ChannelId = reader.GetString(5); - } + var index = 5; var hasProgramAttributes = item as IHasProgramAttributes; if (hasProgramAttributes != null) { - if (!reader.IsDBNull(6)) + if (!reader.IsDBNull(index)) { - hasProgramAttributes.IsMovie = reader.GetBoolean(6); + hasProgramAttributes.IsMovie = reader.GetBoolean(index); } + index++; - if (!reader.IsDBNull(7)) + if (!reader.IsDBNull(index)) { - hasProgramAttributes.IsSports = reader.GetBoolean(7); + hasProgramAttributes.IsSports = reader.GetBoolean(index); } + index++; - if (!reader.IsDBNull(8)) + if (!reader.IsDBNull(index)) { - hasProgramAttributes.IsKids = reader.GetBoolean(8); + hasProgramAttributes.IsKids = reader.GetBoolean(index); } + index++; - if (!reader.IsDBNull(9)) + if (!reader.IsDBNull(index)) { - hasProgramAttributes.IsSeries = reader.GetBoolean(9); + hasProgramAttributes.IsSeries = reader.GetBoolean(index); } + index++; - if (!reader.IsDBNull(10)) + if (!reader.IsDBNull(index)) { - hasProgramAttributes.IsLive = reader.GetBoolean(10); + hasProgramAttributes.IsLive = reader.GetBoolean(index); } + index++; - if (!reader.IsDBNull(11)) + if (!reader.IsDBNull(index)) { - hasProgramAttributes.IsNews = reader.GetBoolean(11); + hasProgramAttributes.IsNews = reader.GetBoolean(index); } + index++; - if (!reader.IsDBNull(12)) + if (!reader.IsDBNull(index)) { - hasProgramAttributes.IsPremiere = reader.GetBoolean(12); + hasProgramAttributes.IsPremiere = reader.GetBoolean(index); } + index++; - if (!reader.IsDBNull(13)) + if (!reader.IsDBNull(index)) { - hasProgramAttributes.EpisodeTitle = reader.GetString(13); + hasProgramAttributes.EpisodeTitle = reader.GetString(index); } + index++; - if (!reader.IsDBNull(14)) + if (!reader.IsDBNull(index)) { - hasProgramAttributes.IsRepeat = reader.GetBoolean(14); + hasProgramAttributes.IsRepeat = reader.GetBoolean(index); } + index++; + } + else + { + index += 9; } - - var index = 15; if (!reader.IsDBNull(index)) { @@ -2368,6 +2370,8 @@ namespace Emby.Server.Implementations.Data CheckDisposed(); + //Logger.Info("GetItemList: " + _environmentInfo.StackTrace); + var now = DateTime.UtcNow; var list = new List(); @@ -2533,6 +2537,7 @@ namespace Emby.Server.Implementations.Data TotalRecordCount = returnList.Count }; } + //Logger.Info("GetItems: " + _environmentInfo.StackTrace); var now = DateTime.UtcNow; @@ -2770,6 +2775,7 @@ namespace Emby.Server.Implementations.Data } CheckDisposed(); + //Logger.Info("GetItemIdsList: " + _environmentInfo.StackTrace); var now = DateTime.UtcNow; @@ -2928,6 +2934,7 @@ namespace Emby.Server.Implementations.Data TotalRecordCount = returnList.Count }; } + //Logger.Info("GetItemIds: " + _environmentInfo.StackTrace); var now = DateTime.UtcNow; @@ -3053,14 +3060,6 @@ namespace Emby.Server.Implementations.Data statement.TryBind("@IsLocked", query.IsLocked); } } - if (query.IsOffline.HasValue) - { - whereClauses.Add("IsOffline=@IsOffline"); - if (statement != null) - { - statement.TryBind("@IsOffline", query.IsOffline); - } - } var exclusiveProgramAttribtues = !(query.IsMovie ?? true) || !(query.IsSports ?? true) || @@ -4721,7 +4720,7 @@ namespace Emby.Server.Implementations.Data using (var connection = CreateConnection(true)) { - using (WriteLock.Write()) + using (WriteLock.Read()) { foreach (var row in connection.Query(commandText)) { @@ -4750,6 +4749,7 @@ namespace Emby.Server.Implementations.Data } CheckDisposed(); + //Logger.Info("GetItemValues: " + _environmentInfo.StackTrace); var now = DateTime.UtcNow; diff --git a/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs b/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs index 0b4768c141..9f7cce13b5 100644 --- a/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs @@ -45,10 +45,9 @@ namespace Emby.Server.Implementations.Data { connection.ExecuteAll(string.Join(";", new[] { + "PRAGMA page_size=4096", "pragma default_temp_store = memory", - "pragma default_synchronous=Normal", - "pragma temp_store = memory", - "pragma synchronous=Normal", + "pragma temp_store = memory" })); string[] queries = { diff --git a/Emby.Server.Implementations/Data/SqliteUserRepository.cs b/Emby.Server.Implementations/Data/SqliteUserRepository.cs index 0a2f9e7cde..f902d981fe 100644 --- a/Emby.Server.Implementations/Data/SqliteUserRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteUserRepository.cs @@ -52,10 +52,9 @@ namespace Emby.Server.Implementations.Data { connection.ExecuteAll(string.Join(";", new[] { + "PRAGMA page_size=4096", "pragma default_temp_store = memory", - "pragma default_synchronous=Normal", - "pragma temp_store = memory", - "pragma synchronous=Normal", + "pragma temp_store = memory" })); string[] queries = { diff --git a/Emby.Server.Implementations/Dto/DtoService.cs b/Emby.Server.Implementations/Dto/DtoService.cs index 85549439b7..438fc55d77 100644 --- a/Emby.Server.Implementations/Dto/DtoService.cs +++ b/Emby.Server.Implementations/Dto/DtoService.cs @@ -482,7 +482,7 @@ namespace Emby.Server.Implementations.Dto { if (dtoOptions.EnableUserData) { - dto.UserData = _userDataRepository.GetUserDataDto(item, user).Result; + dto.UserData = await _userDataRepository.GetUserDataDto(item, user).ConfigureAwait(false); } } @@ -1450,11 +1450,19 @@ namespace Emby.Server.Implementations.Dto private void AddInheritedImages(BaseItemDto dto, BaseItem item, DtoOptions options, BaseItem owner) { + if (!item.SupportsInheritedParentImages) + { + return; + } + var logoLimit = options.GetImageLimit(ImageType.Logo); var artLimit = options.GetImageLimit(ImageType.Art); var thumbLimit = options.GetImageLimit(ImageType.Thumb); var backdropLimit = options.GetImageLimit(ImageType.Backdrop); + // For now. Emby apps are not using this + artLimit = 0; + if (logoLimit == 0 && artLimit == 0 && thumbLimit == 0 && backdropLimit == 0) { return; @@ -1515,6 +1523,12 @@ namespace Emby.Server.Implementations.Dto } isFirst = false; + + if (!parent.SupportsInheritedParentImages) + { + break; + } + parent = parent.GetParent(); } } diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index 13c6485e5b..283d193dd6 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -339,11 +339,6 @@ namespace Emby.Server.Implementations.Library { throw new ArgumentNullException("item"); } - RegisterItem(item.Id, item); - } - - private void RegisterItem(Guid id, BaseItem item) - { if (item is IItemByName) { if (!(item is MusicArtist)) @@ -354,13 +349,13 @@ namespace Emby.Server.Implementations.Library if (item.IsFolder) { - if (!(item is ICollectionFolder) && !(item is UserView) && !(item is Channel) && !(item is AggregateFolder)) - { - if (item.SourceType != SourceType.Library) - { - return; - } - } + //if (!(item is ICollectionFolder) && !(item is UserView) && !(item is Channel) && !(item is AggregateFolder)) + //{ + // if (item.SourceType != SourceType.Library) + // { + // return; + // } + //} } else { @@ -370,7 +365,7 @@ namespace Emby.Server.Implementations.Library } } - LibraryItemsCache.AddOrUpdate(id, item, delegate { return item; }); + LibraryItemsCache.AddOrUpdate(item.Id, item, delegate { return item; }); } public async Task DeleteItem(BaseItem item, DeleteOptions options) @@ -822,7 +817,7 @@ namespace Emby.Server.Implementations.Library return _userRootFolder; } - + public BaseItem FindByPath(string path, bool? isFolder) { // If this returns multiple items it could be tricky figuring out which one is correct. @@ -836,7 +831,7 @@ namespace Emby.Server.Implementations.Library SortOrder = SortOrder.Descending, Limit = 1 }; - + return GetItemList(query) .FirstOrDefault(); } @@ -1273,10 +1268,8 @@ namespace Emby.Server.Implementations.Library return ItemRepository.GetItemList(query); } - public IEnumerable GetItemList(InternalItemsQuery query, IEnumerable parentIds) + public IEnumerable GetItemList(InternalItemsQuery query, List parents) { - var parents = parentIds.Select(i => GetItemById(new Guid(i))).Where(i => i != null).ToList(); - SetTopParentIdsOrAncestors(query, parents); if (query.AncestorIds.Length == 0 && query.TopParentIds.Length == 0) @@ -1536,7 +1529,7 @@ namespace Emby.Server.Implementations.Library } // Handle grouping - if (user != null && !string.IsNullOrWhiteSpace(view.ViewType) && UserView.IsEligibleForGrouping(view.ViewType)) + if (user != null && !string.IsNullOrWhiteSpace(view.ViewType) && UserView.IsEligibleForGrouping(view.ViewType) && user.Configuration.GroupedFolders.Length > 0) { return user.RootFolder .GetChildren(user, true) diff --git a/Emby.Server.Implementations/Library/UserViewManager.cs b/Emby.Server.Implementations/Library/UserViewManager.cs index b93f565a32..f7cc8bb73f 100644 --- a/Emby.Server.Implementations/Library/UserViewManager.cs +++ b/Emby.Server.Implementations/Library/UserViewManager.cs @@ -245,20 +245,26 @@ namespace Emby.Server.Implementations.Library var includeItemTypes = request.IncludeItemTypes; var limit = request.Limit ?? 10; - var parentIds = string.IsNullOrEmpty(parentId) - ? new string[] { } - : new[] { parentId }; + var parents = new List(); - if (parentIds.Length == 0) + if (!string.IsNullOrWhiteSpace(parentId)) { - parentIds = user.RootFolder.GetChildren(user, true) - .OfType() - .Select(i => i.Id.ToString("N")) - .Where(i => !user.Configuration.LatestItemsExcludes.Contains(i)) - .ToArray(); + var parent = _libraryManager.GetItemById(parentId) as Folder; + if (parent != null) + { + parents.Add(parent); + } + } + + if (parents.Count == 0) + { + parents = user.RootFolder.GetChildren(user, true) + .Where(i => i is Folder) + .Where(i => !user.Configuration.LatestItemsExcludes.Contains(i.Id.ToString("N"))) + .ToList(); } - if (parentIds.Length == 0) + if (parents.Count == 0) { return new List(); } @@ -283,10 +289,10 @@ namespace Emby.Server.Implementations.Library ExcludeItemTypes = excludeItemTypes, ExcludeLocationTypes = new[] { LocationType.Virtual }, Limit = limit * 5, - SourceTypes = parentIds.Length == 0 ? new[] { SourceType.Library } : new SourceType[] { }, + SourceTypes = parents.Count == 0 ? new[] { SourceType.Library } : new SourceType[] { }, IsPlayed = request.IsPlayed - }, parentIds); + }, parents); } } } diff --git a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs index 3a6f23fe95..faf9687f40 100644 --- a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs @@ -491,7 +491,7 @@ namespace Emby.Server.Implementations.LiveTv var id = _tvDtoService.GetInternalChannelId(serviceName, channelInfo.Id); - var item = _itemRepo.RetrieveItem(id) as LiveTvChannel; + var item = _libraryManager.GetItemById(id) as LiveTvChannel; if (item == null) { diff --git a/Emby.Server.Implementations/Notifications/SqliteNotificationsRepository.cs b/Emby.Server.Implementations/Notifications/SqliteNotificationsRepository.cs index 5fc691527e..66ef5d5d18 100644 --- a/Emby.Server.Implementations/Notifications/SqliteNotificationsRepository.cs +++ b/Emby.Server.Implementations/Notifications/SqliteNotificationsRepository.cs @@ -31,10 +31,9 @@ namespace Emby.Server.Implementations.Notifications { connection.ExecuteAll(string.Join(";", new[] { + "PRAGMA page_size=4096", "pragma default_temp_store = memory", - "pragma default_synchronous=Normal", - "pragma temp_store = memory", - "pragma synchronous=Normal", + "pragma temp_store = memory" })); string[] queries = { @@ -57,9 +56,9 @@ namespace Emby.Server.Implementations.Notifications { var result = new NotificationResult(); - using (WriteLock.Read()) + using (var connection = CreateConnection(true)) { - using (var connection = CreateConnection(true)) + //using (WriteLock.Read()) { var clauses = new List(); var paramList = new List(); @@ -114,7 +113,7 @@ namespace Emby.Server.Implementations.Notifications using (var connection = CreateConnection(true)) { - using (WriteLock.Read()) + //using (WriteLock.Read()) { using (var statement = connection.PrepareStatement("select Level from Notifications where UserId=@UserId and IsRead=@IsRead")) { diff --git a/Emby.Server.Implementations/Security/AuthenticationRepository.cs b/Emby.Server.Implementations/Security/AuthenticationRepository.cs index 0a598e9a71..dad05718c9 100644 --- a/Emby.Server.Implementations/Security/AuthenticationRepository.cs +++ b/Emby.Server.Implementations/Security/AuthenticationRepository.cs @@ -32,10 +32,9 @@ namespace Emby.Server.Implementations.Security { connection.ExecuteAll(string.Join(";", new[] { + "PRAGMA page_size=4096", "pragma default_temp_store = memory", - "pragma default_synchronous=Normal", - "pragma temp_store = memory", - "pragma synchronous=Normal", + "pragma temp_store = memory" })); string[] queries = { diff --git a/Emby.Server.Implementations/Social/SharingRepository.cs b/Emby.Server.Implementations/Social/SharingRepository.cs index e0ee62780e..6dab54bc6b 100644 --- a/Emby.Server.Implementations/Social/SharingRepository.cs +++ b/Emby.Server.Implementations/Social/SharingRepository.cs @@ -29,10 +29,9 @@ namespace Emby.Server.Implementations.Social { connection.ExecuteAll(string.Join(";", new[] { + "PRAGMA page_size=4096", "pragma default_temp_store = memory", - "pragma default_synchronous=Normal", - "pragma temp_store = memory", - "pragma synchronous=Normal", + "pragma temp_store = memory" })); string[] queries = { diff --git a/Emby.Server.Implementations/Sync/SyncRepository.cs b/Emby.Server.Implementations/Sync/SyncRepository.cs index 36558142b9..308c3bd00d 100644 --- a/Emby.Server.Implementations/Sync/SyncRepository.cs +++ b/Emby.Server.Implementations/Sync/SyncRepository.cs @@ -45,10 +45,9 @@ namespace Emby.Server.Implementations.Sync { connection.ExecuteAll(string.Join(";", new[] { + "PRAGMA page_size=4096", "pragma default_temp_store = memory", - "pragma default_synchronous=Normal", - "pragma temp_store = memory", - "pragma synchronous=Normal", + "pragma temp_store = memory" })); string[] queries = { diff --git a/Emby.Server.Implementations/TV/TVSeriesManager.cs b/Emby.Server.Implementations/TV/TVSeriesManager.cs index a47aaa3055..fd576e081f 100644 --- a/Emby.Server.Implementations/TV/TVSeriesManager.cs +++ b/Emby.Server.Implementations/TV/TVSeriesManager.cs @@ -72,7 +72,7 @@ namespace Emby.Server.Implementations.TV return GetResult(episodes, null, request); } - public QueryResult GetNextUp(NextUpQuery request, IEnumerable parentsFolders) + public QueryResult GetNextUp(NextUpQuery request, List parentsFolders) { var user = _userManager.GetUserById(request.UserId); @@ -106,7 +106,7 @@ namespace Emby.Server.Implementations.TV PresentationUniqueKey = presentationUniqueKey, Limit = limit - }, parentsFolders.Select(i => i.Id.ToString("N"))).Cast(); + }, parentsFolders.Cast().ToList()).Cast(); // Avoid implicitly captured closure var episodes = GetNextUpEpisodes(request, user, items); diff --git a/MediaBrowser.Api/Library/LibraryService.cs b/MediaBrowser.Api/Library/LibraryService.cs index 36a58cc208..695718a255 100644 --- a/MediaBrowser.Api/Library/LibraryService.cs +++ b/MediaBrowser.Api/Library/LibraryService.cs @@ -369,7 +369,7 @@ namespace MediaBrowser.Api.Library if (item is Movie || (program != null && program.IsMovie) || item is Trailer) { - return new MoviesService(_userManager, _userDataManager, _libraryManager, _itemRepo, _dtoService, _config, _authContext) + return new MoviesService(_userManager, _libraryManager, _dtoService, _config, _authContext) { Request = Request, diff --git a/MediaBrowser.Api/Movies/MoviesService.cs b/MediaBrowser.Api/Movies/MoviesService.cs index 1b2fa4fff9..b5c6f52fc0 100644 --- a/MediaBrowser.Api/Movies/MoviesService.cs +++ b/MediaBrowser.Api/Movies/MoviesService.cs @@ -78,16 +78,8 @@ namespace MediaBrowser.Api.Movies /// private readonly IUserManager _userManager; - /// - /// The _user data repository - /// - private readonly IUserDataManager _userDataRepository; - /// - /// The _library manager - /// private readonly ILibraryManager _libraryManager; - private readonly IItemRepository _itemRepo; private readonly IDtoService _dtoService; private readonly IServerConfigurationManager _config; private readonly IAuthorizationContext _authContext; @@ -95,17 +87,10 @@ namespace MediaBrowser.Api.Movies /// /// Initializes a new instance of the class. /// - /// The user manager. - /// The user data repository. - /// The library manager. - /// The item repo. - /// The dto service. - public MoviesService(IUserManager userManager, IUserDataManager userDataRepository, ILibraryManager libraryManager, IItemRepository itemRepo, IDtoService dtoService, IServerConfigurationManager config, IAuthorizationContext authContext) + public MoviesService(IUserManager userManager, ILibraryManager libraryManager, IDtoService dtoService, IServerConfigurationManager config, IAuthorizationContext authContext) { _userManager = userManager; - _userDataRepository = userDataRepository; _libraryManager = libraryManager; - _itemRepo = itemRepo; _dtoService = dtoService; _config = config; _authContext = authContext; diff --git a/MediaBrowser.Controller/Entities/Audio/Audio.cs b/MediaBrowser.Controller/Entities/Audio/Audio.cs index 539cc5f221..e4f638cb6f 100644 --- a/MediaBrowser.Controller/Entities/Audio/Audio.cs +++ b/MediaBrowser.Controller/Entities/Audio/Audio.cs @@ -61,6 +61,12 @@ namespace MediaBrowser.Controller.Entities.Audio get { return true; } } + [IgnoreDataMember] + public override bool SupportsInheritedParentImages + { + get { return true; } + } + [IgnoreDataMember] protected override bool SupportsOwnedItems { diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index cd61d2cce4..b7ea7a92d8 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -1569,6 +1569,12 @@ namespace MediaBrowser.Controller.Entities return IsVisibleStandaloneInternal(user, true); } + [IgnoreDataMember] + public virtual bool SupportsInheritedParentImages + { + get { return false; } + } + protected bool IsVisibleStandaloneInternal(User user, bool checkFolders) { if (!IsVisible(user)) @@ -2329,17 +2335,25 @@ namespace MediaBrowser.Controller.Entities { get { - if (GetParent() is AggregateFolder || this is BasePluginFolder || this is Channel) + if (this is BasePluginFolder || this is Channel) { return true; } var view = this as UserView; - if (view != null && string.Equals(view.ViewType, CollectionType.LiveTv, StringComparison.OrdinalIgnoreCase)) + if (view != null) { - return true; + if (string.Equals(view.ViewType, CollectionType.LiveTv, StringComparison.OrdinalIgnoreCase)) + { + return true; + } + if (string.Equals(view.ViewType, CollectionType.Channels, StringComparison.OrdinalIgnoreCase)) + { + return true; + } } - if (view != null && string.Equals(view.ViewType, CollectionType.Channels, StringComparison.OrdinalIgnoreCase)) + + if (GetParent() is AggregateFolder) { return true; } diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index 3df77673f7..d4ddab7b28 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -1383,6 +1383,15 @@ namespace MediaBrowser.Controller.Entities { return false; } + var iItemByName = this as IItemByName; + if (iItemByName != null) + { + var hasDualAccess = this as IHasDualAccess; + if (hasDualAccess == null || hasDualAccess.IsAccessedByName) + { + return false; + } + } return true; } @@ -1395,17 +1404,6 @@ namespace MediaBrowser.Controller.Entities return; } - var unplayedQueryResult = await GetItems(new InternalItemsQuery(user) - { - Recursive = true, - IsFolder = false, - IsVirtualItem = false, - EnableTotalRecordCount = true, - Limit = 0, - IsPlayed = false - - }).ConfigureAwait(false); - var allItemsQueryResult = await GetItems(new InternalItemsQuery(user) { Recursive = true, @@ -1415,17 +1413,28 @@ namespace MediaBrowser.Controller.Entities Limit = 0 }).ConfigureAwait(false); + var recursiveItemCount = allItemsQueryResult.TotalRecordCount; if (itemDto != null) { itemDto.RecursiveItemCount = allItemsQueryResult.TotalRecordCount; } - var recursiveItemCount = allItemsQueryResult.TotalRecordCount; - double unplayedCount = unplayedQueryResult.TotalRecordCount; - - if (recursiveItemCount > 0) + if (recursiveItemCount > 0 && SupportsPlayedStatus) { + var unplayedQueryResult = recursiveItemCount > 0 ? await GetItems(new InternalItemsQuery(user) + { + Recursive = true, + IsFolder = false, + IsVirtualItem = false, + EnableTotalRecordCount = true, + Limit = 0, + IsPlayed = false + + }).ConfigureAwait(false) : new QueryResult(); + + double unplayedCount = unplayedQueryResult.TotalRecordCount; + var unplayedPercentage = (unplayedCount / recursiveItemCount) * 100; dto.PlayedPercentage = 100 - unplayedPercentage; dto.Played = dto.PlayedPercentage.Value >= 100; diff --git a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs index 94baacf133..be6e95ddd6 100644 --- a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs +++ b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs @@ -124,7 +124,6 @@ namespace MediaBrowser.Controller.Entities public int? MaxParentalRating { get; set; } public bool? HasDeadParentId { get; set; } - public bool? IsOffline { get; set; } public bool? IsVirtualItem { get; set; } public Guid? ParentId { get; set; } diff --git a/MediaBrowser.Controller/Entities/TV/Episode.cs b/MediaBrowser.Controller/Entities/TV/Episode.cs index 99abf56119..29a63f3175 100644 --- a/MediaBrowser.Controller/Entities/TV/Episode.cs +++ b/MediaBrowser.Controller/Entities/TV/Episode.cs @@ -71,6 +71,12 @@ namespace MediaBrowser.Controller.Entities.TV { return IsStacked || MediaSourceCount > 1; } + } + + [IgnoreDataMember] + public override bool SupportsInheritedParentImages + { + get { return true; } } [IgnoreDataMember] diff --git a/MediaBrowser.Controller/Entities/TV/Season.cs b/MediaBrowser.Controller/Entities/TV/Season.cs index d8a9a16c17..2663a9dd50 100644 --- a/MediaBrowser.Controller/Entities/TV/Season.cs +++ b/MediaBrowser.Controller/Entities/TV/Season.cs @@ -39,6 +39,12 @@ namespace MediaBrowser.Controller.Entities.TV } } + [IgnoreDataMember] + public override bool SupportsInheritedParentImages + { + get { return true; } + } + [IgnoreDataMember] public override Guid? DisplayParentId { diff --git a/MediaBrowser.Controller/Entities/TV/Series.cs b/MediaBrowser.Controller/Entities/TV/Series.cs index a997d34766..69a3a67c81 100644 --- a/MediaBrowser.Controller/Entities/TV/Series.cs +++ b/MediaBrowser.Controller/Entities/TV/Series.cs @@ -135,7 +135,6 @@ namespace MediaBrowser.Controller.Entities.TV { AncestorWithPresentationUniqueKey = GetUniqueSeriesKey(this), IncludeItemTypes = new[] { typeof(Season).Name }, - SortBy = new[] { ItemSortBy.SortName }, IsVirtualItem = false, Limit = 0 }); diff --git a/MediaBrowser.Controller/Entities/UserViewBuilder.cs b/MediaBrowser.Controller/Entities/UserViewBuilder.cs index 3820de83d1..d5781d21e2 100644 --- a/MediaBrowser.Controller/Entities/UserViewBuilder.cs +++ b/MediaBrowser.Controller/Entities/UserViewBuilder.cs @@ -1812,7 +1812,7 @@ namespace MediaBrowser.Controller.Entities .Where(i => user.IsFolderGrouped(i.Id) && UserView.IsEligibleForGrouping(i)); } - private IEnumerable GetMediaFolders(User user, IEnumerable viewTypes) + private List GetMediaFolders(User user, IEnumerable viewTypes) { if (user == null) { @@ -1822,7 +1822,7 @@ namespace MediaBrowser.Controller.Entities var folder = i as ICollectionFolder; return folder != null && viewTypes.Contains(folder.CollectionType ?? string.Empty, StringComparer.OrdinalIgnoreCase); - }); + }).ToList(); } return GetMediaFolders(user) .Where(i => @@ -1830,17 +1830,17 @@ namespace MediaBrowser.Controller.Entities var folder = i as ICollectionFolder; return folder != null && viewTypes.Contains(folder.CollectionType ?? string.Empty, StringComparer.OrdinalIgnoreCase); - }); + }).ToList(); } - private IEnumerable GetMediaFolders(Folder parent, User user, IEnumerable viewTypes) + private List GetMediaFolders(Folder parent, User user, IEnumerable viewTypes) { if (parent == null || parent is UserView) { return GetMediaFolders(user, viewTypes); } - return new[] { parent }; + return new List { parent }; } private IEnumerable GetRecursiveChildren(Folder parent, User user, IEnumerable viewTypes) diff --git a/MediaBrowser.Controller/Library/ILibraryManager.cs b/MediaBrowser.Controller/Library/ILibraryManager.cs index acdd9a0423..955230b8ab 100644 --- a/MediaBrowser.Controller/Library/ILibraryManager.cs +++ b/MediaBrowser.Controller/Library/ILibraryManager.cs @@ -538,10 +538,7 @@ namespace MediaBrowser.Controller.Library /// /// Gets the items. /// - /// The query. - /// The parent ids. - /// List<BaseItem>. - IEnumerable GetItemList(InternalItemsQuery query, IEnumerable parentIds); + IEnumerable GetItemList(InternalItemsQuery query, List parents); /// /// Gets the items result. diff --git a/MediaBrowser.Controller/TV/ITVSeriesManager.cs b/MediaBrowser.Controller/TV/ITVSeriesManager.cs index 3d6e87474c..771fa602a0 100644 --- a/MediaBrowser.Controller/TV/ITVSeriesManager.cs +++ b/MediaBrowser.Controller/TV/ITVSeriesManager.cs @@ -19,6 +19,6 @@ namespace MediaBrowser.Controller.TV /// The request. /// The parents folders. /// QueryResult<BaseItem>. - QueryResult GetNextUp(NextUpQuery request, IEnumerable parentsFolders); + QueryResult GetNextUp(NextUpQuery request, List parentsFolders); } } diff --git a/MediaBrowser.Model/System/IEnvironmentInfo.cs b/MediaBrowser.Model/System/IEnvironmentInfo.cs index 7e7d81e30b..f9795a5684 100644 --- a/MediaBrowser.Model/System/IEnvironmentInfo.cs +++ b/MediaBrowser.Model/System/IEnvironmentInfo.cs @@ -14,6 +14,7 @@ namespace MediaBrowser.Model.System Architecture SystemArchitecture { get; } string GetEnvironmentVariable(string name); string GetUserId(); + string StackTrace { get; } } public enum OperatingSystem diff --git a/MediaBrowser.Providers/Manager/MetadataService.cs b/MediaBrowser.Providers/Manager/MetadataService.cs index 3046fc395c..0491e800f6 100644 --- a/MediaBrowser.Providers/Manager/MetadataService.cs +++ b/MediaBrowser.Providers/Manager/MetadataService.cs @@ -536,7 +536,7 @@ namespace MediaBrowser.Providers.Manager refreshResult.UpdateType = refreshResult.UpdateType | ItemUpdateType.MetadataImport; // Only one local provider allowed per item - if (item.IsLocked || IsFullLocalMetadata(localItem.Item)) + if (item.IsLocked || localItem.Item.IsLocked || IsFullLocalMetadata(localItem.Item)) { hasLocalMetadata = true; } @@ -573,14 +573,16 @@ namespace MediaBrowser.Providers.Manager { if (refreshResult.UpdateType > ItemUpdateType.None) { - // If no local metadata, take data from item itself - if (!hasLocalMetadata) + if (hasLocalMetadata) + { + MergeData(temp, metadata, item.LockedFields, true, true); + } + else { // TODO: If the new metadata from above has some blank data, this can cause old data to get filled into those empty fields - MergeData(metadata, temp, new List(), false, true); + MergeData(metadata, temp, new List(), false, false); + MergeData(temp, metadata, item.LockedFields, true, false); } - - MergeData(temp, metadata, item.LockedFields, true, true); } } -- cgit v1.2.3 From d84bb7160f8c3cfc953cdece890264d70e504e39 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Mon, 12 Dec 2016 14:40:27 -0500 Subject: update next up queries --- .../Data/SqliteItemRepository.cs | 62 +++++++++++++++++++++- .../Library/LibraryManager.cs | 20 +++++++ MediaBrowser.Controller/Entities/TV/Series.cs | 28 +++++++--- MediaBrowser.Controller/Library/ILibraryManager.cs | 1 + .../Persistence/IItemRepository.cs | 2 + 5 files changed, 104 insertions(+), 9 deletions(-) (limited to 'MediaBrowser.Controller/Library/ILibraryManager.cs') diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs index 1f0f5a5217..14b81022dd 100644 --- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs @@ -2443,6 +2443,66 @@ namespace Emby.Server.Implementations.Data return " from TypedBaseItems " + alias; } + public int GetCount(InternalItemsQuery query) + { + if (query == null) + { + throw new ArgumentNullException("query"); + } + + CheckDisposed(); + + //Logger.Info("GetItemList: " + _environmentInfo.StackTrace); + + var now = DateTime.UtcNow; + + // Hack for right now since we currently don't support filtering out these duplicates within a query + if (query.Limit.HasValue && query.EnableGroupByMetadataKey) + { + query.Limit = query.Limit.Value + 4; + } + + var commandText = "select " + string.Join(",", GetFinalColumnsToSelect(query, new [] { "count(distinct PresentationUniqueKey)" })) + GetFromText(); + commandText += GetJoinUserDataText(query); + + var whereClauses = GetWhereClauses(query, null); + + var whereText = whereClauses.Count == 0 ? + string.Empty : + " where " + string.Join(" AND ", whereClauses.ToArray()); + + commandText += whereText; + + //commandText += GetGroupBy(query); + + int count = 0; + + using (WriteLock.Read()) + { + using (var connection = CreateConnection(true)) + { + using (var statement = PrepareStatementSafe(connection, commandText)) + { + if (EnableJoinUserData(query)) + { + statement.TryBind("@UserId", query.User.Id); + } + + BindSimilarParams(query, statement); + + // Running this again will bind the params + GetWhereClauses(query, statement); + + count = statement.ExecuteQuery().SelectScalarInt().First(); + } + } + + LogQueryTime("GetCount", commandText, now); + } + + return count; + } + public List GetItemList(InternalItemsQuery query) { if (query == null) @@ -2859,7 +2919,7 @@ namespace Emby.Server.Implementations.Data } if (string.Equals(name, ItemSortBy.SeriesDatePlayed, StringComparison.OrdinalIgnoreCase)) { - return new Tuple("(Select MAX(LastPlayedDate) from TypedBaseItems B" + GetJoinUserDataText(query) + " where B.SeriesPresentationUniqueKey=A.PresentationUniqueKey)", false); + return new Tuple("(Select MAX(LastPlayedDate) from TypedBaseItems B" + GetJoinUserDataText(query) + " where Played=1 and B.SeriesPresentationUniqueKey=A.PresentationUniqueKey)", false); } return new Tuple(name, false); diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index 3db8c7213c..ad91988e53 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -1279,6 +1279,26 @@ namespace Emby.Server.Implementations.Library return ItemRepository.GetItemList(query); } + public int GetCount(InternalItemsQuery query) + { + if (query.Recursive && query.ParentId.HasValue) + { + var parent = GetItemById(query.ParentId.Value); + if (parent != null) + { + SetTopParentIdsOrAncestors(query, new List { parent }); + query.ParentId = null; + } + } + + if (query.User != null) + { + AddUserToQuery(query, query.User); + } + + return ItemRepository.GetCount(query); + } + public IEnumerable GetItemList(InternalItemsQuery query, List parents) { SetTopParentIdsOrAncestors(query, parents); diff --git a/MediaBrowser.Controller/Entities/TV/Series.cs b/MediaBrowser.Controller/Entities/TV/Series.cs index caebff16f2..872011ce8d 100644 --- a/MediaBrowser.Controller/Entities/TV/Series.cs +++ b/MediaBrowser.Controller/Entities/TV/Series.cs @@ -138,16 +138,24 @@ namespace MediaBrowser.Controller.Entities.TV var enableSeriesPresentationKey = ConfigurationManager.Configuration.EnableSeriesPresentationUniqueKey; var seriesKey = GetUniqueSeriesKey(this); - var result = LibraryManager.GetItemsResult(new InternalItemsQuery(user) + var result = LibraryManager.GetCount(new InternalItemsQuery(user) { AncestorWithPresentationUniqueKey = enableSeriesPresentationKey ? null : seriesKey, SeriesPresentationUniqueKey = enableSeriesPresentationKey ? seriesKey : null, IncludeItemTypes = new[] { typeof(Season).Name }, IsVirtualItem = false, - Limit = 0 + Limit = 0, + DtoOptions = new Dto.DtoOptions + { + Fields = new List + { + + }, + EnableImages = false + } }); - return result.TotalRecordCount; + return result; } public override int GetRecursiveChildCount(User user) @@ -159,19 +167,23 @@ namespace MediaBrowser.Controller.Entities.TV { AncestorWithPresentationUniqueKey = enableSeriesPresentationKey ? null : seriesKey, SeriesPresentationUniqueKey = enableSeriesPresentationKey ? seriesKey : null, + DtoOptions = new Dto.DtoOptions + { + Fields = new List + { + + }, + EnableImages = false + } }; - 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; - var totalRecordCount = LibraryManager.GetItemsResult(query).TotalRecordCount; + var totalRecordCount = LibraryManager.GetCount(query); return totalRecordCount; } diff --git a/MediaBrowser.Controller/Library/ILibraryManager.cs b/MediaBrowser.Controller/Library/ILibraryManager.cs index 955230b8ab..d297fd0065 100644 --- a/MediaBrowser.Controller/Library/ILibraryManager.cs +++ b/MediaBrowser.Controller/Library/ILibraryManager.cs @@ -571,5 +571,6 @@ namespace MediaBrowser.Controller.Library void RegisterIgnoredPath(string path); void UnRegisterIgnoredPath(string path); + int GetCount(InternalItemsQuery query); } } \ No newline at end of file diff --git a/MediaBrowser.Controller/Persistence/IItemRepository.cs b/MediaBrowser.Controller/Persistence/IItemRepository.cs index 7a822e7b4e..58ae1f3b0e 100644 --- a/MediaBrowser.Controller/Persistence/IItemRepository.cs +++ b/MediaBrowser.Controller/Persistence/IItemRepository.cs @@ -163,6 +163,8 @@ namespace MediaBrowser.Controller.Persistence /// Task. Task UpdateInheritedValues(CancellationToken cancellationToken); + int GetCount(InternalItemsQuery query); + QueryResult> GetGenres(InternalItemsQuery query); QueryResult> GetMusicGenres(InternalItemsQuery query); QueryResult> GetGameGenres(InternalItemsQuery query); -- cgit v1.2.3 From e1b880a5a072764cabace79cd6d1d65315ec65e4 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Tue, 13 Dec 2016 02:36:30 -0500 Subject: update series queries --- .../Activity/ActivityRepository.cs | 15 +- .../Data/BaseSqliteRepository.cs | 2 + .../Data/SqliteItemRepository.cs | 261 +++++++++++---------- .../Data/SqliteUserDataRepository.cs | 12 +- Emby.Server.Implementations/Dto/DtoService.cs | 105 ++++++--- .../FileOrganization/EpisodeFileOrganizer.cs | 6 + .../SocketSharp/WebSocketSharpListener.cs | 3 +- .../Library/LibraryManager.cs | 58 +++-- .../Library/UserDataManager.cs | 7 +- .../Notifications/SqliteNotificationsRepository.cs | 20 +- .../Security/AuthenticationRepository.cs | 12 +- MediaBrowser.Api/BaseApiService.cs | 32 ++- MediaBrowser.Api/ItemLookupService.cs | 15 +- MediaBrowser.Controller/Entities/BaseItem.cs | 3 +- .../Entities/CollectionFolder.cs | 68 ++++-- MediaBrowser.Controller/Entities/Folder.cs | 36 +-- MediaBrowser.Controller/Entities/IHasUserData.cs | 6 +- MediaBrowser.Controller/Library/ILibraryManager.cs | 2 + .../Library/IUserDataManager.cs | 6 +- MediaBrowser.Model/Querying/ItemFields.cs | 2 + RSSDP/SsdpDevicePublisherBase.cs | 8 +- 21 files changed, 418 insertions(+), 261 deletions(-) (limited to 'MediaBrowser.Controller/Library/ILibraryManager.cs') diff --git a/Emby.Server.Implementations/Activity/ActivityRepository.cs b/Emby.Server.Implementations/Activity/ActivityRepository.cs index 7ac0e680ca..5f6518a14f 100644 --- a/Emby.Server.Implementations/Activity/ActivityRepository.cs +++ b/Emby.Server.Implementations/Activity/ActivityRepository.cs @@ -84,9 +84,6 @@ namespace Emby.Server.Implementations.Activity { using (var connection = CreateConnection(true)) { - var list = new List(); - var result = new QueryResult(); - var commandText = BaseActivitySelectText; var whereClauses = new List(); @@ -127,8 +124,11 @@ namespace Emby.Server.Implementations.Activity statementTexts.Add(commandText); statementTexts.Add("select count (Id) from ActivityLogEntries" + whereTextWithoutPaging); - connection.RunInTransaction(db => + return connection.RunInTransaction(db => { + var list = new List(); + var result = new QueryResult(); + var statements = PrepareAllSafe(db, string.Join(";", statementTexts.ToArray())).ToList(); using (var statement = statements[0]) @@ -153,10 +153,11 @@ namespace Emby.Server.Implementations.Activity result.TotalRecordCount = statement.ExecuteQuery().SelectScalarInt().First(); } - }, ReadTransactionMode); - result.Items = list.ToArray(); - return result; + result.Items = list.ToArray(); + return result; + + }, ReadTransactionMode); } } } diff --git a/Emby.Server.Implementations/Data/BaseSqliteRepository.cs b/Emby.Server.Implementations/Data/BaseSqliteRepository.cs index 9e60a43aab..2fc721f83e 100644 --- a/Emby.Server.Implementations/Data/BaseSqliteRepository.cs +++ b/Emby.Server.Implementations/Data/BaseSqliteRepository.cs @@ -43,6 +43,7 @@ namespace Emby.Server.Implementations.Data //CheckOk(rc); rc = raw.sqlite3_config(raw.SQLITE_CONFIG_MULTITHREAD, 1); + //rc = raw.sqlite3_config(raw.SQLITE_CONFIG_SERIALIZED, 1); //CheckOk(rc); rc = raw.sqlite3_enable_shared_cache(1); @@ -94,6 +95,7 @@ namespace Emby.Server.Implementations.Data var queries = new List { //"PRAGMA cache size=-10000" + //"PRAGMA read_uncommitted = true" }; if (EnableTempStoreMemory) diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs index 42cbf19657..803ebeca03 100644 --- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs @@ -328,6 +328,8 @@ namespace Emby.Server.Implementations.Data "drop table if exists Images", "drop index if exists idx_Images", "drop index if exists idx_TypeSeriesPresentationUniqueKey", + "drop index if exists idx_SeriesPresentationUniqueKey", + "drop index if exists idx_TypeSeriesPresentationUniqueKey2", "create index if not exists idx_PathTypedBaseItems on TypedBaseItems(Path)", "create index if not exists idx_ParentIdTypedBaseItems on TypedBaseItems(ParentId)", @@ -343,8 +345,9 @@ namespace Emby.Server.Implementations.Data // series "create index if not exists idx_TypeSeriesPresentationUniqueKey1 on TypedBaseItems(Type,SeriesPresentationUniqueKey,PresentationUniqueKey,SortName)", - // series next up - "create index if not exists idx_SeriesPresentationUniqueKey on TypedBaseItems(SeriesPresentationUniqueKey)", + // series counts + // seriesdateplayed sort order + "create index if not exists idx_TypeSeriesPresentationUniqueKey3 on TypedBaseItems(SeriesPresentationUniqueKey,Type,IsFolder,IsVirtualItem)", // live tv programs "create index if not exists idx_TypeTopParentIdStartDate on TypedBaseItems(Type,TopParentId,StartDate)", @@ -2079,25 +2082,29 @@ namespace Emby.Server.Implementations.Data throw new ArgumentNullException("id"); } - var list = new List(); - using (WriteLock.Read()) { using (var connection = CreateConnection(true)) { - using (var statement = PrepareStatementSafe(connection, "select StartPositionTicks,Name,ImagePath,ImageDateModified from " + ChaptersTableName + " where ItemId = @ItemId order by ChapterIndex asc")) + return connection.RunInTransaction(db => { - statement.TryBind("@ItemId", id); + var list = new List(); - foreach (var row in statement.ExecuteQuery()) + using (var statement = PrepareStatementSafe(db, "select StartPositionTicks,Name,ImagePath,ImageDateModified from " + ChaptersTableName + " where ItemId = @ItemId order by ChapterIndex asc")) { - list.Add(GetChapter(row)); + statement.TryBind("@ItemId", id); + + foreach (var row in statement.ExecuteQuery()) + { + list.Add(GetChapter(row)); + } } - } + + return list; + + }, ReadTransactionMode); } } - - return list; } /// @@ -2470,32 +2477,33 @@ namespace Emby.Server.Implementations.Data //commandText += GetGroupBy(query); - int count = 0; - using (WriteLock.Read()) { using (var connection = CreateConnection(true)) { - using (var statement = PrepareStatementSafe(connection, commandText)) + return connection.RunInTransaction(db => { - if (EnableJoinUserData(query)) + using (var statement = PrepareStatementSafe(db, commandText)) { - 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); - count = statement.ExecuteQuery().SelectScalarInt().First(); - } + var count = statement.ExecuteQuery().SelectScalarInt().First(); + LogQueryTime("GetCount", commandText, now); + return count; + } + + }, ReadTransactionMode); } - LogQueryTime("GetCount", commandText, now); } - - return count; } public List GetItemList(InternalItemsQuery query) @@ -2511,8 +2519,6 @@ namespace Emby.Server.Implementations.Data var now = DateTime.UtcNow; - var list = new List(); - // Hack for right now since we currently don't support filtering out these duplicates within a query if (query.Limit.HasValue && query.EnableGroupByMetadataKey) { @@ -2553,53 +2559,59 @@ namespace Emby.Server.Implementations.Data { using (var connection = CreateConnection(true)) { - using (var statement = PrepareStatementSafe(connection, commandText)) + return connection.RunInTransaction(db => { - if (EnableJoinUserData(query)) + var list = new List(); + + using (var statement = PrepareStatementSafe(db, commandText)) { - 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()) - { - var item = GetItem(row, query); - if (item != null) + foreach (var row in statement.ExecuteQuery()) { - list.Add(item); + var item = GetItem(row, query); + if (item != null) + { + list.Add(item); + } } } - } - } - LogQueryTime("GetItemList", commandText, now); - } + // Hack for right now since we currently don't support filtering out these duplicates within a query + if (query.EnableGroupByMetadataKey) + { + var limit = query.Limit ?? int.MaxValue; + limit -= 4; + var newList = new List(); - // Hack for right now since we currently don't support filtering out these duplicates within a query - if (query.EnableGroupByMetadataKey) - { - var limit = query.Limit ?? int.MaxValue; - limit -= 4; - var newList = new List(); + foreach (var item in list) + { + AddItem(newList, item); - foreach (var item in list) - { - AddItem(newList, item); + if (newList.Count >= limit) + { + break; + } + } - if (newList.Count >= limit) - { - break; - } - } + list = newList; + } - list = newList; - } + LogQueryTime("GetItemList", commandText, now); - return list; + return list; + + }, ReadTransactionMode); + } + } } private void AddItem(List items, BaseItem newItem) @@ -2637,7 +2649,7 @@ namespace Emby.Server.Implementations.Data var slowThreshold = 1000; #if DEBUG - slowThreshold = 50; + slowThreshold = 2; #endif if (elapsed >= slowThreshold) @@ -2718,7 +2730,6 @@ namespace Emby.Server.Implementations.Data } } - var result = new QueryResult(); var isReturningZeroItems = query.Limit.HasValue && query.Limit <= 0; var statementTexts = new List(); @@ -2748,8 +2759,9 @@ namespace Emby.Server.Implementations.Data { using (var connection = CreateConnection(true)) { - connection.RunInTransaction(db => + return connection.RunInTransaction(db => { + var result = new QueryResult(); var statements = PrepareAllSafe(db, string.Join(";", statementTexts.ToArray())) .ToList(); @@ -2796,12 +2808,12 @@ namespace Emby.Server.Implementations.Data } } - }, ReadTransactionMode); + LogQueryTime("GetItems", commandText, now); - LogQueryTime("GetItems", commandText, now); + result.Items = list.ToArray(); + return result; - result.Items = list.ToArray(); - return result; + }, ReadTransactionMode); } } } @@ -2962,34 +2974,38 @@ namespace Emby.Server.Implementations.Data } } - var list = new List(); - using (WriteLock.Read()) { using (var connection = CreateConnection(true)) { - using (var statement = PrepareStatementSafe(connection, commandText)) + return connection.RunInTransaction(db => { - if (EnableJoinUserData(query)) + var list = new List(); + + using (var statement = PrepareStatementSafe(db, commandText)) { - 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()); + } } - } - } - LogQueryTime("GetItemList", commandText, now); + LogQueryTime("GetItemList", commandText, now); - return list; + return list; + + }, ReadTransactionMode); + } } } @@ -3153,10 +3169,10 @@ namespace Emby.Server.Implementations.Data { using (var connection = CreateConnection(true)) { - var result = new QueryResult(); - - connection.RunInTransaction(db => + return connection.RunInTransaction(db => { + var result = new QueryResult(); + var statements = PrepareAllSafe(db, string.Join(";", statementTexts.ToArray())) .ToList(); @@ -3199,12 +3215,12 @@ namespace Emby.Server.Implementations.Data } } - }, ReadTransactionMode); + LogQueryTime("GetItemIds", commandText, now); - LogQueryTime("GetItemIds", commandText, now); + result.Items = list.ToArray(); + return result; - result.Items = list.ToArray(); - return result; + }, ReadTransactionMode); } } } @@ -4653,13 +4669,13 @@ namespace Emby.Server.Implementations.Data commandText += " order by ListOrder"; - var list = new List(); using (WriteLock.Read()) { using (var connection = CreateConnection(true)) { - connection.RunInTransaction(db => + return connection.RunInTransaction(db => { + var list = new List(); using (var statement = PrepareStatementSafe(db, commandText)) { // Run this again to bind the params @@ -4670,9 +4686,9 @@ namespace Emby.Server.Implementations.Data list.Add(row.GetString(0)); } } + return list; }, ReadTransactionMode); } - return list; } } @@ -4696,14 +4712,14 @@ namespace Emby.Server.Implementations.Data commandText += " order by ListOrder"; - var list = new List(); - using (WriteLock.Read()) { using (var connection = CreateConnection(true)) { - connection.RunInTransaction(db => + return connection.RunInTransaction(db => { + var list = new List(); + using (var statement = PrepareStatementSafe(db, commandText)) { // Run this again to bind the params @@ -4714,11 +4730,11 @@ namespace Emby.Server.Implementations.Data list.Add(GetPerson(row)); } } + + return list; }, ReadTransactionMode); } } - - return list; } private List GetPeopleWhereClauses(InternalPeopleQuery query, IStatement statement) @@ -4899,8 +4915,6 @@ namespace Emby.Server.Implementations.Data ("Type=" + itemValueTypes[0].ToString(CultureInfo.InvariantCulture)) : ("Type in (" + string.Join(",", itemValueTypes.Select(i => i.ToString(CultureInfo.InvariantCulture)).ToArray()) + ")"); - var list = new List(); - var commandText = "Select Value From ItemValues where " + typeClause; if (withItemTypes.Count > 0) @@ -4920,8 +4934,10 @@ namespace Emby.Server.Implementations.Data { using (var connection = CreateConnection(true)) { - connection.RunInTransaction(db => + return connection.RunInTransaction(db => { + var list = new List(); + using (var statement = PrepareStatementSafe(db, commandText)) { foreach (var row in statement.ExecuteQuery()) @@ -4932,12 +4948,13 @@ namespace Emby.Server.Implementations.Data } } } + + LogQueryTime("GetItemValueNames", commandText, now); + + return list; }, ReadTransactionMode); } } - LogQueryTime("GetItemValueNames", commandText, now); - - return list; } private QueryResult> GetItemValues(InternalItemsQuery query, int[] itemValueTypes, string returnType) @@ -5081,9 +5098,6 @@ namespace Emby.Server.Implementations.Data var isReturningZeroItems = query.Limit.HasValue && query.Limit <= 0; - var list = new List>(); - var result = new QueryResult>(); - var statementTexts = new List(); if (!isReturningZeroItems) { @@ -5102,8 +5116,11 @@ namespace Emby.Server.Implementations.Data { using (var connection = CreateConnection(true)) { - connection.RunInTransaction(db => + return connection.RunInTransaction(db => { + var list = new List>(); + var result = new QueryResult>(); + var statements = PrepareAllSafe(db, string.Join(";", statementTexts.ToArray())).ToList(); if (!isReturningZeroItems) @@ -5167,17 +5184,18 @@ namespace Emby.Server.Implementations.Data LogQueryTime("GetItemValues", commandText, now); } } + + if (result.TotalRecordCount == 0) + { + result.TotalRecordCount = list.Count; + } + result.Items = list.ToArray(); + + return result; + }, ReadTransactionMode); } } - - if (result.TotalRecordCount == 0) - { - result.TotalRecordCount = list.Count; - } - result.Items = list.ToArray(); - - return result; } private ItemCounts GetItemCounts(IReadOnlyList reader, int countStartColumn, List typesToCount) @@ -5390,8 +5408,6 @@ namespace Emby.Server.Implementations.Data throw new ArgumentNullException("query"); } - var list = new List(); - var cmdText = "select " + string.Join(",", _mediaStreamSaveColumns) + " from mediastreams where"; cmdText += " ItemId=@ItemId"; @@ -5412,8 +5428,10 @@ namespace Emby.Server.Implementations.Data { using (var connection = CreateConnection(true)) { - connection.RunInTransaction(db => + return connection.RunInTransaction(db => { + var list = new List(); + using (var statement = PrepareStatementSafe(db, cmdText)) { statement.TryBind("@ItemId", query.ItemId.ToGuidParamValue()); @@ -5433,11 +5451,12 @@ namespace Emby.Server.Implementations.Data list.Add(GetMediaStream(row)); } } + + return list; + }, ReadTransactionMode); } } - - return list; } public async Task SaveMediaStreams(Guid id, List streams, CancellationToken cancellationToken) diff --git a/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs b/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs index 7afb5720e9..7767ae892d 100644 --- a/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs @@ -300,9 +300,7 @@ namespace Emby.Server.Implementations.Data { using (var connection = CreateConnection(true)) { - UserItemData result = null; - - connection.RunInTransaction(db => + return connection.RunInTransaction(db => { using (var statement = db.PrepareStatement("select key,userid,rating,played,playCount,isFavorite,playbackPositionTicks,lastPlayedDate,AudioStreamIndex,SubtitleStreamIndex from userdata where key =@Key and userId=@UserId")) { @@ -311,13 +309,13 @@ namespace Emby.Server.Implementations.Data foreach (var row in statement.ExecuteQuery()) { - result = ReadRow(row); - break; + return ReadRow(row); } } - }, ReadTransactionMode); - return result; + return null; + + }, ReadTransactionMode); } } } diff --git a/Emby.Server.Implementations/Dto/DtoService.cs b/Emby.Server.Implementations/Dto/DtoService.cs index 2b2c3e000d..d0c473777d 100644 --- a/Emby.Server.Implementations/Dto/DtoService.cs +++ b/Emby.Server.Implementations/Dto/DtoService.cs @@ -459,12 +459,21 @@ namespace Emby.Server.Implementations.Dto if (dtoOptions.EnableUserData) { - dto.UserData = await _userDataRepository.GetUserDataDto(item, dto, user).ConfigureAwait(false); + dto.UserData = await _userDataRepository.GetUserDataDto(item, dto, user, dtoOptions.Fields).ConfigureAwait(false); } if (!dto.ChildCount.HasValue && item.SourceType == SourceType.Library) { - dto.ChildCount = GetChildCount(folder, user); + // For these types we can try to optimize and assume these values will be equal + if (item is MusicAlbum || item is Season) + { + dto.ChildCount = dto.RecursiveItemCount; + } + + if (dtoOptions.Fields.Contains(ItemFields.ChildCount)) + { + dto.ChildCount = dto.ChildCount ?? GetChildCount(folder, user); + } } if (fields.Contains(ItemFields.CumulativeRunTimeTicks)) @@ -1151,28 +1160,29 @@ namespace Emby.Server.Implementations.Dto { dto.Artists = hasArtist.Artists; - var artistItems = _libraryManager.GetArtists(new InternalItemsQuery - { - EnableTotalRecordCount = false, - ItemIds = new[] { item.Id.ToString("N") } - }); - - dto.ArtistItems = artistItems.Items - .Select(i => - { - var artist = i.Item1; - return new NameIdPair - { - Name = artist.Name, - Id = artist.Id.ToString("N") - }; - }) - .ToList(); + //var artistItems = _libraryManager.GetArtists(new InternalItemsQuery + //{ + // EnableTotalRecordCount = false, + // ItemIds = new[] { item.Id.ToString("N") } + //}); + + //dto.ArtistItems = artistItems.Items + // .Select(i => + // { + // var artist = i.Item1; + // return new NameIdPair + // { + // Name = artist.Name, + // Id = artist.Id.ToString("N") + // }; + // }) + // .ToList(); // Include artists that are not in the database yet, e.g., just added via metadata editor - var foundArtists = artistItems.Items.Select(i => i.Item1.Name).ToList(); + //var foundArtists = artistItems.Items.Select(i => i.Item1.Name).ToList(); + dto.ArtistItems = new List(); dto.ArtistItems.AddRange(hasArtist.Artists - .Except(foundArtists, new DistinctNameComparer()) + //.Except(foundArtists, new DistinctNameComparer()) .Select(i => { // This should not be necessary but we're seeing some cases of it @@ -1201,23 +1211,48 @@ namespace Emby.Server.Implementations.Dto { dto.AlbumArtist = hasAlbumArtist.AlbumArtists.FirstOrDefault(); - var artistItems = _libraryManager.GetAlbumArtists(new InternalItemsQuery - { - EnableTotalRecordCount = false, - ItemIds = new[] { item.Id.ToString("N") } - }); - - dto.AlbumArtists = artistItems.Items + //var artistItems = _libraryManager.GetAlbumArtists(new InternalItemsQuery + //{ + // EnableTotalRecordCount = false, + // ItemIds = new[] { item.Id.ToString("N") } + //}); + + //dto.AlbumArtists = artistItems.Items + // .Select(i => + // { + // var artist = i.Item1; + // return new NameIdPair + // { + // Name = artist.Name, + // Id = artist.Id.ToString("N") + // }; + // }) + // .ToList(); + + dto.AlbumArtists = new List(); + dto.AlbumArtists.AddRange(hasAlbumArtist.AlbumArtists + //.Except(foundArtists, new DistinctNameComparer()) .Select(i => { - var artist = i.Item1; - return new NameIdPair + // This should not be necessary but we're seeing some cases of it + if (string.IsNullOrWhiteSpace(i)) { - Name = artist.Name, - Id = artist.Id.ToString("N") - }; - }) - .ToList(); + return null; + } + + var artist = _libraryManager.GetArtist(i); + if (artist != null) + { + return new NameIdPair + { + Name = artist.Name, + Id = artist.Id.ToString("N") + }; + } + + return null; + + }).Where(i => i != null)); } // Add video info diff --git a/Emby.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs b/Emby.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs index cc2dcb6fd1..5bb21d02ac 100644 --- a/Emby.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs +++ b/Emby.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs @@ -519,6 +519,12 @@ namespace Emby.Server.Implementations.FileOrganization private void PerformFileSorting(TvFileOrganizationOptions options, FileOrganizationResult result) { + // We should probably handle this earlier so that we never even make it this far + if (string.Equals(result.OriginalPath, result.TargetPath, StringComparison.OrdinalIgnoreCase)) + { + return; + } + _libraryMonitor.ReportFileSystemChangeBeginning(result.TargetPath); _fileSystem.CreateDirectory(Path.GetDirectoryName(result.TargetPath)); diff --git a/Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs b/Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs index 94cc383a7a..4606d0e316 100644 --- a/Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs +++ b/Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs @@ -76,7 +76,8 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp private void ProcessContext(HttpListenerContext context) { - Task.Factory.StartNew(() => InitTask(context)); + //Task.Factory.StartNew(() => InitTask(context), TaskCreationOptions.DenyChildAttach | TaskCreationOptions.PreferFairness); + Task.Run(() => InitTask(context)); } private Task InitTask(HttpListenerContext context) diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index ad91988e53..1ff61286f9 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -817,7 +817,31 @@ namespace Emby.Server.Implementations.Library return _userRootFolder; } - + + public Guid? FindIdByPath(string path, bool? isFolder) + { + // If this returns multiple items it could be tricky figuring out which one is correct. + // In most cases, the newest one will be and the others obsolete but not yet cleaned up + + var query = new InternalItemsQuery + { + Path = path, + IsFolder = isFolder, + SortBy = new[] { ItemSortBy.DateCreated }, + SortOrder = SortOrder.Descending, + Limit = 1 + }; + + var id = GetItemIds(query); + + if (id.Count == 0) + { + return null; + } + + return id[0]; + } + public BaseItem FindByPath(string path, bool? isFolder) { // If this returns multiple items it could be tricky figuring out which one is correct. @@ -1430,7 +1454,7 @@ namespace Emby.Server.Implementations.Library })) { // Optimize by querying against top level views - query.TopParentIds = parents.SelectMany(i => GetTopParentsForQuery(i, query.User)).Select(i => i.Id.ToString("N")).ToArray(); + query.TopParentIds = parents.SelectMany(i => GetTopParentIdsForQuery(i, query.User)).Select(i => i.ToString("N")).ToArray(); query.AncestorIds = new string[] { }; } } @@ -1489,7 +1513,7 @@ namespace Emby.Server.Implementations.Library })) { // Optimize by querying against top level views - query.TopParentIds = parents.SelectMany(i => GetTopParentsForQuery(i, query.User)).Select(i => i.Id.ToString("N")).ToArray(); + query.TopParentIds = parents.SelectMany(i => GetTopParentIdsForQuery(i, query.User)).Select(i => i.ToString("N")).ToArray(); } else { @@ -1515,11 +1539,11 @@ namespace Emby.Server.Implementations.Library }, CancellationToken.None).Result.ToList(); - query.TopParentIds = userViews.SelectMany(i => GetTopParentsForQuery(i, user)).Select(i => i.Id.ToString("N")).ToArray(); + query.TopParentIds = userViews.SelectMany(i => GetTopParentIdsForQuery(i, user)).Select(i => i.ToString("N")).ToArray(); } } - private IEnumerable GetTopParentsForQuery(BaseItem item, User user) + private IEnumerable GetTopParentIdsForQuery(BaseItem item, User user) { var view = item as UserView; @@ -1527,7 +1551,7 @@ namespace Emby.Server.Implementations.Library { if (string.Equals(view.ViewType, CollectionType.LiveTv)) { - return new[] { view }; + return new[] { view.Id }; } if (string.Equals(view.ViewType, CollectionType.Channels)) { @@ -1537,7 +1561,7 @@ namespace Emby.Server.Implementations.Library }, CancellationToken.None).Result; - return channelResult.Items; + return channelResult.Items.Select(i => i.Id); } // Translate view into folders @@ -1546,18 +1570,18 @@ namespace Emby.Server.Implementations.Library var displayParent = GetItemById(view.DisplayParentId); if (displayParent != null) { - return GetTopParentsForQuery(displayParent, user); + return GetTopParentIdsForQuery(displayParent, user); } - return new BaseItem[] { }; + return new Guid[] { }; } if (view.ParentId != Guid.Empty) { var displayParent = GetItemById(view.ParentId); if (displayParent != null) { - return GetTopParentsForQuery(displayParent, user); + return GetTopParentIdsForQuery(displayParent, user); } - return new BaseItem[] { }; + return new Guid[] { }; } // Handle grouping @@ -1568,23 +1592,23 @@ namespace Emby.Server.Implementations.Library .OfType() .Where(i => string.IsNullOrWhiteSpace(i.CollectionType) || string.Equals(i.CollectionType, view.ViewType, StringComparison.OrdinalIgnoreCase)) .Where(i => user.IsFolderGrouped(i.Id)) - .SelectMany(i => GetTopParentsForQuery(i, user)); + .SelectMany(i => GetTopParentIdsForQuery(i, user)); } - return new BaseItem[] { }; + return new Guid[] { }; } var collectionFolder = item as CollectionFolder; if (collectionFolder != null) { - return collectionFolder.GetPhysicalParents(); + return collectionFolder.PhysicalFolderIds; } - + var topParent = item.GetTopParent(); if (topParent != null) { - return new[] { topParent }; + return new[] { topParent.Id }; } - return new BaseItem[] { }; + return new Guid[] { }; } /// diff --git a/Emby.Server.Implementations/Library/UserDataManager.cs b/Emby.Server.Implementations/Library/UserDataManager.cs index f4a30fc00b..5a14edf135 100644 --- a/Emby.Server.Implementations/Library/UserDataManager.cs +++ b/Emby.Server.Implementations/Library/UserDataManager.cs @@ -12,6 +12,7 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; +using MediaBrowser.Model.Querying; namespace Emby.Server.Implementations.Library { @@ -186,16 +187,16 @@ namespace Emby.Server.Implementations.Library var userData = GetUserData(user.Id, item); var dto = GetUserItemDataDto(userData); - await item.FillUserDataDtoValues(dto, userData, null, user).ConfigureAwait(false); + await item.FillUserDataDtoValues(dto, userData, null, user, new List()).ConfigureAwait(false); return dto; } - public async Task GetUserDataDto(IHasUserData item, BaseItemDto itemDto, User user) + public async Task GetUserDataDto(IHasUserData item, BaseItemDto itemDto, User user, List fields) { var userData = GetUserData(user.Id, item); var dto = GetUserItemDataDto(userData); - await item.FillUserDataDtoValues(dto, userData, itemDto, user).ConfigureAwait(false); + await item.FillUserDataDtoValues(dto, userData, itemDto, user, fields).ConfigureAwait(false); return dto; } diff --git a/Emby.Server.Implementations/Notifications/SqliteNotificationsRepository.cs b/Emby.Server.Implementations/Notifications/SqliteNotificationsRepository.cs index 43e19da65a..f18278cb25 100644 --- a/Emby.Server.Implementations/Notifications/SqliteNotificationsRepository.cs +++ b/Emby.Server.Implementations/Notifications/SqliteNotificationsRepository.cs @@ -65,9 +65,9 @@ namespace Emby.Server.Implementations.Notifications var whereClause = " where " + string.Join(" And ", clauses.ToArray()); - using (var connection = CreateConnection(true)) + using (WriteLock.Read()) { - lock (WriteLock) + using (var connection = CreateConnection(true)) { result.TotalRecordCount = connection.Query("select count(Id) from Notifications" + whereClause, paramList.ToArray()).SelectScalarInt().First(); @@ -106,9 +106,9 @@ namespace Emby.Server.Implementations.Notifications { var result = new NotificationsSummary(); - using (var connection = CreateConnection(true)) + using (WriteLock.Read()) { - lock (WriteLock) + using (var connection = CreateConnection(true)) { using (var statement = connection.PrepareStatement("select Level from Notifications where UserId=@UserId and IsRead=@IsRead")) { @@ -223,9 +223,9 @@ namespace Emby.Server.Implementations.Notifications cancellationToken.ThrowIfCancellationRequested(); - using (var connection = CreateConnection()) + lock (WriteLock) { - lock (WriteLock) + using (var connection = CreateConnection()) { connection.RunInTransaction(conn => { @@ -286,9 +286,9 @@ namespace Emby.Server.Implementations.Notifications { cancellationToken.ThrowIfCancellationRequested(); - using (var connection = CreateConnection()) + using (WriteLock.Write()) { - lock (WriteLock) + using (var connection = CreateConnection()) { connection.RunInTransaction(conn => { @@ -308,9 +308,9 @@ namespace Emby.Server.Implementations.Notifications { cancellationToken.ThrowIfCancellationRequested(); - using (var connection = CreateConnection()) + using (WriteLock.Write()) { - lock (WriteLock) + using (var connection = CreateConnection()) { connection.RunInTransaction(conn => { diff --git a/Emby.Server.Implementations/Security/AuthenticationRepository.cs b/Emby.Server.Implementations/Security/AuthenticationRepository.cs index 392db69353..7199f4f4d6 100644 --- a/Emby.Server.Implementations/Security/AuthenticationRepository.cs +++ b/Emby.Server.Implementations/Security/AuthenticationRepository.cs @@ -206,10 +206,10 @@ namespace Emby.Server.Implementations.Security { using (var connection = CreateConnection(true)) { - var result = new QueryResult(); - - connection.RunInTransaction(db => + return connection.RunInTransaction(db => { + var result = new QueryResult(); + var statementTexts = new List(); statementTexts.Add(commandText); statementTexts.Add("select count (Id) from AccessTokens" + whereTextWithoutPaging); @@ -236,10 +236,10 @@ namespace Emby.Server.Implementations.Security } } - }, ReadTransactionMode); + result.Items = list.ToArray(); + return result; - result.Items = list.ToArray(); - return result; + }, ReadTransactionMode); } } } diff --git a/MediaBrowser.Api/BaseApiService.cs b/MediaBrowser.Api/BaseApiService.cs index 73a2bedb9a..7a8951396a 100644 --- a/MediaBrowser.Api/BaseApiService.cs +++ b/MediaBrowser.Api/BaseApiService.cs @@ -121,7 +121,9 @@ namespace MediaBrowser.Api { var options = new DtoOptions(); - options.DeviceId = authContext.GetAuthorizationInfo(Request).DeviceId; + var authInfo = authContext.GetAuthorizationInfo(Request); + + options.DeviceId = authInfo.DeviceId; var hasFields = request as IHasItemFields; if (hasFields != null) @@ -129,6 +131,34 @@ namespace MediaBrowser.Api options.Fields = hasFields.GetItemFields().ToList(); } + var client = authInfo.Client ?? string.Empty; + if (client.IndexOf("kodi", StringComparison.OrdinalIgnoreCase) != -1 || + client.IndexOf("wmc", StringComparison.OrdinalIgnoreCase) != -1 || + client.IndexOf("media center", StringComparison.OrdinalIgnoreCase) != -1 || + client.IndexOf("classic", StringComparison.OrdinalIgnoreCase) != -1) + { + options.Fields.Add(Model.Querying.ItemFields.RecursiveItemCount); + } + + if (client.IndexOf("kodi", StringComparison.OrdinalIgnoreCase) != -1 || + client.IndexOf("wmc", StringComparison.OrdinalIgnoreCase) != -1 || + client.IndexOf("media center", StringComparison.OrdinalIgnoreCase) != -1 || + client.IndexOf("classic", StringComparison.OrdinalIgnoreCase) != -1 || + client.IndexOf("roku", StringComparison.OrdinalIgnoreCase) != -1 || + client.IndexOf("samsung", StringComparison.OrdinalIgnoreCase) != -1) + { + options.Fields.Add(Model.Querying.ItemFields.ChildCount); + } + + if (client.IndexOf("web", StringComparison.OrdinalIgnoreCase) == -1 && + client.IndexOf("mobile", StringComparison.OrdinalIgnoreCase) == -1 && + client.IndexOf("ios", StringComparison.OrdinalIgnoreCase) == -1 && + client.IndexOf("android", StringComparison.OrdinalIgnoreCase) == -1 && + client.IndexOf("theater", StringComparison.OrdinalIgnoreCase) == -1) + { + options.Fields.Add(Model.Querying.ItemFields.ChildCount); + } + var hasDtoOptions = request as IHasDtoOptions; if (hasDtoOptions != null) { diff --git a/MediaBrowser.Api/ItemLookupService.cs b/MediaBrowser.Api/ItemLookupService.cs index 0ae1fbff41..b5c51bfef0 100644 --- a/MediaBrowser.Api/ItemLookupService.cs +++ b/MediaBrowser.Api/ItemLookupService.cs @@ -14,8 +14,6 @@ using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Common.IO; -using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; using MediaBrowser.Model.Serialization; using MediaBrowser.Model.Services; @@ -88,6 +86,12 @@ namespace MediaBrowser.Api { } + [Route("/Items/RemoteSearch/Book", "POST")] + [Authenticated] + public class GetBookRemoteSearchResults : RemoteSearchQuery, IReturn> + { + } + [Route("/Items/RemoteSearch/Image", "GET", Summary = "Gets a remote image")] public class GetRemoteSearchImage { @@ -147,6 +151,13 @@ namespace MediaBrowser.Api return ToOptimizedResult(result); } + public async Task Post(GetBookRemoteSearchResults request) + { + var result = await _providerManager.GetRemoteSearchResults(request, CancellationToken.None).ConfigureAwait(false); + + return ToOptimizedResult(result); + } + public async Task Post(GetMovieRemoteSearchResults request) { var result = await _providerManager.GetRemoteSearchResults(request, CancellationToken.None).ConfigureAwait(false); diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index 9f45034665..2aa53d6515 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -30,6 +30,7 @@ using MediaBrowser.Model.Globalization; using MediaBrowser.Model.IO; using MediaBrowser.Model.LiveTv; using MediaBrowser.Model.Providers; +using MediaBrowser.Model.Querying; using MediaBrowser.Model.Serialization; namespace MediaBrowser.Controller.Entities @@ -2191,7 +2192,7 @@ namespace MediaBrowser.Controller.Entities return path; } - public virtual Task FillUserDataDtoValues(UserItemDataDto dto, UserItemData userData, BaseItemDto itemDto, User user) + public virtual Task FillUserDataDtoValues(UserItemDataDto dto, UserItemData userData, BaseItemDto itemDto, User user, List itemFields) { if (RunTimeTicks.HasValue) { diff --git a/MediaBrowser.Controller/Entities/CollectionFolder.cs b/MediaBrowser.Controller/Entities/CollectionFolder.cs index ebc55ca8a0..c505aefb3f 100644 --- a/MediaBrowser.Controller/Entities/CollectionFolder.cs +++ b/MediaBrowser.Controller/Entities/CollectionFolder.cs @@ -27,6 +27,7 @@ namespace MediaBrowser.Controller.Entities public CollectionFolder() { PhysicalLocationsList = new List(); + PhysicalFolderIds = new List(); } [IgnoreDataMember] @@ -153,6 +154,7 @@ namespace MediaBrowser.Controller.Entities } public List PhysicalLocationsList { get; set; } + public List PhysicalFolderIds { get; set; } protected override IEnumerable GetFileSystemChildren(IDirectoryService directoryService) { @@ -176,6 +178,18 @@ namespace MediaBrowser.Controller.Entities } } + if (!changed) + { + var folderIds = PhysicalFolderIds.ToList(); + + var newFolderIds = GetPhysicalFolders(false).Select(i => i.Id).ToList(); + + if (!folderIds.SequenceEqual(newFolderIds)) + { + changed = true; + } + } + return changed; } @@ -186,6 +200,31 @@ namespace MediaBrowser.Controller.Entities return changed; } + protected override bool RefreshLinkedChildren(IEnumerable fileSystemChildren) + { + var physicalFolders = GetPhysicalFolders(false) + .ToList(); + + var linkedChildren = physicalFolders + .SelectMany(c => c.LinkedChildren) + .ToList(); + + var changed = !linkedChildren.SequenceEqual(LinkedChildren, new LinkedChildComparer()); + + LinkedChildren = linkedChildren; + + var folderIds = PhysicalFolderIds.ToList(); + var newFolderIds = physicalFolders.Select(i => i.Id).ToList(); + + if (!folderIds.SequenceEqual(newFolderIds)) + { + changed = true; + PhysicalFolderIds = newFolderIds.ToList(); + } + + return changed; + } + internal override bool IsValidFromResolver(BaseItem newItem) { var newCollectionFolder = newItem as CollectionFolder; @@ -260,26 +299,6 @@ namespace MediaBrowser.Controller.Entities return Task.FromResult(true); } - /// - /// Our children are actually just references to the ones in the physical root... - /// - /// The linked children. - [IgnoreDataMember] - public override List LinkedChildren - { - get { return GetLinkedChildrenInternal(); } - set - { - base.LinkedChildren = value; - } - } - private List GetLinkedChildrenInternal() - { - return GetPhysicalParents() - .SelectMany(c => c.LinkedChildren) - .ToList(); - } - /// /// Our children are actually just references to the ones in the physical root... /// @@ -292,11 +311,16 @@ namespace MediaBrowser.Controller.Entities private IEnumerable GetActualChildren() { - return GetPhysicalParents().SelectMany(c => c.Children); + return GetPhysicalFolders(true).SelectMany(c => c.Children); } - public IEnumerable GetPhysicalParents() + private IEnumerable GetPhysicalFolders(bool enableCache) { + if (enableCache) + { + return PhysicalFolderIds.Select(i => LibraryManager.GetItemById(i)).OfType(); + } + var rootChildren = LibraryManager.RootFolder.Children .OfType() .ToList(); diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index 4705f03fa0..a84e9a5d23 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -1222,7 +1222,7 @@ namespace MediaBrowser.Controller.Entities /// Refreshes the linked children. /// /// true if XXXX, false otherwise - private bool RefreshLinkedChildren(IEnumerable fileSystemChildren) + protected virtual bool RefreshLinkedChildren(IEnumerable fileSystemChildren) { var currentManualLinks = LinkedChildren.Where(i => i.Type == LinkedChildType.Manual).ToList(); var currentShortcutLinks = LinkedChildren.Where(i => i.Type == LinkedChildType.Shortcut).ToList(); @@ -1410,23 +1410,24 @@ namespace MediaBrowser.Controller.Entities } } - public override async Task FillUserDataDtoValues(UserItemDataDto dto, UserItemData userData, BaseItemDto itemDto, User user) + public override async Task FillUserDataDtoValues(UserItemDataDto dto, UserItemData userData, BaseItemDto itemDto, User user, List itemFields) { if (!SupportsUserDataFromChildren) { return; } - var recursiveItemCount = GetRecursiveChildCount(user); - if (itemDto != null) { - itemDto.RecursiveItemCount = recursiveItemCount; + if (itemFields.Contains(ItemFields.RecursiveItemCount)) + { + itemDto.RecursiveItemCount = GetRecursiveChildCount(user); + } } - if (recursiveItemCount > 0 && SupportsPlayedStatus) + if (SupportsPlayedStatus) { - var unplayedQueryResult = recursiveItemCount > 0 ? await GetItems(new InternalItemsQuery(user) + var unplayedQueryResult = await GetItems(new InternalItemsQuery(user) { Recursive = true, IsFolder = false, @@ -1435,21 +1436,24 @@ namespace MediaBrowser.Controller.Entities Limit = 0, IsPlayed = false - }).ConfigureAwait(false) : new QueryResult(); + }).ConfigureAwait(false); double unplayedCount = unplayedQueryResult.TotalRecordCount; - var unplayedPercentage = (unplayedCount / recursiveItemCount) * 100; - dto.PlayedPercentage = 100 - unplayedPercentage; - dto.Played = dto.PlayedPercentage.Value >= 100; dto.UnplayedItemCount = unplayedQueryResult.TotalRecordCount; - } - if (itemDto != null) - { - if (this is Season || this is MusicAlbum) + if (itemDto != null && itemDto.RecursiveItemCount.HasValue) + { + if (itemDto.RecursiveItemCount.Value > 0) + { + var unplayedPercentage = (unplayedCount/itemDto.RecursiveItemCount.Value)*100; + dto.PlayedPercentage = 100 - unplayedPercentage; + dto.Played = dto.PlayedPercentage.Value >= 100; + } + } + else { - itemDto.ChildCount = recursiveItemCount; + dto.Played = (dto.UnplayedItemCount ?? 0) == 0; } } } diff --git a/MediaBrowser.Controller/Entities/IHasUserData.cs b/MediaBrowser.Controller/Entities/IHasUserData.cs index c21e170ae7..0b3b7dc8d9 100644 --- a/MediaBrowser.Controller/Entities/IHasUserData.cs +++ b/MediaBrowser.Controller/Entities/IHasUserData.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using System.Threading.Tasks; using MediaBrowser.Model.Dto; +using MediaBrowser.Model.Querying; namespace MediaBrowser.Controller.Entities { @@ -14,10 +15,7 @@ namespace MediaBrowser.Controller.Entities /// /// Fills the user data dto values. /// - /// The dto. - /// The user data. - /// The user. - Task FillUserDataDtoValues(UserItemDataDto dto, UserItemData userData, BaseItemDto itemDto, User user); + Task FillUserDataDtoValues(UserItemDataDto dto, UserItemData userData, BaseItemDto itemDto, User user, List fields); bool EnableRememberingTrackSelections { get; } diff --git a/MediaBrowser.Controller/Library/ILibraryManager.cs b/MediaBrowser.Controller/Library/ILibraryManager.cs index d297fd0065..bf9a076264 100644 --- a/MediaBrowser.Controller/Library/ILibraryManager.cs +++ b/MediaBrowser.Controller/Library/ILibraryManager.cs @@ -62,6 +62,8 @@ namespace MediaBrowser.Controller.Library /// BaseItem. BaseItem FindByPath(string path, bool? isFolder); + Guid? FindIdByPath(string path, bool? isFolder); + /// /// Gets the artist. /// diff --git a/MediaBrowser.Controller/Library/IUserDataManager.cs b/MediaBrowser.Controller/Library/IUserDataManager.cs index 86c52c4c31..5940c7e292 100644 --- a/MediaBrowser.Controller/Library/IUserDataManager.cs +++ b/MediaBrowser.Controller/Library/IUserDataManager.cs @@ -5,6 +5,7 @@ using MediaBrowser.Model.Entities; using System; using System.Threading; using System.Threading.Tasks; +using MediaBrowser.Model.Querying; namespace MediaBrowser.Controller.Library { @@ -37,12 +38,9 @@ namespace MediaBrowser.Controller.Library /// /// Gets the user data dto. /// - /// The item. - /// The user. - /// UserItemDataDto. Task GetUserDataDto(IHasUserData item, User user); - Task GetUserDataDto(IHasUserData item, BaseItemDto itemDto, User user); + Task GetUserDataDto(IHasUserData item, BaseItemDto itemDto, User user, List fields); /// /// Get all user data for the given user diff --git a/MediaBrowser.Model/Querying/ItemFields.cs b/MediaBrowser.Model/Querying/ItemFields.cs index bf1d4991cf..e36abf16ed 100644 --- a/MediaBrowser.Model/Querying/ItemFields.cs +++ b/MediaBrowser.Model/Querying/ItemFields.cs @@ -171,6 +171,8 @@ /// PrimaryImageAspectRatio, + RecursiveItemCount, + /// /// The revenue /// diff --git a/RSSDP/SsdpDevicePublisherBase.cs b/RSSDP/SsdpDevicePublisherBase.cs index 260c008960..8ab35d6616 100644 --- a/RSSDP/SsdpDevicePublisherBase.cs +++ b/RSSDP/SsdpDevicePublisherBase.cs @@ -291,7 +291,7 @@ namespace Rssdp.Infrastructure if (devices != null) { var deviceList = devices.ToList(); - WriteTrace(String.Format("Sending {0} search responses", deviceList.Count)); + //WriteTrace(String.Format("Sending {0} search responses", deviceList.Count)); foreach (var device in deviceList) { @@ -300,7 +300,7 @@ namespace Rssdp.Infrastructure } else { - WriteTrace(String.Format("Sending 0 search responses.")); + //WriteTrace(String.Format("Sending 0 search responses.")); } }); } @@ -413,7 +413,7 @@ namespace Rssdp.Infrastructure //DisposeRebroadcastTimer(); - WriteTrace("Begin Sending Alive Notifications For All Devices"); + //WriteTrace("Begin Sending Alive Notifications For All Devices"); _LastNotificationTime = DateTime.Now; @@ -430,7 +430,7 @@ namespace Rssdp.Infrastructure SendAliveNotifications(device, true); } - WriteTrace("Completed Sending Alive Notifications For All Devices"); + //WriteTrace("Completed Sending Alive Notifications For All Devices"); } catch (ObjectDisposedException ex) { -- cgit v1.2.3