diff options
| author | Techywarrior <techywarrior@gmail.com> | 2013-04-02 13:07:55 -0700 |
|---|---|---|
| committer | Techywarrior <techywarrior@gmail.com> | 2013-04-02 13:07:55 -0700 |
| commit | 713afcf6755b15142244cad6b16f8d539bd12893 (patch) | |
| tree | d5d7479281f85fc47d24d8c95a2ce29a3a146d8b | |
| parent | c957f202cc1fefb174377b99495b329a6cb9ee72 (diff) | |
| parent | e2562879d86aafc1063e37bfd353c22309e8e237 (diff) | |
Merge branch 'master' of https://github.com/MediaBrowser/MediaBrowser
23 files changed, 408 insertions, 433 deletions
diff --git a/MediaBrowser.Api/Library/LibraryService.cs b/MediaBrowser.Api/Library/LibraryService.cs index f2867b595..9c68df771 100644 --- a/MediaBrowser.Api/Library/LibraryService.cs +++ b/MediaBrowser.Api/Library/LibraryService.cs @@ -104,13 +104,16 @@ namespace MediaBrowser.Api.Library /// </summary> private readonly IApplicationHost _appHost; private readonly ILibraryManager _libraryManager; + private readonly IUserManager _userManager; /// <summary> /// Initializes a new instance of the <see cref="LibraryService" /> class. /// </summary> /// <param name="appHost">The app host.</param> + /// <param name="libraryManager">The library manager.</param> + /// <param name="userManager">The user manager.</param> /// <exception cref="System.ArgumentNullException">appHost</exception> - public LibraryService(IApplicationHost appHost, ILibraryManager libraryManager) + public LibraryService(IApplicationHost appHost, ILibraryManager libraryManager, IUserManager userManager) { if (appHost == null) { @@ -119,6 +122,7 @@ namespace MediaBrowser.Api.Library _appHost = appHost; _libraryManager = libraryManager; + _userManager = userManager; } /// <summary> @@ -133,7 +137,7 @@ namespace MediaBrowser.Api.Library // Get everything var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true)); - var result = new DtoBuilder(Logger, _libraryManager).GetBaseItemDto(item, fields.ToList()).Result; + var result = new DtoBuilder(Logger, _libraryManager, _userManager).GetBaseItemDto(item, fields.ToList()).Result; return ToOptimizedResult(result); } @@ -150,7 +154,7 @@ namespace MediaBrowser.Api.Library // Get everything var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true)); - var result = new DtoBuilder(Logger, _libraryManager).GetBaseItemDto(item, fields.ToList()).Result; + var result = new DtoBuilder(Logger, _libraryManager, _userManager).GetBaseItemDto(item, fields.ToList()).Result; return ToOptimizedResult(result); } @@ -167,7 +171,7 @@ namespace MediaBrowser.Api.Library // Get everything var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true)); - var result = new DtoBuilder(Logger, _libraryManager).GetBaseItemDto(item, fields.ToList()).Result; + var result = new DtoBuilder(Logger, _libraryManager, _userManager).GetBaseItemDto(item, fields.ToList()).Result; return ToOptimizedResult(result); } @@ -184,7 +188,7 @@ namespace MediaBrowser.Api.Library // Get everything var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true)); - var result = new DtoBuilder(Logger, _libraryManager).GetBaseItemDto(item, fields.ToList()).Result; + var result = new DtoBuilder(Logger, _libraryManager, _userManager).GetBaseItemDto(item, fields.ToList()).Result; return ToOptimizedResult(result); } diff --git a/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs b/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs index 8dc9cfd62..a0ad1fb2a 100644 --- a/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs +++ b/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs @@ -149,7 +149,7 @@ namespace MediaBrowser.Api.UserLibrary return null; } - var dto = await new DtoBuilder(Logger, LibraryManager).GetBaseItemDto(item, user, fields).ConfigureAwait(false); + var dto = await new DtoBuilder(Logger, LibraryManager, UserManager).GetBaseItemDto(item, user, fields).ConfigureAwait(false); dto.ChildCount = stub.Item2(); diff --git a/MediaBrowser.Api/UserLibrary/ItemsService.cs b/MediaBrowser.Api/UserLibrary/ItemsService.cs index 77b991a54..a74516fa2 100644 --- a/MediaBrowser.Api/UserLibrary/ItemsService.cs +++ b/MediaBrowser.Api/UserLibrary/ItemsService.cs @@ -179,7 +179,7 @@ namespace MediaBrowser.Api.UserLibrary var fields = GetItemFields(request).ToList(); - var dtoBuilder = new DtoBuilder(Logger, _libraryManager); + var dtoBuilder = new DtoBuilder(Logger, _libraryManager, _userManager); var returnItems = await Task.WhenAll(pagedItems.Select(i => dtoBuilder.GetBaseItemDto(i, user, fields))).ConfigureAwait(false); @@ -241,12 +241,15 @@ namespace MediaBrowser.Api.UserLibrary /// <returns>IEnumerable{BaseItem}.</returns> private IEnumerable<BaseItem> ApplyFilter(IEnumerable<BaseItem> items, ItemFilter filter, User user) { + // Avoids implicitly captured closure + var currentUser = user; + switch (filter) { case ItemFilter.Likes: return items.Where(item => { - var userdata = item.GetUserData(user, false); + var userdata = _userManager.GetUserData(user.Id, item.UserDataId).Result; return userdata != null && userdata.Likes.HasValue && userdata.Likes.Value; }); @@ -254,7 +257,7 @@ namespace MediaBrowser.Api.UserLibrary case ItemFilter.Dislikes: return items.Where(item => { - var userdata = item.GetUserData(user, false); + var userdata = _userManager.GetUserData(user.Id, item.UserDataId).Result; return userdata != null && userdata.Likes.HasValue && !userdata.Likes.Value; }); @@ -262,18 +265,18 @@ namespace MediaBrowser.Api.UserLibrary case ItemFilter.IsFavorite: return items.Where(item => { - var userdata = item.GetUserData(user, false); + var userdata = _userManager.GetUserData(user.Id, item.UserDataId).Result; return userdata != null && userdata.IsFavorite; }); case ItemFilter.IsRecentlyAdded: - return items.Where(item => item.IsRecentlyAdded(user)); + return items.Where(item => item.IsRecentlyAdded(currentUser)); case ItemFilter.IsResumable: return items.Where(item => { - var userdata = item.GetUserData(user, false); + var userdata = _userManager.GetUserData(user.Id, item.UserDataId).Result; return userdata != null && userdata.PlaybackPositionTicks > 0; }); @@ -281,7 +284,7 @@ namespace MediaBrowser.Api.UserLibrary case ItemFilter.IsPlayed: return items.Where(item => { - var userdata = item.GetUserData(user, false); + var userdata = _userManager.GetUserData(user.Id, item.UserDataId).Result; return userdata != null && userdata.PlayCount > 0; }); @@ -289,7 +292,7 @@ namespace MediaBrowser.Api.UserLibrary case ItemFilter.IsUnplayed: return items.Where(item => { - var userdata = item.GetUserData(user, false); + var userdata = _userManager.GetUserData(user.Id, item.UserDataId).Result; return userdata == null || userdata.PlayCount == 0; }); diff --git a/MediaBrowser.Api/UserLibrary/UserLibraryService.cs b/MediaBrowser.Api/UserLibrary/UserLibraryService.cs index 5c9c8e1f3..d1f963a9e 100644 --- a/MediaBrowser.Api/UserLibrary/UserLibraryService.cs +++ b/MediaBrowser.Api/UserLibrary/UserLibraryService.cs @@ -1,4 +1,5 @@ -using MediaBrowser.Controller.Entities; +using System.Threading; +using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Library; using MediaBrowser.Model.Connectivity; @@ -385,7 +386,7 @@ namespace MediaBrowser.Api.UserLibrary var movie = (Movie)item; - var dtoBuilder = new DtoBuilder(Logger, _libraryManager); + var dtoBuilder = new DtoBuilder(Logger, _libraryManager, _userManager); var items = movie.SpecialFeatures.Select(i => dtoBuilder.GetBaseItemDto(i, user, fields)).AsParallel().Select(t => t.Result).ToList(); @@ -406,7 +407,7 @@ namespace MediaBrowser.Api.UserLibrary // Get everything var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true)).ToList(); - var dtoBuilder = new DtoBuilder(Logger, _libraryManager); + var dtoBuilder = new DtoBuilder(Logger, _libraryManager, _userManager); var items = item.LocalTrailers.Select(i => dtoBuilder.GetBaseItemDto(i, user, fields)).AsParallel().Select(t => t.Result).ToList(); @@ -427,7 +428,7 @@ namespace MediaBrowser.Api.UserLibrary // Get everything var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true)).ToList(); - var dtoBuilder = new DtoBuilder(Logger, _libraryManager); + var dtoBuilder = new DtoBuilder(Logger, _libraryManager, _userManager); var result = dtoBuilder.GetBaseItemDto(item, user, fields).Result; @@ -443,7 +444,7 @@ namespace MediaBrowser.Api.UserLibrary // Get everything var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true)).ToList(); - var dtoBuilder = new DtoBuilder(Logger, _libraryManager); + var dtoBuilder = new DtoBuilder(Logger, _libraryManager, _userManager); var result = dtoBuilder.GetBaseItemDto(item, user, fields).Result; @@ -486,7 +487,7 @@ namespace MediaBrowser.Api.UserLibrary // Serialize to json and then back so that the core doesn't see the request dto type var displayPreferences = _jsonSerializer.DeserializeFromString<DisplayPreferences>(_jsonSerializer.SerializeToString(request)); - var task = _libraryManager.SaveDisplayPreferencesForFolder(user, folder, displayPreferences); + var task = _userManager.SaveDisplayPreferences(user.Id, folder.DisplayPreferencesId, displayPreferences, CancellationToken.None); Task.WaitAll(task); } @@ -502,12 +503,12 @@ namespace MediaBrowser.Api.UserLibrary var item = string.IsNullOrEmpty(request.Id) ? user.RootFolder : DtoBuilder.GetItemByClientId(request.Id, _userManager, _libraryManager, user.Id); // Get the user data for this item - var data = item.GetUserData(user, true); + var data = _userManager.GetUserData(user.Id, item.UserDataId).Result; // Set favorite status data.IsFavorite = true; - var task = _userManager.SaveUserDataForItem(user, item, data); + var task = _userManager.SaveUserData(user.Id, item.UserDataId, data, CancellationToken.None); Task.WaitAll(task); } @@ -523,12 +524,12 @@ namespace MediaBrowser.Api.UserLibrary var item = string.IsNullOrEmpty(request.Id) ? user.RootFolder : DtoBuilder.GetItemByClientId(request.Id, _userManager, _libraryManager, user.Id); // Get the user data for this item - var data = item.GetUserData(user, true); + var data = _userManager.GetUserData(user.Id, item.UserDataId).Result; // Set favorite status data.IsFavorite = false; - var task = _userManager.SaveUserDataForItem(user, item, data); + var task = _userManager.SaveUserData(user.Id, item.UserDataId, data, CancellationToken.None); Task.WaitAll(task); } @@ -544,11 +545,11 @@ namespace MediaBrowser.Api.UserLibrary var item = string.IsNullOrEmpty(request.Id) ? user.RootFolder : DtoBuilder.GetItemByClientId(request.Id, _userManager, _libraryManager, user.Id); // Get the user data for this item - var data = item.GetUserData(user, true); + var data = _userManager.GetUserData(user.Id, item.UserDataId).Result; data.Rating = null; - var task = _userManager.SaveUserDataForItem(user, item, data); + var task = _userManager.SaveUserData(user.Id, item.UserDataId, data, CancellationToken.None); Task.WaitAll(task); } @@ -564,11 +565,11 @@ namespace MediaBrowser.Api.UserLibrary var item = string.IsNullOrEmpty(request.Id) ? user.RootFolder : DtoBuilder.GetItemByClientId(request.Id, _userManager, _libraryManager, user.Id); // Get the user data for this item - var data = item.GetUserData(user, true); + var data = _userManager.GetUserData(user.Id, item.UserDataId).Result; data.Likes = request.Likes; - var task = _userManager.SaveUserDataForItem(user, item, data); + var task = _userManager.SaveUserData(user.Id, item.UserDataId, data, CancellationToken.None); Task.WaitAll(task); } diff --git a/MediaBrowser.Api/UserService.cs b/MediaBrowser.Api/UserService.cs index b495d07f9..f2a9ca24b 100644 --- a/MediaBrowser.Api/UserService.cs +++ b/MediaBrowser.Api/UserService.cs @@ -142,6 +142,8 @@ namespace MediaBrowser.Api /// Initializes a new instance of the <see cref="UserService" /> class. /// </summary> /// <param name="xmlSerializer">The XML serializer.</param> + /// <param name="userManager">The user manager.</param> + /// <param name="libraryManager">The library manager.</param> /// <exception cref="System.ArgumentNullException">xmlSerializer</exception> public UserService(IXmlSerializer xmlSerializer, IUserManager userManager, ILibraryManager libraryManager) : base() @@ -163,7 +165,7 @@ namespace MediaBrowser.Api /// <returns>System.Object.</returns> public object Get(GetUsers request) { - var dtoBuilder = new DtoBuilder(Logger, _libraryManager); + var dtoBuilder = new DtoBuilder(Logger, _libraryManager, _userManager); var tasks = _userManager.Users.OrderBy(u => u.Name).Select(dtoBuilder.GetUserDto).ToArray(); @@ -186,7 +188,7 @@ namespace MediaBrowser.Api throw new ResourceNotFoundException("User not found"); } - var result = new DtoBuilder(Logger, _libraryManager).GetUserDto(user).Result; + var result = new DtoBuilder(Logger, _libraryManager, _userManager).GetUserDto(user).Result; return ToOptimizedResult(result); } @@ -300,7 +302,7 @@ namespace MediaBrowser.Api newUser.UpdateConfiguration(dtoUser.Configuration, _xmlSerializer); - var result = new DtoBuilder(Logger, _libraryManager).GetUserDto(newUser).Result; + var result = new DtoBuilder(Logger, _libraryManager, _userManager).GetUserDto(newUser).Result; return ToOptimizedResult(result); } diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index d30f11f7d..411190d77 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -797,109 +797,6 @@ namespace MediaBrowser.Controller.Entities } /// <summary> - /// The _user data - /// </summary> - private IEnumerable<UserItemData> _userData; - /// <summary> - /// The _user data initialized - /// </summary> - private bool _userDataInitialized; - /// <summary> - /// The _user data sync lock - /// </summary> - private object _userDataSyncLock = new object(); - /// <summary> - /// Gets the user data. - /// </summary> - /// <value>The user data.</value> - [IgnoreDataMember] - public IEnumerable<UserItemData> UserData - { - get - { - // Call ToList to exhaust the stream because we'll be iterating over this multiple times - LazyInitializer.EnsureInitialized(ref _userData, ref _userDataInitialized, ref _userDataSyncLock, () => Kernel.Instance.UserDataRepository.RetrieveUserData(this).ToList()); - return _userData; - } - private set - { - _userData = value; - - if (value == null) - { - _userDataInitialized = false; - } - } - } - - /// <summary> - /// Gets the user data. - /// </summary> - /// <param name="user">The user.</param> - /// <param name="createIfNull">if set to <c>true</c> [create if null].</param> - /// <returns>UserItemData.</returns> - /// <exception cref="System.ArgumentNullException"></exception> - public UserItemData GetUserData(User user, bool createIfNull) - { - if (user == null) - { - throw new ArgumentNullException(); - } - - if (UserData == null) - { - if (!createIfNull) - { - return null; - } - - AddOrUpdateUserData(user, new UserItemData { UserId = user.Id }); - } - - var data = UserData.FirstOrDefault(u => u.UserId == user.Id); - - if (data == null && createIfNull) - { - data = new UserItemData { UserId = user.Id }; - AddOrUpdateUserData(user, data); - } - - return data; - } - - /// <summary> - /// Adds the or update user data. - /// </summary> - /// <param name="user">The user.</param> - /// <param name="data">The data.</param> - /// <exception cref="System.ArgumentNullException"></exception> - public void AddOrUpdateUserData(User user, UserItemData data) - { - if (user == null) - { - throw new ArgumentNullException(); - } - - if (data == null) - { - throw new ArgumentNullException(); - } - - data.UserId = user.Id; - - if (UserData == null) - { - UserData = new[] { data }; - } - else - { - var list = UserData.Where(u => u.UserId != user.Id).ToList(); - list.Add(data); - UserData = list; - } - } - - /// <summary> /// The _user data id /// </summary> protected Guid _userDataId; //cache this so it doesn't have to be re-constructed on every reference @@ -1205,16 +1102,17 @@ namespace MediaBrowser.Controller.Entities /// </summary> /// <param name="user">The user.</param> /// <param name="wasPlayed">if set to <c>true</c> [was played].</param> + /// <param name="userManager">The user manager.</param> /// <returns>Task.</returns> /// <exception cref="System.ArgumentNullException"></exception> - public virtual Task SetPlayedStatus(User user, bool wasPlayed, IUserManager userManager) + public virtual async Task SetPlayedStatus(User user, bool wasPlayed, IUserManager userManager) { if (user == null) { throw new ArgumentNullException(); } - var data = GetUserData(user, true); + var data = await userManager.GetUserData(user.Id, UserDataId).ConfigureAwait(false); if (wasPlayed) { @@ -1237,7 +1135,7 @@ namespace MediaBrowser.Controller.Entities data.Played = wasPlayed; - return userManager.SaveUserDataForItem(user, this, data); + await userManager.SaveUserData(user.Id, UserDataId, data, CancellationToken.None).ConfigureAwait(false); } /// <summary> diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index 5a61844c2..05ee87def 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -74,109 +74,6 @@ namespace MediaBrowser.Controller.Entities } } - /// <summary> - /// The _display prefs - /// </summary> - private IEnumerable<DisplayPreferences> _displayPreferences; - /// <summary> - /// The _display prefs initialized - /// </summary> - private bool _displayPreferencesInitialized; - /// <summary> - /// The _display prefs sync lock - /// </summary> - private object _displayPreferencesSyncLock = new object(); - /// <summary> - /// Gets the display prefs. - /// </summary> - /// <value>The display prefs.</value> - [IgnoreDataMember] - public IEnumerable<DisplayPreferences> DisplayPreferences - { - get - { - // Call ToList to exhaust the stream because we'll be iterating over this multiple times - LazyInitializer.EnsureInitialized(ref _displayPreferences, ref _displayPreferencesInitialized, ref _displayPreferencesSyncLock, () => Kernel.Instance.DisplayPreferencesRepository.RetrieveDisplayPreferences(this).ToList()); - return _displayPreferences; - } - private set - { - _displayPreferences = value; - - if (value == null) - { - _displayPreferencesInitialized = false; - } - } - } - - /// <summary> - /// Gets the display prefs. - /// </summary> - /// <param name="user">The user.</param> - /// <param name="createIfNull">if set to <c>true</c> [create if null].</param> - /// <returns>DisplayPreferences.</returns> - /// <exception cref="System.ArgumentNullException"></exception> - public DisplayPreferences GetDisplayPreferences(User user, bool createIfNull) - { - if (user == null) - { - throw new ArgumentNullException(); - } - - if (DisplayPreferences == null) - { - if (!createIfNull) - { - return null; - } - - AddOrUpdateDisplayPreferences(user, new DisplayPreferences { UserId = user.Id }); - } - - var data = DisplayPreferences.FirstOrDefault(u => u.UserId == user.Id); - - if (data == null && createIfNull) - { - data = new DisplayPreferences { UserId = user.Id }; - AddOrUpdateDisplayPreferences(user, data); - } - - return data; - } - - /// <summary> - /// Adds the or update display prefs. - /// </summary> - /// <param name="user">The user.</param> - /// <param name="data">The data.</param> - /// <exception cref="System.ArgumentNullException"></exception> - public void AddOrUpdateDisplayPreferences(User user, DisplayPreferences data) - { - if (user == null) - { - throw new ArgumentNullException(); - } - - if (data == null) - { - throw new ArgumentNullException(); - } - - data.UserId = user.Id; - - if (DisplayPreferences == null) - { - DisplayPreferences = new[] { data }; - } - else - { - var list = DisplayPreferences.Where(u => u.UserId != user.Id).ToList(); - list.Add(data); - DisplayPreferences = list; - } - } - #region Indexing /// <summary> @@ -902,6 +799,7 @@ namespace MediaBrowser.Controller.Entities /// </summary> /// <param name="user">The user.</param> /// <param name="wasPlayed">if set to <c>true</c> [was played].</param> + /// <param name="userManager">The user manager.</param> /// <returns>Task.</returns> public override async Task SetPlayedStatus(User user, bool wasPlayed, IUserManager userManager) { diff --git a/MediaBrowser.Controller/Library/DtoBuilder.cs b/MediaBrowser.Controller/Library/DtoBuilder.cs index 36c7eba1f..d9244c64c 100644 --- a/MediaBrowser.Controller/Library/DtoBuilder.cs +++ b/MediaBrowser.Controller/Library/DtoBuilder.cs @@ -28,11 +28,13 @@ namespace MediaBrowser.Controller.Library private readonly ILogger _logger; private readonly ILibraryManager _libraryManager; + private readonly IUserManager _userManager; - public DtoBuilder(ILogger logger, ILibraryManager libraryManager) + public DtoBuilder(ILogger logger, ILibraryManager libraryManager, IUserManager userManager) { _logger = logger; _libraryManager = libraryManager; + _userManager = userManager; } /// <summary> @@ -141,9 +143,9 @@ namespace MediaBrowser.Controller.Library tasks.Add(AttachPeople(dto, item)); } - AttachBasicFields(dto, item, fields); + tasks.Add(AttachUserSpecificInfo(dto, item, user, fields)); - AttachUserSpecificInfo(dto, item, user, fields); + AttachBasicFields(dto, item, fields); // Make sure all the tasks we kicked off have completed. if (tasks.Count > 0) @@ -161,21 +163,20 @@ namespace MediaBrowser.Controller.Library /// <param name="item">The item.</param> /// <param name="user">The user.</param> /// <param name="fields">The fields.</param> - private void AttachUserSpecificInfo(BaseItemDto dto, BaseItem item, User user, List<ItemFields> fields) + private async Task AttachUserSpecificInfo(BaseItemDto dto, BaseItem item, User user, List<ItemFields> fields) { if (fields.Contains(ItemFields.UserData)) { - var userData = item.GetUserData(user, false); + var userData = await _userManager.GetUserData(user.Id, item.UserDataId).ConfigureAwait(false); - if (userData != null) - { - dto.UserData = GetUserItemDataDto(userData); - } + dto.UserData = GetUserItemDataDto(userData); } if (item.IsFolder && fields.Contains(ItemFields.DisplayPreferences)) { - dto.DisplayPreferences = ((Folder)item).GetDisplayPreferences(user, false) ?? new DisplayPreferences { UserId = user.Id }; + var displayPreferencesId = ((Folder) item).DisplayPreferencesId; + + dto.DisplayPreferences = await _userManager.GetDisplayPreferences(user.Id, displayPreferencesId).ConfigureAwait(false); } if (item.IsFolder) @@ -187,11 +188,11 @@ namespace MediaBrowser.Controller.Library // Skip sorting since all we want is a count dto.ChildCount = folder.GetChildren(user).Count(); - SetSpecialCounts(folder, user, dto); + await SetSpecialCounts(folder, user, dto, _userManager).ConfigureAwait(false); } } } - + /// <summary> /// Attaches the primary image aspect ratio. /// </summary> @@ -484,7 +485,9 @@ namespace MediaBrowser.Controller.Library /// <param name="folder">The folder.</param> /// <param name="user">The user.</param> /// <param name="dto">The dto.</param> - private static void SetSpecialCounts(Folder folder, User user, BaseItemDto dto) + /// <param name="userManager">The user manager.</param> + /// <returns>Task.</returns> + private static async Task SetSpecialCounts(Folder folder, User user, BaseItemDto dto, IUserManager userManager) { var rcentlyAddedItemCount = 0; var recursiveItemCount = 0; @@ -494,7 +497,7 @@ namespace MediaBrowser.Controller.Library // Loop through each recursive child foreach (var child in folder.GetRecursiveChildren(user).Where(i => !i.IsFolder)) { - var userdata = child.GetUserData(user, false); + var userdata = await userManager.GetUserData(user.Id, child.UserDataId).ConfigureAwait(false); recursiveItemCount++; diff --git a/MediaBrowser.Controller/Library/ILibraryManager.cs b/MediaBrowser.Controller/Library/ILibraryManager.cs index 1b9d2f4b2..da2f46abb 100644 --- a/MediaBrowser.Controller/Library/ILibraryManager.cs +++ b/MediaBrowser.Controller/Library/ILibraryManager.cs @@ -108,15 +108,6 @@ namespace MediaBrowser.Controller.Library Task ValidateMediaLibrary(IProgress<double> progress, CancellationToken cancellationToken); /// <summary> - /// Saves display preferences for a Folder - /// </summary> - /// <param name="user">The user.</param> - /// <param name="folder">The folder.</param> - /// <param name="data">The data.</param> - /// <returns>Task.</returns> - Task SaveDisplayPreferencesForFolder(User user, Folder folder, DisplayPreferences data); - - /// <summary> /// Gets the default view. /// </summary> /// <returns>IEnumerable{VirtualFolderInfo}.</returns> diff --git a/MediaBrowser.Controller/Library/IUserManager.cs b/MediaBrowser.Controller/Library/IUserManager.cs index 229e4cb76..8374c6880 100644 --- a/MediaBrowser.Controller/Library/IUserManager.cs +++ b/MediaBrowser.Controller/Library/IUserManager.cs @@ -1,6 +1,7 @@ using MediaBrowser.Common.Events; using MediaBrowser.Controller.Entities; using MediaBrowser.Model.Connectivity; +using MediaBrowser.Model.Entities; using System; using System.Collections.Generic; using System.Threading; @@ -157,14 +158,6 @@ namespace MediaBrowser.Controller.Library Task OnPlaybackStopped(User user, BaseItem item, long? positionTicks, string clientType, string deviceId, string deviceName); /// <summary> - /// Saves user data for an item - /// </summary> - /// <param name="user">The user.</param> - /// <param name="item">The item.</param> - /// <param name="data">The data.</param> - Task SaveUserDataForItem(User user, BaseItem item, UserItemData data); - - /// <summary> /// Resets the password. /// </summary> /// <param name="user">The user.</param> @@ -178,5 +171,43 @@ namespace MediaBrowser.Controller.Library /// <param name="newPassword">The new password.</param> /// <returns>Task.</returns> Task ChangePassword(User user, string newPassword); + + /// <summary> + /// Saves display preferences for an item + /// </summary> + /// <param name="userId">The user id.</param> + /// <param name="userDataId">The user data id.</param> + /// <param name="userData">The user data.</param> + /// <param name="cancellationToken">The cancellation token.</param> + /// <returns>Task.</returns> + Task SaveUserData(Guid userId, Guid userDataId, UserItemData userData, + CancellationToken cancellationToken); + + /// <summary> + /// Gets the display preferences. + /// </summary> + /// <param name="userId">The user id.</param> + /// <param name="userDataId">The user data id.</param> + /// <returns>Task{DisplayPreferences}.</returns> + Task<UserItemData> GetUserData(Guid userId, Guid userDataId); + + /// <summary> + /// Gets the display preferences. + /// </summary> + /// <param name="userId">The user id.</param> + /// <param name="displayPreferencesId">The display preferences id.</param> + /// <returns>DisplayPreferences.</returns> + Task<DisplayPreferences> GetDisplayPreferences(Guid userId, Guid displayPreferencesId); + + /// <summary> + /// Saves display preferences for an item + /// </summary> + /// <param name="userId">The user id.</param> + /// <param name="displayPreferencesId">The display preferences id.</param> + /// <param name="displayPreferences">The display preferences.</param> + /// <param name="cancellationToken">The cancellation token.</param> + /// <returns>Task.</returns> + Task SaveDisplayPreferences(Guid userId, Guid displayPreferencesId, DisplayPreferences displayPreferences, + CancellationToken cancellationToken); } } diff --git a/MediaBrowser.Controller/Persistence/IDisplayPreferencesRepository.cs b/MediaBrowser.Controller/Persistence/IDisplayPreferencesRepository.cs index 6f03810c2..eb43c8ca5 100644 --- a/MediaBrowser.Controller/Persistence/IDisplayPreferencesRepository.cs +++ b/MediaBrowser.Controller/Persistence/IDisplayPreferencesRepository.cs @@ -1,6 +1,5 @@ -using MediaBrowser.Controller.Entities; -using MediaBrowser.Model.Entities; -using System.Collections.Generic; +using MediaBrowser.Model.Entities; +using System; using System.Threading; using System.Threading.Tasks; @@ -14,16 +13,20 @@ namespace MediaBrowser.Controller.Persistence /// <summary> /// Saves display preferences for an item /// </summary> - /// <param name="item">The item.</param> + /// <param name="userId">The user id.</param> + /// <param name="displayPreferencesId">The display preferences id.</param> + /// <param name="displayPreferences">The display preferences.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task.</returns> - Task SaveDisplayPreferences(Folder item, CancellationToken cancellationToken); + Task SaveDisplayPreferences(Guid userId, Guid displayPreferencesId, DisplayPreferences displayPreferences, + CancellationToken cancellationToken); /// <summary> - /// Gets display preferences for an item + /// Gets the display preferences. /// </summary> - /// <param name="item">The item.</param> - /// <returns>IEnumerable{DisplayPreferences}.</returns> - IEnumerable<DisplayPreferences> RetrieveDisplayPreferences(Folder item); + /// <param name="userId">The user id.</param> + /// <param name="displayPreferencesId">The display preferences id.</param> + /// <returns>Task{DisplayPreferences}.</returns> + Task<DisplayPreferences> GetDisplayPreferences(Guid userId, Guid displayPreferencesId); } } diff --git a/MediaBrowser.Controller/Persistence/IUserDataRepository.cs b/MediaBrowser.Controller/Persistence/IUserDataRepository.cs index 115bd411a..592206faf 100644 --- a/MediaBrowser.Controller/Persistence/IUserDataRepository.cs +++ b/MediaBrowser.Controller/Persistence/IUserDataRepository.cs @@ -1,5 +1,5 @@ using MediaBrowser.Controller.Entities; -using System.Collections.Generic; +using System; using System.Threading; using System.Threading.Tasks; @@ -11,18 +11,22 @@ namespace MediaBrowser.Controller.Persistence public interface IUserDataRepository : IRepository { /// <summary> - /// Saves user data for an item + /// Saves the user data. /// </summary> - /// <param name="item">The item.</param> + /// <param name="userId">The user id.</param> + /// <param name="userDataId">The user data id.</param> + /// <param name="userData">The user data.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task.</returns> - Task SaveUserData(BaseItem item, CancellationToken cancellationToken); + Task SaveUserData(Guid userId, Guid userDataId, UserItemData userData, + CancellationToken cancellationToken); /// <summary> - /// Gets user data for an item + /// Gets the user data. /// </summary> - /// <param name="item">The item.</param> - /// <returns>IEnumerable{UserItemData}.</returns> - IEnumerable<UserItemData> RetrieveUserData(BaseItem item); + /// <param name="userId">The user id.</param> + /// <param name="userDataId">The user data id.</param> + /// <returns>Task{UserItemData}.</returns> + Task<UserItemData> GetUserData(Guid userId, Guid userDataId); } } diff --git a/MediaBrowser.Controller/Sorting/IUserBaseItemComparer.cs b/MediaBrowser.Controller/Sorting/IUserBaseItemComparer.cs index b9da1f6a6..76d84a653 100644 --- a/MediaBrowser.Controller/Sorting/IUserBaseItemComparer.cs +++ b/MediaBrowser.Controller/Sorting/IUserBaseItemComparer.cs @@ -1,4 +1,5 @@ using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Library; namespace MediaBrowser.Controller.Sorting { @@ -12,5 +13,11 @@ namespace MediaBrowser.Controller.Sorting /// </summary> /// <value>The user.</value> User User { get; set; } + + /// <summary> + /// Gets or sets the user manager. + /// </summary> + /// <value>The user manager.</value> + IUserManager UserManager { get; set; } } } diff --git a/MediaBrowser.Server.Implementations/HttpServer/HttpServer.cs b/MediaBrowser.Server.Implementations/HttpServer/HttpServer.cs index edb227c79..669603958 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/HttpServer.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/HttpServer.cs @@ -160,7 +160,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer if (exception != null) { - _logger.ErrorException("Error processing request", exception); + _logger.ErrorException("Error processing request for {0}", exception, req.RawUrl); if (!string.IsNullOrEmpty(exception.Message)) { diff --git a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs index 84055cea7..a57eb8eaa 100644 --- a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs +++ b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs @@ -124,15 +124,6 @@ namespace MediaBrowser.Server.Implementations.Library LazyInitializer.EnsureInitialized(ref _libraryItemsCache, ref _libraryItemsCacheInitialized, ref _libraryItemsCacheSyncLock, CreateLibraryItemsCache); return _libraryItemsCache; } - set - { - _libraryItemsCache = value; - - if (value == null) - { - _libraryItemsCacheInitialized = false; - } - } } /// <summary> @@ -267,10 +258,22 @@ namespace MediaBrowser.Server.Implementations.Library items.AddRange(specialFeatures); items.AddRange(localTrailers); - // Can't add these right now because there could be separate instances with the same id. - //items.AddRange(_userManager.Users.Select(i => i.RootFolder).Distinct().ToList()); + // Need to use DistinctBy Id because there could be multiple instances with the same id + // due to sharing the default library + var userRootFolders = _userManager.Users.Select(i => i.RootFolder) + .DistinctBy(i => i.Id) + .ToList(); + + items.AddRange(userRootFolders); - items.AddRange(_userManager.Users.SelectMany(i => i.RootFolder.Children).Where(i => !(i is BasePluginFolder)).Distinct().ToList()); + // Get all user collection folders + var userFolders = + _userManager.Users.SelectMany(i => i.RootFolder.Children) + .Where(i => !(i is BasePluginFolder)) + .DistinctBy(i => i.Id) + .ToList(); + + items.AddRange(userFolders); return new ConcurrentDictionary<Guid,BaseItem>(items.ToDictionary(i => i.Id)); } @@ -745,26 +748,6 @@ namespace MediaBrowser.Server.Implementations.Library } /// <summary> - /// Saves display preferences for a Folder - /// </summary> - /// <param name="user">The user.</param> - /// <param name="folder">The folder.</param> - /// <param name="data">The data.</param> - /// <returns>Task.</returns> - public Task SaveDisplayPreferencesForFolder(User user, Folder folder, DisplayPreferences data) - { - // Need to update all items with the same DisplayPreferencesId - foreach (var child in RootFolder.GetRecursiveChildren(user) - .OfType<Folder>() - .Where(i => i.DisplayPreferencesId == folder.DisplayPreferencesId)) - { - child.AddOrUpdateDisplayPreferences(user, data); - } - - return Kernel.DisplayPreferencesRepository.SaveDisplayPreferences(folder, CancellationToken.None); - } - - /// <summary> /// Gets the default view. /// </summary> /// <returns>IEnumerable{VirtualFolderInfo}.</returns> @@ -878,6 +861,7 @@ namespace MediaBrowser.Server.Implementations.Library var userComparer = (IUserBaseItemComparer)Activator.CreateInstance(comparer.GetType()); userComparer.User = user; + userComparer.UserManager = _userManager; return userComparer; } diff --git a/MediaBrowser.Server.Implementations/Library/UserManager.cs b/MediaBrowser.Server.Implementations/Library/UserManager.cs index 49b2a3f18..ca3c1fe7c 100644 --- a/MediaBrowser.Server.Implementations/Library/UserManager.cs +++ b/MediaBrowser.Server.Implementations/Library/UserManager.cs @@ -5,8 +5,10 @@ using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; using MediaBrowser.Model.Connectivity; +using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Security.Cryptography; @@ -98,6 +100,13 @@ namespace MediaBrowser.Server.Implementations.Library private IServerConfigurationManager ConfigurationManager { get; set; } /// <summary> + /// The _user data + /// </summary> + private readonly ConcurrentDictionary<string, Task<DisplayPreferences>> _displayPreferences = new ConcurrentDictionary<string, Task<DisplayPreferences>>(); + + private readonly ConcurrentDictionary<string, Task<UserItemData>> _userData = new ConcurrentDictionary<string, Task<UserItemData>>(); + + /// <summary> /// Initializes a new instance of the <see cref="UserManager" /> class. /// </summary> /// <param name="kernel">The kernel.</param> @@ -157,6 +166,63 @@ namespace MediaBrowser.Server.Implementations.Library #endregion /// <summary> + /// Gets the display preferences. + /// </summary> + /// <param name="userId">The user id.</param> + /// <param name="displayPreferencesId">The display preferences id.</param> + /// <returns>DisplayPreferences.</returns> + public Task<DisplayPreferences> GetDisplayPreferences(Guid userId, Guid displayPreferencesId) + { + var key = userId + displayPreferencesId.ToString(); + + return _displayPreferences.GetOrAdd(key, keyName => RetrieveDisplayPreferences(userId, displayPreferencesId)); + } + + /// <summary> + /// Retrieves the display preferences. + /// </summary> + /// <param name="userId">The user id.</param> + /// <param name="displayPreferencesId">The display preferences id.</param> + /// <returns>DisplayPreferences.</returns> + private async Task<DisplayPreferences> RetrieveDisplayPreferences(Guid userId, Guid displayPreferencesId) + { + var displayPreferences = await Kernel.Instance.DisplayPreferencesRepository.GetDisplayPreferences(userId, displayPreferencesId).ConfigureAwait(false); + + return displayPreferences ?? new DisplayPreferences(); + } + + /// <summary> + /// Saves display preferences for an item + /// </summary> + /// <param name="userId">The user id.</param> + /// <param name="displayPreferencesId">The display preferences id.</param> + /// <param name="displayPreferences">The display preferences.</param> + /// <param name="cancellationToken">The cancellation token.</param> + /// <returns>Task.</returns> + public async Task SaveDisplayPreferences(Guid userId, Guid displayPreferencesId, DisplayPreferences displayPreferences, CancellationToken cancellationToken) + { + var key = userId + displayPreferencesId.ToString(); + + try + { + await Kernel.Instance.DisplayPreferencesRepository.SaveDisplayPreferences(userId, displayPreferencesId, + displayPreferences, + cancellationToken).ConfigureAwait(false); + + var newValue = Task.FromResult(displayPreferences); + + // Once it succeeds, put it into the dictionary to make it available to everyone else + _displayPreferences.AddOrUpdate(key, newValue, delegate { return newValue; }); + } + catch (Exception ex) + { + _logger.ErrorException("Error saving display preferences", ex); + + throw; + } + } + + /// <summary> /// Gets a User by Id /// </summary> /// <param name="id">The id.</param> @@ -588,10 +654,10 @@ namespace MediaBrowser.Server.Implementations.Library if (positionTicks.HasValue) { - var data = item.GetUserData(user, true); + var data = await GetUserData(user.Id, item.UserDataId).ConfigureAwait(false); UpdatePlayState(item, data, positionTicks.Value, false); - await SaveUserDataForItem(user, item, data).ConfigureAwait(false); + await SaveUserData(user.Id, item.UserDataId, data, CancellationToken.None).ConfigureAwait(false); } EventHelper.QueueEventIfNotNull(PlaybackProgress, this, new PlaybackProgressEventArgs @@ -626,7 +692,7 @@ namespace MediaBrowser.Server.Implementations.Library RemoveNowPlayingItemId(user, clientType, deviceId, deviceName, item); - var data = item.GetUserData(user, true); + var data = await GetUserData(user.Id, item.UserDataId).ConfigureAwait(false); if (positionTicks.HasValue) { @@ -639,7 +705,7 @@ namespace MediaBrowser.Server.Implementations.Library data.Played = true; } - await SaveUserDataForItem(user, item, data).ConfigureAwait(false); + await SaveUserData(user.Id, item.UserDataId, data, CancellationToken.None).ConfigureAwait(false); EventHelper.QueueEventIfNotNull(PlaybackStopped, this, new PlaybackProgressEventArgs { @@ -700,17 +766,57 @@ namespace MediaBrowser.Server.Implementations.Library } /// <summary> - /// Saves user data for an item + /// Saves display preferences for an item /// </summary> - /// <param name="user">The user.</param> - /// <param name="item">The item.</param> - /// <param name="data">The data.</param> - public Task SaveUserDataForItem(User user, BaseItem item, UserItemData data) + /// <param name="userId">The user id.</param> + /// <param name="userDataId">The user data id.</param> + /// <param name="userData">The user data.</param> + /// <param name="cancellationToken">The cancellation token.</param> + /// <returns>Task.</returns> + public async Task SaveUserData(Guid userId, Guid userDataId, UserItemData userData, CancellationToken cancellationToken) + { + var key = userId + userDataId.ToString(); + try + { + await Kernel.Instance.UserDataRepository.SaveUserData(userId, userDataId, userData, cancellationToken).ConfigureAwait(false); + + var newValue = Task.FromResult(userData); + + // Once it succeeds, put it into the dictionary to make it available to everyone else + _userData.AddOrUpdate(key, newValue, delegate { return newValue; }); + } + catch (Exception ex) + { + _logger.ErrorException("Error saving user data", ex); + + throw; + } + } + + /// <summary> + /// Gets the display preferences. + /// </summary> + /// <param name="userId">The user id.</param> + /// <param name="userDataId">The user data id.</param> + /// <returns>Task{DisplayPreferences}.</returns> + public Task<UserItemData> GetUserData(Guid userId, Guid userDataId) { - item.AddOrUpdateUserData(user, data); + var key = userId + userDataId.ToString(); - return Kernel.UserDataRepository.SaveUserData(item, CancellationToken.None); + return _userData.GetOrAdd(key, keyName => RetrieveUserData(userId, userDataId)); } + /// <summary> + /// Retrieves the display preferences. + /// </summary> + /// <param name="userId">The user id.</param> + /// <param name="userDataId">The user data id.</param> + /// <returns>DisplayPreferences.</returns> + private async Task<UserItemData> RetrieveUserData(Guid userId, Guid userDataId) + { + var userdata = await Kernel.Instance.UserDataRepository.GetUserData(userId, userDataId).ConfigureAwait(false); + + return userdata ?? new UserItemData(); + } } } diff --git a/MediaBrowser.Server.Implementations/Sorting/DatePlayedComparer.cs b/MediaBrowser.Server.Implementations/Sorting/DatePlayedComparer.cs index c37b6b4a4..905d5413a 100644 --- a/MediaBrowser.Server.Implementations/Sorting/DatePlayedComparer.cs +++ b/MediaBrowser.Server.Implementations/Sorting/DatePlayedComparer.cs @@ -1,4 +1,5 @@ using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Sorting; using MediaBrowser.Model.Querying; using System; @@ -17,6 +18,12 @@ namespace MediaBrowser.Server.Implementations.Sorting public User User { get; set; } /// <summary> + /// Gets or sets the user manager. + /// </summary> + /// <value>The user manager.</value> + public IUserManager UserManager { get; set; } + + /// <summary> /// Compares the specified x. /// </summary> /// <param name="x">The x.</param> @@ -34,7 +41,7 @@ namespace MediaBrowser.Server.Implementations.Sorting /// <returns>DateTime.</returns> private DateTime GetDate(BaseItem x) { - var userdata = x.GetUserData(User, false); + var userdata = UserManager.GetUserData(User.Id, x.UserDataId).Result; if (userdata != null && userdata.LastPlayedDate.HasValue) { diff --git a/MediaBrowser.Server.Implementations/Sorting/PlayCountComparer.cs b/MediaBrowser.Server.Implementations/Sorting/PlayCountComparer.cs index 9cd5281c3..82e76e78d 100644 --- a/MediaBrowser.Server.Implementations/Sorting/PlayCountComparer.cs +++ b/MediaBrowser.Server.Implementations/Sorting/PlayCountComparer.cs @@ -1,4 +1,5 @@ using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Sorting; using MediaBrowser.Model.Querying; @@ -33,7 +34,7 @@ namespace MediaBrowser.Server.Implementations.Sorting /// <returns>DateTime.</returns> private int GetValue(BaseItem x) { - var userdata = x.GetUserData(User, false); + var userdata = UserManager.GetUserData(User.Id, x.UserDataId).Result; return userdata == null ? 0 : userdata.PlayCount; } @@ -46,5 +47,11 @@ namespace MediaBrowser.Server.Implementations.Sorting { get { return ItemSortBy.PlayCount; } } + + /// <summary> + /// Gets or sets the user manager. + /// </summary> + /// <value>The user manager.</value> + public IUserManager UserManager { get; set; } } } diff --git a/MediaBrowser.Server.Implementations/Sqlite/SQLiteDisplayPreferencesRepository.cs b/MediaBrowser.Server.Implementations/Sqlite/SQLiteDisplayPreferencesRepository.cs index baa38cde0..44674e125 100644 --- a/MediaBrowser.Server.Implementations/Sqlite/SQLiteDisplayPreferencesRepository.cs +++ b/MediaBrowser.Server.Implementations/Sqlite/SQLiteDisplayPreferencesRepository.cs @@ -1,11 +1,9 @@ using MediaBrowser.Common.Configuration; -using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Persistence; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; using MediaBrowser.Model.Serialization; using System; -using System.Collections.Generic; using System.Data; using System.IO; using System.Threading; @@ -80,8 +78,8 @@ namespace MediaBrowser.Server.Implementations.Sqlite string[] queries = { - "create table if not exists display_prefs (item_id GUID, user_id GUID, data BLOB)", - "create unique index if not exists idx_display_prefs on display_prefs (item_id, user_id)", + "create table if not exists displaypreferences (id GUID, userId GUID, data BLOB)", + "create unique index if not exists displaypreferencesindex on displaypreferences (id, userId)", "create table if not exists schema_version (table_name primary key, version)", //pragmas "pragma temp_store = memory" @@ -93,82 +91,87 @@ namespace MediaBrowser.Server.Implementations.Sqlite /// <summary> /// Save the display preferences associated with an item in the repo /// </summary> - /// <param name="item">The item.</param> + /// <param name="userId">The user id.</param> + /// <param name="displayPreferencesId">The display preferences id.</param> + /// <param name="displayPreferences">The display preferences.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task.</returns> /// <exception cref="System.ArgumentNullException">item</exception> - public Task SaveDisplayPreferences(Folder item, CancellationToken cancellationToken) + public Task SaveDisplayPreferences(Guid userId, Guid displayPreferencesId, DisplayPreferences displayPreferences, CancellationToken cancellationToken) { - if (item == null) + if (displayPreferences == null) { - throw new ArgumentNullException("item"); + throw new ArgumentNullException("displayPreferences"); } - if (cancellationToken == null) { throw new ArgumentNullException("cancellationToken"); } + if (userId == Guid.Empty) + { + throw new ArgumentNullException("userId"); + } + if (displayPreferencesId == Guid.Empty) + { + throw new ArgumentNullException("displayPreferencesId"); + } cancellationToken.ThrowIfCancellationRequested(); - + return Task.Run(() => { - var cmd = connection.CreateCommand(); + var serialized = _protobufSerializer.SerializeToBytes(displayPreferences); - cmd.CommandText = "delete from display_prefs where item_id = @guid"; - cmd.AddParam("@guid", item.DisplayPreferencesId); + cancellationToken.ThrowIfCancellationRequested(); + var cmd = connection.CreateCommand(); + cmd.CommandText = "replace into displaypreferences (id, userId, data) values (@1, @2, @3)"; + cmd.AddParam("@1", displayPreferencesId); + cmd.AddParam("@2", userId); + cmd.AddParam("@3", serialized); QueueCommand(cmd); - - if (item.DisplayPreferences != null) - { - foreach (var data in item.DisplayPreferences) - { - cmd = connection.CreateCommand(); - cmd.CommandText = "insert into display_prefs (item_id, user_id, data) values (@1, @2, @3)"; - cmd.AddParam("@1", item.DisplayPreferencesId); - cmd.AddParam("@2", data.UserId); - - cmd.AddParam("@3", _protobufSerializer.SerializeToBytes(data)); - - QueueCommand(cmd); - } - } }); } /// <summary> - /// Gets display preferences for an item + /// Gets the display preferences. /// </summary> - /// <param name="item">The item.</param> - /// <returns>IEnumerable{DisplayPreferences}.</returns> - /// <exception cref="System.ArgumentNullException"></exception> - public IEnumerable<DisplayPreferences> RetrieveDisplayPreferences(Folder item) + /// <param name="userId">The user id.</param> + /// <param name="displayPreferencesId">The display preferences id.</param> + /// <returns>Task{DisplayPreferences}.</returns> + /// <exception cref="System.ArgumentNullException">item</exception> + public async Task<DisplayPreferences> GetDisplayPreferences(Guid userId, Guid displayPreferencesId) { - if (item == null) + if (userId == Guid.Empty) + { + throw new ArgumentNullException("userId"); + } + if (displayPreferencesId == Guid.Empty) { - throw new ArgumentNullException("item"); + throw new ArgumentNullException("displayPreferencesId"); } var cmd = connection.CreateCommand(); - cmd.CommandText = "select data from display_prefs where item_id = @guid"; - var guidParam = cmd.Parameters.Add("@guid", DbType.Guid); - guidParam.Value = item.DisplayPreferencesId; + cmd.CommandText = "select data from displaypreferences where id = @id and userId=@userId"; + + var idParam = cmd.Parameters.Add("@id", DbType.Guid); + idParam.Value = displayPreferencesId; - using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)) + var userIdParam = cmd.Parameters.Add("@userId", DbType.Guid); + userIdParam.Value = userId; + + using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult | CommandBehavior.SingleRow).ConfigureAwait(false)) { - while (reader.Read()) + if (reader.Read()) { using (var stream = GetStream(reader, 0)) { - var data = _protobufSerializer.DeserializeFromStream<DisplayPreferences>(stream); - if (data != null) - { - yield return data; - } + return _protobufSerializer.DeserializeFromStream<DisplayPreferences>(stream); } } } + + return null; } } } diff --git a/MediaBrowser.Server.Implementations/Sqlite/SQLiteUserDataRepository.cs b/MediaBrowser.Server.Implementations/Sqlite/SQLiteUserDataRepository.cs index dafdce798..f3dede889 100644 --- a/MediaBrowser.Server.Implementations/Sqlite/SQLiteUserDataRepository.cs +++ b/MediaBrowser.Server.Implementations/Sqlite/SQLiteUserDataRepository.cs @@ -79,8 +79,8 @@ namespace MediaBrowser.Server.Implementations.Sqlite string[] queries = { - "create table if not exists user_data (item_id GUID, user_id GUID, data BLOB)", - "create unique index if not exists idx_user_data on user_data (item_id, user_id)", + "create table if not exists userdata (id GUID, userId GUID, data BLOB)", + "create unique index if not exists userdataindex on userdata (id, userId)", "create table if not exists schema_version (table_name primary key, version)", //pragmas "pragma temp_store = memory" @@ -90,84 +90,101 @@ namespace MediaBrowser.Server.Implementations.Sqlite } /// <summary> - /// Save the user specific data associated with an item in the repo + /// Saves the user data. /// </summary> - /// <param name="item">The item.</param> + /// <param name="userId">The user id.</param> + /// <param name="userDataId">The user data id.</param> + /// <param name="userData">The user data.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task.</returns> - /// <exception cref="System.ArgumentNullException">item</exception> - public Task SaveUserData(BaseItem item, CancellationToken cancellationToken) + /// <exception cref="System.ArgumentNullException"> + /// userData + /// or + /// cancellationToken + /// or + /// userId + /// or + /// userDataId + /// </exception> + public Task SaveUserData(Guid userId, Guid userDataId, UserItemData userData, CancellationToken cancellationToken) { - if (item == null) + if (userData == null) { - throw new ArgumentNullException("item"); + throw new ArgumentNullException("userData"); } - if (cancellationToken == null) { throw new ArgumentNullException("cancellationToken"); } - + if (userId == Guid.Empty) + { + throw new ArgumentNullException("userId"); + } + if (userDataId == Guid.Empty) + { + throw new ArgumentNullException("userDataId"); + } + + cancellationToken.ThrowIfCancellationRequested(); + return Task.Run(() => { + var serialized = _protobufSerializer.SerializeToBytes(userData); + cancellationToken.ThrowIfCancellationRequested(); var cmd = connection.CreateCommand(); - - cmd.CommandText = "delete from user_data where item_id = @guid"; - cmd.AddParam("@guid", item.UserDataId); - + cmd.CommandText = "replace into userdata (id, userId, data) values (@1, @2, @3)"; + cmd.AddParam("@1", userDataId); + cmd.AddParam("@2", userId); + cmd.AddParam("@3", serialized); QueueCommand(cmd); - - if (item.UserData != null) - { - foreach (var data in item.UserData) - { - cmd = connection.CreateCommand(); - cmd.CommandText = "insert into user_data (item_id, user_id, data) values (@1, @2, @3)"; - cmd.AddParam("@1", item.UserDataId); - cmd.AddParam("@2", data.UserId); - - cmd.AddParam("@3", _protobufSerializer.SerializeToBytes(data)); - - QueueCommand(cmd); - } - } }); } /// <summary> - /// Gets user data for an item + /// Gets the user data. /// </summary> - /// <param name="item">The item.</param> - /// <returns>IEnumerable{UserItemData}.</returns> - /// <exception cref="System.ArgumentNullException">item</exception> - public IEnumerable<UserItemData> RetrieveUserData(BaseItem item) + /// <param name="userId">The user id.</param> + /// <param name="userDataId">The user data id.</param> + /// <returns>Task{UserItemData}.</returns> + /// <exception cref="System.ArgumentNullException"> + /// userId + /// or + /// userDataId + /// </exception> + public async Task<UserItemData> GetUserData(Guid userId, Guid userDataId) { - if (item == null) + if (userId == Guid.Empty) { - throw new ArgumentNullException("item"); + throw new ArgumentNullException("userId"); + } + if (userDataId == Guid.Empty) + { + throw new ArgumentNullException("userDataId"); } var cmd = connection.CreateCommand(); - cmd.CommandText = "select data from user_data where item_id = @guid"; - var guidParam = cmd.Parameters.Add("@guid", DbType.Guid); - guidParam.Value = item.UserDataId; + cmd.CommandText = "select data from userdata where id = @id and userId=@userId"; + + var idParam = cmd.Parameters.Add("@id", DbType.Guid); + idParam.Value = userDataId; - using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)) + var userIdParam = cmd.Parameters.Add("@userId", DbType.Guid); + userIdParam.Value = userId; + + using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult | CommandBehavior.SingleRow).ConfigureAwait(false)) { - while (reader.Read()) + if (reader.Read()) { using (var stream = GetStream(reader, 0)) { - var data = _protobufSerializer.DeserializeFromStream<UserItemData>(stream); - if (data != null) - { - yield return data; - } + return _protobufSerializer.DeserializeFromStream<UserItemData>(stream); } } } + + return null; } } } diff --git a/MediaBrowser.ServerApplication/EntryPoints/WebSocketEvents.cs b/MediaBrowser.ServerApplication/EntryPoints/WebSocketEvents.cs index 50d625739..9ddd14491 100644 --- a/MediaBrowser.ServerApplication/EntryPoints/WebSocketEvents.cs +++ b/MediaBrowser.ServerApplication/EntryPoints/WebSocketEvents.cs @@ -174,7 +174,7 @@ namespace MediaBrowser.ServerApplication.EntryPoints /// <param name="e">The e.</param> async void userManager_UserUpdated(object sender, GenericEventArgs<User> e) { - var dto = await new DtoBuilder(_logger, _libraryManager).GetUserDto(e.Argument).ConfigureAwait(false); + var dto = await new DtoBuilder(_logger, _libraryManager, _userManager).GetUserDto(e.Argument).ConfigureAwait(false); _serverManager.SendWebSocketMessage("UserUpdated", dto); } diff --git a/MediaBrowser.ServerApplication/LibraryExplorer.xaml.cs b/MediaBrowser.ServerApplication/LibraryExplorer.xaml.cs index ca69459be..8811de9db 100644 --- a/MediaBrowser.ServerApplication/LibraryExplorer.xaml.cs +++ b/MediaBrowser.ServerApplication/LibraryExplorer.xaml.cs @@ -33,7 +33,8 @@ namespace MediaBrowser.ServerApplication private readonly IJsonSerializer _jsonSerializer; private readonly ILibraryManager _libraryManager; - + private readonly IUserManager _userManager; + /// <summary> /// The current user /// </summary> @@ -46,6 +47,7 @@ namespace MediaBrowser.ServerApplication _logger = logger; _jsonSerializer = jsonSerializer; _libraryManager = libraryManager; + _userManager = userManager; InitializeComponent(); lblVersion.Content = "Version: " + appHost.ApplicationVersion; @@ -89,7 +91,7 @@ namespace MediaBrowser.ServerApplication var currentFolder = folder; Task.Factory.StartNew(() => { - var prefs = ddlProfile.SelectedItem != null ? currentFolder.GetDisplayPreferences(ddlProfile.SelectedItem as User, false) ?? new DisplayPreferences {SortBy = ItemSortBy.SortName} : new DisplayPreferences {SortBy = ItemSortBy.SortName}; + var prefs = ddlProfile.SelectedItem != null ? _userManager.GetDisplayPreferences((ddlProfile.SelectedItem as User).Id, currentFolder.DisplayPreferencesId).Result ?? new DisplayPreferences { SortBy = ItemSortBy.SortName } : new DisplayPreferences { SortBy = ItemSortBy.SortName }; var node = new TreeViewItem { Tag = currentFolder }; var subChildren = currentFolder.GetChildren(CurrentUser, prefs.IndexBy); @@ -142,7 +144,8 @@ namespace MediaBrowser.ServerApplication var subFolder = item as Folder; if (subFolder != null) { - var prefs = subFolder.GetDisplayPreferences(user, false) ?? new DisplayPreferences {SortBy = LocalizedStrings.Instance.GetString("NameDispPref")}; + var prefs = _userManager.GetDisplayPreferences(user.Id, subFolder.DisplayPreferencesId).Result; + AddChildren(node, OrderBy(subFolder.GetChildren(user), user, prefs.SortBy), user); node.Header = item.Name + " (" + node.Items.Count + ")"; } @@ -196,7 +199,10 @@ namespace MediaBrowser.ServerApplication ItemSortBy.Runtime }; - var prefs = folder.GetDisplayPreferences(ddlProfile.SelectedItem as User, false); + var prefs = + await + _userManager.GetDisplayPreferences((ddlProfile.SelectedItem as User).Id, + folder.DisplayPreferencesId); ddlIndexBy.SelectedItem = prefs != null ? prefs.IndexBy ?? LocalizedStrings.Instance.GetString("NoneDispPref") : LocalizedStrings.Instance.GetString("NoneDispPref"); @@ -354,7 +360,7 @@ namespace MediaBrowser.ServerApplication var folder = treeItem != null ? treeItem.Tag as Folder : null; - var prefs = folder != null ? folder.GetDisplayPreferences(CurrentUser, true) : new DisplayPreferences {SortBy = ItemSortBy.SortName}; + var prefs = folder != null ? _userManager.GetDisplayPreferences(CurrentUser.Id, folder.DisplayPreferencesId).Result : new DisplayPreferences {SortBy = ItemSortBy.SortName}; if (folder != null && prefs.IndexBy != ddlIndexBy.SelectedItem as string) { //grab UI context so we can update within the below task @@ -395,7 +401,7 @@ namespace MediaBrowser.ServerApplication var folder = treeItem != null ? treeItem.Tag as Folder : null; - var prefs = folder != null ? folder.GetDisplayPreferences(CurrentUser, true) : new DisplayPreferences(); + var prefs = folder != null ? _userManager.GetDisplayPreferences(CurrentUser.Id, folder.DisplayPreferencesId).Result : new DisplayPreferences(); if (folder != null && prefs.SortBy != ddlSortBy.SelectedItem as string) { //grab UI context so we can update within the below task diff --git a/MediaBrowser.WebDashboard/Api/DashboardService.cs b/MediaBrowser.WebDashboard/Api/DashboardService.cs index b80b1bffd..f6c64b49e 100644 --- a/MediaBrowser.WebDashboard/Api/DashboardService.cs +++ b/MediaBrowser.WebDashboard/Api/DashboardService.cs @@ -163,7 +163,7 @@ namespace MediaBrowser.WebDashboard.Api { var connections = userManager.RecentConnections.ToArray(); - var dtoBuilder = new DtoBuilder(logger, libraryManager); + var dtoBuilder = new DtoBuilder(logger, libraryManager, userManager); var tasks = userManager.Users.Where(u => connections.Any(c => c.UserId == u.Id)).Select(dtoBuilder.GetUserDto); var users = await Task.WhenAll(tasks).ConfigureAwait(false); |
