diff --git a/MediaBrowser.Api/Images/ImageService.cs b/MediaBrowser.Api/Images/ImageService.cs index cb26688e39..07bbaff749 100644 --- a/MediaBrowser.Api/Images/ImageService.cs +++ b/MediaBrowser.Api/Images/ImageService.cs @@ -2,6 +2,7 @@ using MediaBrowser.Common.IO; using MediaBrowser.Common.Net; using MediaBrowser.Controller; +using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; using MediaBrowser.Model.Entities; diff --git a/MediaBrowser.Api/Library/LibraryService.cs b/MediaBrowser.Api/Library/LibraryService.cs index 9c68df7712..5b34119dea 100644 --- a/MediaBrowser.Api/Library/LibraryService.cs +++ b/MediaBrowser.Api/Library/LibraryService.cs @@ -1,6 +1,8 @@ using MediaBrowser.Common; +using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Persistence; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Querying; using ServiceStack.ServiceHost; @@ -104,16 +106,16 @@ namespace MediaBrowser.Api.Library /// private readonly IApplicationHost _appHost; private readonly ILibraryManager _libraryManager; - private readonly IUserManager _userManager; + private readonly IUserDataRepository _userDataRepository; /// /// Initializes a new instance of the class. /// /// The app host. /// The library manager. - /// The user manager. + /// The user data repository. /// appHost - public LibraryService(IApplicationHost appHost, ILibraryManager libraryManager, IUserManager userManager) + public LibraryService(IApplicationHost appHost, ILibraryManager libraryManager, IUserDataRepository userDataRepository) { if (appHost == null) { @@ -122,7 +124,7 @@ namespace MediaBrowser.Api.Library _appHost = appHost; _libraryManager = libraryManager; - _userManager = userManager; + _userDataRepository = userDataRepository; } /// @@ -137,7 +139,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, _userManager).GetBaseItemDto(item, fields.ToList()).Result; + var result = new DtoBuilder(Logger, _libraryManager, _userDataRepository).GetBaseItemDto(item, fields.ToList()).Result; return ToOptimizedResult(result); } @@ -154,7 +156,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, _userManager).GetBaseItemDto(item, fields.ToList()).Result; + var result = new DtoBuilder(Logger, _libraryManager, _userDataRepository).GetBaseItemDto(item, fields.ToList()).Result; return ToOptimizedResult(result); } @@ -171,7 +173,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, _userManager).GetBaseItemDto(item, fields.ToList()).Result; + var result = new DtoBuilder(Logger, _libraryManager, _userDataRepository).GetBaseItemDto(item, fields.ToList()).Result; return ToOptimizedResult(result); } @@ -188,7 +190,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, _userManager).GetBaseItemDto(item, fields.ToList()).Result; + var result = new DtoBuilder(Logger, _libraryManager, _userDataRepository).GetBaseItemDto(item, fields.ToList()).Result; return ToOptimizedResult(result); } diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index 3c6731e71f..1510dd472f 100644 --- a/MediaBrowser.Api/Playback/BaseStreamingService.cs +++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs @@ -2,6 +2,7 @@ using MediaBrowser.Common.IO; using MediaBrowser.Common.MediaInfo; using MediaBrowser.Controller; +using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Providers.MediaInfo; diff --git a/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs b/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs index 6801e14f0a..42aafd2cd2 100644 --- a/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs +++ b/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs @@ -1,6 +1,7 @@ -using System.Threading; +using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Persistence; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Querying; using ServiceStack.ServiceHost; @@ -8,6 +9,7 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; +using System.Threading; using System.Threading.Tasks; namespace MediaBrowser.Api.UserLibrary @@ -27,16 +29,19 @@ namespace MediaBrowser.Api.UserLibrary /// The library manager /// protected readonly ILibraryManager LibraryManager; + protected readonly IUserDataRepository UserDataRepository; /// /// Initializes a new instance of the class. /// /// The user manager. /// The library manager. - protected BaseItemsByNameService(IUserManager userManager, ILibraryManager libraryManager) + /// The user data repository. + protected BaseItemsByNameService(IUserManager userManager, ILibraryManager libraryManager, IUserDataRepository userDataRepository) { UserManager = userManager; LibraryManager = libraryManager; + UserDataRepository = userDataRepository; } /// @@ -132,18 +137,19 @@ namespace MediaBrowser.Api.UserLibrary /// IEnumerable{BaseItem}. private IEnumerable FilterItems(GetItemsByName request, IEnumerable items, User user) { - items = items.AsParallel(); - - items = ItemsService.ApplyAdditionalFilters(request, items); - - // Apply filters - // Run them starting with the ones that are likely to reduce the list the most - foreach (var filter in request.GetFilters().OrderByDescending(f => (int)f)) + // Exclude item types + if (!string.IsNullOrEmpty(request.ExcludeItemTypes)) { - items = ItemsService.ApplyFilter(items, filter, user, UserManager); + var vals = request.ExcludeItemTypes.Split(','); + items = items.Where(f => !vals.Contains(f.GetType().Name, StringComparer.OrdinalIgnoreCase)); } - items = items.AsEnumerable(); + // Include item types + if (!string.IsNullOrEmpty(request.IncludeItemTypes)) + { + var vals = request.IncludeItemTypes.Split(','); + items = items.Where(f => vals.Contains(f.GetType().Name, StringComparer.OrdinalIgnoreCase)); + } return items; } @@ -185,7 +191,7 @@ namespace MediaBrowser.Api.UserLibrary return null; } - var dto = await new DtoBuilder(Logger, LibraryManager, UserManager).GetBaseItemDto(item, user, fields).ConfigureAwait(false); + var dto = await new DtoBuilder(Logger, LibraryManager, UserDataRepository).GetBaseItemDto(item, user, fields).ConfigureAwait(false); if (fields.Contains(ItemFields.ItemCounts)) { @@ -211,13 +217,15 @@ namespace MediaBrowser.Api.UserLibrary var item = await getItem().ConfigureAwait(false); + var key = item.GetUserDataKey(); + // Get the user data for this item - var data = await UserManager.GetUserData(user.Id, item.UserDataId).ConfigureAwait(false); + var data = await UserDataRepository.GetUserData(user.Id, key).ConfigureAwait(false); // Set favorite status data.IsFavorite = isFavorite; - await UserManager.SaveUserData(user.Id, item.UserDataId, data, CancellationToken.None).ConfigureAwait(false); + await UserDataRepository.SaveUserData(user.Id, key, data, CancellationToken.None).ConfigureAwait(false); } } diff --git a/MediaBrowser.Api/UserLibrary/GenresService.cs b/MediaBrowser.Api/UserLibrary/GenresService.cs index 54561f4005..e275b6ed03 100644 --- a/MediaBrowser.Api/UserLibrary/GenresService.cs +++ b/MediaBrowser.Api/UserLibrary/GenresService.cs @@ -1,6 +1,6 @@ -using System.Threading; -using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Persistence; using ServiceStack.ServiceHost; using System; using System.Collections.Generic; @@ -18,52 +18,14 @@ namespace MediaBrowser.Api.UserLibrary public class GetGenres : GetItemsByName { } - - [Route("/Users/{UserId}/FavoriteGenres/{Name}", "POST")] - [Api(Description = "Marks a genre as a favorite")] - public class MarkFavoriteGenre : IReturnVoid - { - /// - /// Gets or sets the user id. - /// - /// The user id. - [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")] - public Guid UserId { get; set; } - - /// - /// Gets or sets the name. - /// - /// The name. - [ApiMember(Name = "Name", Description = "Name", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")] - public string Name { get; set; } - } - - [Route("/Users/{UserId}/FavoriteGenres/{Name}", "DELETE")] - [Api(Description = "Unmarks a genre as a favorite")] - public class UnmarkFavoriteGenre : IReturnVoid - { - /// - /// Gets or sets the user id. - /// - /// The user id. - [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")] - public Guid UserId { get; set; } - - /// - /// Gets or sets the name. - /// - /// The name. - [ApiMember(Name = "Name", Description = "Name", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")] - public string Name { get; set; } - } /// /// Class GenresService /// public class GenresService : BaseItemsByNameService { - public GenresService(IUserManager userManager, ILibraryManager libraryManager) - : base(userManager, libraryManager) + public GenresService(IUserManager userManager, ILibraryManager libraryManager, IUserDataRepository userDataRepository) + : base(userManager, libraryManager, userDataRepository) { } @@ -79,28 +41,6 @@ namespace MediaBrowser.Api.UserLibrary return ToOptimizedResult(result); } - /// - /// Posts the specified request. - /// - /// The request. - public void Post(MarkFavoriteGenre request) - { - var task = MarkFavorite(() => LibraryManager.GetGenre(request.Name), request.UserId, true); - - Task.WaitAll(task); - } - - /// - /// Deletes the specified request. - /// - /// The request. - public void Delete(UnmarkFavoriteGenre request) - { - var task = MarkFavorite(() => LibraryManager.GetGenre(request.Name), request.UserId, false); - - Task.WaitAll(task); - } - /// /// Gets all items. /// diff --git a/MediaBrowser.Api/UserLibrary/ItemsService.cs b/MediaBrowser.Api/UserLibrary/ItemsService.cs index aed84e07f2..675ac0cd55 100644 --- a/MediaBrowser.Api/UserLibrary/ItemsService.cs +++ b/MediaBrowser.Api/UserLibrary/ItemsService.cs @@ -1,6 +1,8 @@ -using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Dto; +using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Persistence; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Querying; using ServiceStack.ServiceHost; @@ -148,6 +150,7 @@ namespace MediaBrowser.Api.UserLibrary /// The _user manager /// private readonly IUserManager _userManager; + private readonly IUserDataRepository _userDataRepository; /// /// The _library manager @@ -161,11 +164,13 @@ namespace MediaBrowser.Api.UserLibrary /// The user manager. /// The library manager. /// The search engine. - public ItemsService(IUserManager userManager, ILibraryManager libraryManager, ILibrarySearchEngine searchEngine) + /// The user data repository. + public ItemsService(IUserManager userManager, ILibraryManager libraryManager, ILibrarySearchEngine searchEngine, IUserDataRepository userDataRepository) { _userManager = userManager; _libraryManager = libraryManager; _searchEngine = searchEngine; + _userDataRepository = userDataRepository; } /// @@ -199,7 +204,7 @@ namespace MediaBrowser.Api.UserLibrary // Run them starting with the ones that are likely to reduce the list the most foreach (var filter in request.GetFilters().OrderByDescending(f => (int)f)) { - items = ApplyFilter(items, filter, user, _userManager); + items = ApplyFilter(items, filter, user, _userDataRepository); } items = items.AsEnumerable(); @@ -214,7 +219,7 @@ namespace MediaBrowser.Api.UserLibrary var fields = request.GetItemFields().ToList(); - var dtoBuilder = new DtoBuilder(Logger, _libraryManager, _userManager); + var dtoBuilder = new DtoBuilder(Logger, _libraryManager, _userDataRepository); var returnItems = await Task.WhenAll(pagedItems.Select(i => dtoBuilder.GetBaseItemDto(i, user, fields))).ConfigureAwait(false); @@ -274,9 +279,9 @@ namespace MediaBrowser.Api.UserLibrary /// The items. /// The filter. /// The user. - /// The user manager. + /// The repository. /// IEnumerable{BaseItem}. - internal static IEnumerable ApplyFilter(IEnumerable items, ItemFilter filter, User user, IUserManager userManager) + internal static IEnumerable ApplyFilter(IEnumerable items, ItemFilter filter, User user, IUserDataRepository repository) { // Avoids implicitly captured closure var currentUser = user; @@ -286,7 +291,7 @@ namespace MediaBrowser.Api.UserLibrary case ItemFilter.Likes: return items.Where(item => { - var userdata = userManager.GetUserData(user.Id, item.UserDataId).Result; + var userdata = repository.GetUserData(user.Id, item.GetUserDataKey()).Result; return userdata != null && userdata.Likes.HasValue && userdata.Likes.Value; }); @@ -294,7 +299,7 @@ namespace MediaBrowser.Api.UserLibrary case ItemFilter.Dislikes: return items.Where(item => { - var userdata = userManager.GetUserData(user.Id, item.UserDataId).Result; + var userdata = repository.GetUserData(user.Id, item.GetUserDataKey()).Result; return userdata != null && userdata.Likes.HasValue && !userdata.Likes.Value; }); @@ -302,7 +307,7 @@ namespace MediaBrowser.Api.UserLibrary case ItemFilter.IsFavorite: return items.Where(item => { - var userdata = userManager.GetUserData(user.Id, item.UserDataId).Result; + var userdata = repository.GetUserData(user.Id, item.GetUserDataKey()).Result; return userdata != null && userdata.IsFavorite; }); @@ -313,7 +318,7 @@ namespace MediaBrowser.Api.UserLibrary case ItemFilter.IsResumable: return items.Where(item => { - var userdata = userManager.GetUserData(user.Id, item.UserDataId).Result; + var userdata = repository.GetUserData(user.Id, item.GetUserDataKey()).Result; return userdata != null && userdata.PlaybackPositionTicks > 0; }); @@ -321,7 +326,7 @@ namespace MediaBrowser.Api.UserLibrary case ItemFilter.IsPlayed: return items.Where(item => { - var userdata = userManager.GetUserData(user.Id, item.UserDataId).Result; + var userdata = repository.GetUserData(user.Id, item.GetUserDataKey()).Result; return userdata != null && userdata.PlayCount > 0; }); @@ -329,7 +334,7 @@ namespace MediaBrowser.Api.UserLibrary case ItemFilter.IsUnplayed: return items.Where(item => { - var userdata = userManager.GetUserData(user.Id, item.UserDataId).Result; + var userdata = repository.GetUserData(user.Id, item.GetUserDataKey()).Result; return userdata == null || userdata.PlayCount == 0; }); @@ -347,32 +352,11 @@ namespace MediaBrowser.Api.UserLibrary /// /// Applies the additional filters. /// - /// The items request. + /// The request. /// The items. /// IEnumerable{BaseItem}. - internal static IEnumerable ApplyAdditionalFilters(BaseItemsRequest itemsRequest, IEnumerable items) + internal static IEnumerable ApplyAdditionalFilters(GetItems request, IEnumerable items) { - // Exclude item types - if (!string.IsNullOrEmpty(itemsRequest.ExcludeItemTypes)) - { - var vals = itemsRequest.ExcludeItemTypes.Split(','); - items = items.Where(f => !vals.Contains(f.GetType().Name, StringComparer.OrdinalIgnoreCase)); - } - - // Include item types - if (!string.IsNullOrEmpty(itemsRequest.IncludeItemTypes)) - { - var vals = itemsRequest.IncludeItemTypes.Split(','); - items = items.Where(f => vals.Contains(f.GetType().Name, StringComparer.OrdinalIgnoreCase)); - } - - var request = itemsRequest as GetItems; - - if (request == null) - { - return items; - } - // Filter by Series Status if (!string.IsNullOrEmpty(request.SeriesStatus)) { diff --git a/MediaBrowser.Api/UserLibrary/PersonsService.cs b/MediaBrowser.Api/UserLibrary/PersonsService.cs index 4253ddc804..974b8c0027 100644 --- a/MediaBrowser.Api/UserLibrary/PersonsService.cs +++ b/MediaBrowser.Api/UserLibrary/PersonsService.cs @@ -1,5 +1,6 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Persistence; using ServiceStack.ServiceHost; using System; using System.Collections.Generic; @@ -22,52 +23,14 @@ namespace MediaBrowser.Api.UserLibrary /// The person types. public string PersonTypes { get; set; } } - - [Route("/Users/{UserId}/FavoritePersons/{Name}", "POST")] - [Api(Description = "Marks a person as a favorite")] - public class MarkFavoritePerson : IReturnVoid - { - /// - /// Gets or sets the user id. - /// - /// The user id. - [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")] - public Guid UserId { get; set; } - - /// - /// Gets or sets the name. - /// - /// The name. - [ApiMember(Name = "Name", Description = "Name", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")] - public string Name { get; set; } - } - - [Route("/Users/{UserId}/FavoritePersons/{Name}", "DELETE")] - [Api(Description = "Unmarks a person as a favorite")] - public class UnmarkFavoritePerson : IReturnVoid - { - /// - /// Gets or sets the user id. - /// - /// The user id. - [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")] - public Guid UserId { get; set; } - - /// - /// Gets or sets the name. - /// - /// The name. - [ApiMember(Name = "Name", Description = "Name", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")] - public string Name { get; set; } - } /// /// Class PersonsService /// public class PersonsService : BaseItemsByNameService { - public PersonsService(IUserManager userManager, ILibraryManager libraryManager) - : base(userManager, libraryManager) + public PersonsService(IUserManager userManager, ILibraryManager libraryManager, IUserDataRepository userDataRepository) + : base(userManager, libraryManager, userDataRepository) { } @@ -83,28 +46,6 @@ namespace MediaBrowser.Api.UserLibrary return ToOptimizedResult(result); } - /// - /// Posts the specified request. - /// - /// The request. - public void Post(MarkFavoritePerson request) - { - var task = MarkFavorite(() => LibraryManager.GetPerson(request.Name), request.UserId, true); - - Task.WaitAll(task); - } - - /// - /// Deletes the specified request. - /// - /// The request. - public void Delete(UnmarkFavoritePerson request) - { - var task = MarkFavorite(() => LibraryManager.GetPerson(request.Name), request.UserId, false); - - Task.WaitAll(task); - } - /// /// Gets all items. /// diff --git a/MediaBrowser.Api/UserLibrary/StudiosService.cs b/MediaBrowser.Api/UserLibrary/StudiosService.cs index 24f09c5ef7..77f20d8e85 100644 --- a/MediaBrowser.Api/UserLibrary/StudiosService.cs +++ b/MediaBrowser.Api/UserLibrary/StudiosService.cs @@ -1,5 +1,6 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Persistence; using ServiceStack.ServiceHost; using System; using System.Collections.Generic; @@ -17,52 +18,14 @@ namespace MediaBrowser.Api.UserLibrary public class GetStudios : GetItemsByName { } - - [Route("/Users/{UserId}/FavoriteStudios/{Name}", "POST")] - [Api(Description = "Marks a studio as a favorite")] - public class MarkFavoriteStudio : IReturnVoid - { - /// - /// Gets or sets the user id. - /// - /// The user id. - [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")] - public Guid UserId { get; set; } - - /// - /// Gets or sets the name. - /// - /// The name. - [ApiMember(Name = "Name", Description = "Name", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")] - public string Name { get; set; } - } - - [Route("/Users/{UserId}/FavoriteStudios/{Name}", "DELETE")] - [Api(Description = "Unmarks a studio as a favorite")] - public class UnmarkFavoriteStudio : IReturnVoid - { - /// - /// Gets or sets the user id. - /// - /// The user id. - [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")] - public Guid UserId { get; set; } - - /// - /// Gets or sets the name. - /// - /// The name. - [ApiMember(Name = "Name", Description = "Name", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")] - public string Name { get; set; } - } /// /// Class StudiosService /// public class StudiosService : BaseItemsByNameService { - public StudiosService(IUserManager userManager, ILibraryManager libraryManager) - : base(userManager, libraryManager) + public StudiosService(IUserManager userManager, ILibraryManager libraryManager, IUserDataRepository userDataRepository) + : base(userManager, libraryManager, userDataRepository) { } @@ -77,28 +40,6 @@ namespace MediaBrowser.Api.UserLibrary return ToOptimizedResult(result); } - - /// - /// Posts the specified request. - /// - /// The request. - public void Post(MarkFavoriteStudio request) - { - var task = MarkFavorite(() => LibraryManager.GetStudio(request.Name), request.UserId, true); - - Task.WaitAll(task); - } - - /// - /// Deletes the specified request. - /// - /// The request. - public void Delete(UnmarkFavoriteStudio request) - { - var task = MarkFavorite(() => LibraryManager.GetStudio(request.Name), request.UserId, false); - - Task.WaitAll(task); - } /// /// Gets all items. diff --git a/MediaBrowser.Api/UserLibrary/UserLibraryService.cs b/MediaBrowser.Api/UserLibrary/UserLibraryService.cs index e24e638196..70e5287a1c 100644 --- a/MediaBrowser.Api/UserLibrary/UserLibraryService.cs +++ b/MediaBrowser.Api/UserLibrary/UserLibraryService.cs @@ -1,6 +1,8 @@ -using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Dto; +using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Persistence; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Querying; using ServiceStack.ServiceHost; @@ -335,18 +337,19 @@ namespace MediaBrowser.Api.UserLibrary /// The _user manager /// private readonly IUserManager _userManager; - + private readonly IUserDataRepository _userDataRepository; private readonly ILibraryManager _libraryManager; /// /// Initializes a new instance of the class. /// /// jsonSerializer - public UserLibraryService(IUserManager userManager, ILibraryManager libraryManager) + public UserLibraryService(IUserManager userManager, ILibraryManager libraryManager, IUserDataRepository userDataRepository) : base() { _userManager = userManager; _libraryManager = libraryManager; + _userDataRepository = userDataRepository; } /// @@ -365,7 +368,7 @@ namespace MediaBrowser.Api.UserLibrary var movie = (Movie)item; - var dtoBuilder = new DtoBuilder(Logger, _libraryManager, _userManager); + var dtoBuilder = new DtoBuilder(Logger, _libraryManager, _userDataRepository); var items = movie.SpecialFeatures.Select(i => dtoBuilder.GetBaseItemDto(i, user, fields)).AsParallel().Select(t => t.Result).ToList(); @@ -386,7 +389,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, _userManager); + var dtoBuilder = new DtoBuilder(Logger, _libraryManager, _userDataRepository); var items = item.LocalTrailers.Select(i => dtoBuilder.GetBaseItemDto(i, user, fields)).AsParallel().Select(t => t.Result).ToList(); @@ -407,7 +410,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, _userManager); + var dtoBuilder = new DtoBuilder(Logger, _libraryManager, _userDataRepository); var result = dtoBuilder.GetBaseItemDto(item, user, fields).Result; @@ -423,7 +426,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, _userManager); + var dtoBuilder = new DtoBuilder(Logger, _libraryManager, _userDataRepository); var result = dtoBuilder.GetBaseItemDto(item, user, fields).Result; @@ -457,12 +460,14 @@ 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 = _userManager.GetUserData(user.Id, item.UserDataId).Result; + var key = item.GetUserDataKey(); + + var data = _userDataRepository.GetUserData(user.Id, key).Result; // Set favorite status data.IsFavorite = true; - var task = _userManager.SaveUserData(user.Id, item.UserDataId, data, CancellationToken.None); + var task = _userDataRepository.SaveUserData(user.Id, key, data, CancellationToken.None); Task.WaitAll(task); } @@ -477,13 +482,15 @@ namespace MediaBrowser.Api.UserLibrary var item = string.IsNullOrEmpty(request.Id) ? user.RootFolder : DtoBuilder.GetItemByClientId(request.Id, _userManager, _libraryManager, user.Id); + var key = item.GetUserDataKey(); + // Get the user data for this item - var data = _userManager.GetUserData(user.Id, item.UserDataId).Result; + var data = _userDataRepository.GetUserData(user.Id, key).Result; // Set favorite status data.IsFavorite = false; - var task = _userManager.SaveUserData(user.Id, item.UserDataId, data, CancellationToken.None); + var task = _userDataRepository.SaveUserData(user.Id, key, data, CancellationToken.None); Task.WaitAll(task); } @@ -498,12 +505,14 @@ namespace MediaBrowser.Api.UserLibrary var item = string.IsNullOrEmpty(request.Id) ? user.RootFolder : DtoBuilder.GetItemByClientId(request.Id, _userManager, _libraryManager, user.Id); + var key = item.GetUserDataKey(); + // Get the user data for this item - var data = _userManager.GetUserData(user.Id, item.UserDataId).Result; + var data = _userDataRepository.GetUserData(user.Id, key).Result; data.Rating = null; - var task = _userManager.SaveUserData(user.Id, item.UserDataId, data, CancellationToken.None); + var task = _userDataRepository.SaveUserData(user.Id, key, data, CancellationToken.None); Task.WaitAll(task); } @@ -518,12 +527,14 @@ namespace MediaBrowser.Api.UserLibrary var item = string.IsNullOrEmpty(request.Id) ? user.RootFolder : DtoBuilder.GetItemByClientId(request.Id, _userManager, _libraryManager, user.Id); + var key = item.GetUserDataKey(); + // Get the user data for this item - var data = _userManager.GetUserData(user.Id, item.UserDataId).Result; + var data = _userDataRepository.GetUserData(user.Id, key).Result; data.Likes = request.Likes; - var task = _userManager.SaveUserData(user.Id, item.UserDataId, data, CancellationToken.None); + var task = _userDataRepository.SaveUserData(user.Id, key, data, CancellationToken.None); Task.WaitAll(task); } @@ -623,7 +634,7 @@ namespace MediaBrowser.Api.UserLibrary { var item = DtoBuilder.GetItemByClientId(itemId, _userManager, _libraryManager, user.Id); - return item.SetPlayedStatus(user, wasPlayed, _userManager); + return item.SetPlayedStatus(user, wasPlayed, _userDataRepository); } } } diff --git a/MediaBrowser.Api/UserLibrary/YearsService.cs b/MediaBrowser.Api/UserLibrary/YearsService.cs index f2cf367507..481645c242 100644 --- a/MediaBrowser.Api/UserLibrary/YearsService.cs +++ b/MediaBrowser.Api/UserLibrary/YearsService.cs @@ -1,5 +1,6 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Persistence; using ServiceStack.ServiceHost; using System; using System.Collections.Generic; @@ -28,9 +29,9 @@ namespace MediaBrowser.Api.UserLibrary /// The us culture /// private static readonly CultureInfo UsCulture = new CultureInfo("en-US"); - - public YearsService(IUserManager userManager, ILibraryManager libraryManager) - : base(userManager, libraryManager) + + public YearsService(IUserManager userManager, ILibraryManager libraryManager, IUserDataRepository userDataRepository) + : base(userManager, libraryManager, userDataRepository) { } diff --git a/MediaBrowser.Api/UserService.cs b/MediaBrowser.Api/UserService.cs index 76c67cd2f8..3f3af743d1 100644 --- a/MediaBrowser.Api/UserService.cs +++ b/MediaBrowser.Api/UserService.cs @@ -1,4 +1,5 @@ using MediaBrowser.Common.Extensions; +using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Library; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Serialization; @@ -165,7 +166,7 @@ namespace MediaBrowser.Api /// System.Object. public object Get(GetUsers request) { - var dtoBuilder = new DtoBuilder(Logger, _libraryManager, _userManager); + var dtoBuilder = new UserDtoBuilder(Logger); var users = _userManager.Users.OrderBy(u => u.Name).Select(dtoBuilder.GetUserDto).ToArray(); @@ -186,7 +187,9 @@ namespace MediaBrowser.Api throw new ResourceNotFoundException("User not found"); } - var result = new DtoBuilder(Logger, _libraryManager, _userManager).GetUserDto(user); + var dtoBuilder = new UserDtoBuilder(Logger); + + var result = dtoBuilder.GetUserDto(user); return ToOptimizedResult(result); } @@ -300,7 +303,9 @@ namespace MediaBrowser.Api newUser.UpdateConfiguration(dtoUser.Configuration, _xmlSerializer); - var result = new DtoBuilder(Logger, _libraryManager, _userManager).GetUserDto(newUser); + var dtoBuilder = new UserDtoBuilder(Logger); + + var result = dtoBuilder.GetUserDto(newUser); return ToOptimizedResult(result); } diff --git a/MediaBrowser.Common/Extensions/BaseExtensions.cs b/MediaBrowser.Common/Extensions/BaseExtensions.cs index 9591862e76..b4ad901689 100644 --- a/MediaBrowser.Common/Extensions/BaseExtensions.cs +++ b/MediaBrowser.Common/Extensions/BaseExtensions.cs @@ -1,6 +1,4 @@ using System; -using System.Collections.Generic; -using System.Linq; using System.Security.Cryptography; using System.Text; using System.Text.RegularExpressions; @@ -55,26 +53,6 @@ namespace MediaBrowser.Common.Extensions return (aType.FullName + str.ToLower()).GetMD5(); } - /// - /// Helper method for Dictionaries since they throw on not-found keys - /// - /// - /// - /// The dictionary. - /// The key. - /// The default value. - /// ``1. - public static U GetValueOrDefault(this Dictionary dictionary, T key, U defaultValue) - { - U val; - if (!dictionary.TryGetValue(key, out val)) - { - val = defaultValue; - } - return val; - - } - /// /// Gets the attribute value. /// diff --git a/MediaBrowser.Common/Plugins/BasePlugin.cs b/MediaBrowser.Common/Plugins/BasePlugin.cs index ca2891734e..f90cd2c0fe 100644 --- a/MediaBrowser.Common/Plugins/BasePlugin.cs +++ b/MediaBrowser.Common/Plugins/BasePlugin.cs @@ -302,7 +302,7 @@ namespace MediaBrowser.Common.Plugins AssemblyFileName = AssemblyFileName, ConfigurationDateLastModified = ConfigurationDateLastModified, Description = Description, - Id = Id, + Id = Id.ToString(), EnableAutoUpdate = Configuration.EnableAutoUpdate, UpdateClass = Configuration.UpdateClass, ConfigurationFileName = ConfigurationFileName diff --git a/MediaBrowser.Controller/Library/DtoBuilder.cs b/MediaBrowser.Controller/Dto/DtoBuilder.cs similarity index 93% rename from MediaBrowser.Controller/Library/DtoBuilder.cs rename to MediaBrowser.Controller/Dto/DtoBuilder.cs index 7f9a6f1879..0da4da356b 100644 --- a/MediaBrowser.Controller/Library/DtoBuilder.cs +++ b/MediaBrowser.Controller/Dto/DtoBuilder.cs @@ -3,6 +3,8 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Entities.TV; +using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Persistence; using MediaBrowser.Model.Drawing; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; @@ -14,7 +16,7 @@ using System.IO; using System.Linq; using System.Threading.Tasks; -namespace MediaBrowser.Controller.Library +namespace MediaBrowser.Controller.Dto { /// /// Generates DTO's from domain entities @@ -28,13 +30,13 @@ namespace MediaBrowser.Controller.Library private readonly ILogger _logger; private readonly ILibraryManager _libraryManager; - private readonly IUserManager _userManager; + private readonly IUserDataRepository _userDataRepository; - public DtoBuilder(ILogger logger, ILibraryManager libraryManager, IUserManager userManager) + public DtoBuilder(ILogger logger, ILibraryManager libraryManager, IUserDataRepository userDataRepository) { _logger = logger; _libraryManager = libraryManager; - _userManager = userManager; + _userDataRepository = userDataRepository; } /// @@ -73,7 +75,7 @@ namespace MediaBrowser.Controller.Library { try { - AttachPrimaryImageAspectRatio(dto, item); + AttachPrimaryImageAspectRatio(dto, item, _logger); } catch (Exception ex) { @@ -136,7 +138,7 @@ namespace MediaBrowser.Controller.Library { try { - AttachPrimaryImageAspectRatio(dto, item); + AttachPrimaryImageAspectRatio(dto, item, _logger); } catch (Exception ex) { @@ -167,7 +169,7 @@ namespace MediaBrowser.Controller.Library { if (fields.Contains(ItemFields.UserData)) { - var userData = await _userManager.GetUserData(user.Id, item.UserDataId).ConfigureAwait(false); + var userData = await _userDataRepository.GetUserData(user.Id, item.GetUserDataKey()).ConfigureAwait(false); dto.UserData = GetUserItemDataDto(userData); } @@ -186,18 +188,19 @@ namespace MediaBrowser.Controller.Library // Skip sorting since all we want is a count dto.ChildCount = folder.GetChildren(user).Count(); - await SetSpecialCounts(folder, user, dto, _userManager).ConfigureAwait(false); + await SetSpecialCounts(folder, user, dto, _userDataRepository).ConfigureAwait(false); } } } - + /// /// Attaches the primary image aspect ratio. /// /// The dto. /// The item. + /// The _logger. /// Task. - private void AttachPrimaryImageAspectRatio(IItemDto dto, BaseItem item) + internal static void AttachPrimaryImageAspectRatio(IItemDto dto, BaseItem item, ILogger _logger) { var path = item.PrimaryImagePath; @@ -503,9 +506,9 @@ namespace MediaBrowser.Controller.Library /// The folder. /// The user. /// The dto. - /// The user manager. + /// The user data repository. /// Task. - private static async Task SetSpecialCounts(Folder folder, User user, BaseItemDto dto, IUserManager userManager) + private static async Task SetSpecialCounts(Folder folder, User user, BaseItemDto dto, IUserDataRepository userDataRepository) { var rcentlyAddedItemCount = 0; var recursiveItemCount = 0; @@ -515,7 +518,7 @@ namespace MediaBrowser.Controller.Library // Loop through each recursive child foreach (var child in folder.GetRecursiveChildren(user).Where(i => !i.IsFolder)) { - var userdata = await userManager.GetUserData(user.Id, child.UserDataId).ConfigureAwait(false); + var userdata = await userDataRepository.GetUserData(user.Id, child.GetUserDataKey()).ConfigureAwait(false); recursiveItemCount++; @@ -785,49 +788,6 @@ namespace MediaBrowser.Controller.Library return item.Id.ToString(); } - /// - /// Converts a User to a DTOUser - /// - /// The user. - /// DtoUser. - /// user - public UserDto GetUserDto(User user) - { - if (user == null) - { - throw new ArgumentNullException("user"); - } - - var dto = new UserDto - { - Id = user.Id, - Name = user.Name, - HasPassword = !String.IsNullOrEmpty(user.Password), - LastActivityDate = user.LastActivityDate, - LastLoginDate = user.LastLoginDate, - Configuration = user.Configuration - }; - - var image = user.PrimaryImagePath; - - if (!string.IsNullOrEmpty(image)) - { - dto.PrimaryImageTag = Kernel.Instance.ImageManager.GetImageCacheTag(user, ImageType.Primary, image); - - try - { - AttachPrimaryImageAspectRatio(dto, user); - } - catch (Exception ex) - { - // Have to use a catch-all unfortunately because some .net image methods throw plain Exceptions - _logger.ErrorException("Error generating PrimaryImageAspectRatio for {0}", ex, user.Name); - } - } - - return dto; - } - /// /// Gets a BaseItem based upon it's client-side item id /// diff --git a/MediaBrowser.Controller/Dto/UserDtoBuilder.cs b/MediaBrowser.Controller/Dto/UserDtoBuilder.cs new file mode 100644 index 0000000000..5c717529ae --- /dev/null +++ b/MediaBrowser.Controller/Dto/UserDtoBuilder.cs @@ -0,0 +1,71 @@ +using MediaBrowser.Controller.Entities; +using MediaBrowser.Model.Dto; +using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Logging; +using System; + +namespace MediaBrowser.Controller.Dto +{ + /// + /// Class UserDtoBuilder + /// + public class UserDtoBuilder + { + /// + /// The _logger + /// + private readonly ILogger _logger; + + /// + /// Initializes a new instance of the class. + /// + /// The logger. + public UserDtoBuilder(ILogger logger) + { + _logger = logger; + } + + /// + /// Converts a User to a DTOUser + /// + /// The user. + /// DtoUser. + /// user + public UserDto GetUserDto(User user) + { + if (user == null) + { + throw new ArgumentNullException("user"); + } + + var dto = new UserDto + { + Id = user.Id.ToString(), + Name = user.Name, + HasPassword = !String.IsNullOrEmpty(user.Password), + LastActivityDate = user.LastActivityDate, + LastLoginDate = user.LastLoginDate, + Configuration = user.Configuration + }; + + var image = user.PrimaryImagePath; + + if (!string.IsNullOrEmpty(image)) + { + dto.PrimaryImageTag = Kernel.Instance.ImageManager.GetImageCacheTag(user, ImageType.Primary, image); + + try + { + DtoBuilder.AttachPrimaryImageAspectRatio(dto, user, _logger); + } + catch (Exception ex) + { + // Have to use a catch-all unfortunately because some .net image methods throw plain Exceptions + _logger.ErrorException("Error generating PrimaryImageAspectRatio for {0}", ex, user.Name); + } + } + + return dto; + } + } +} diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index 2cb8ac7949..ccaabd4382 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -3,6 +3,7 @@ using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.IO; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Localization; +using MediaBrowser.Controller.Persistence; using MediaBrowser.Controller.Providers; using MediaBrowser.Controller.Resolvers; using MediaBrowser.Model.Entities; @@ -183,23 +184,18 @@ namespace MediaBrowser.Controller.Entities /// /// The _file system stamp /// - private Guid? _fileSystemStamp; + private string _fileSystemStamp; /// /// Gets a directory stamp, in the form of a string, that can be used for /// comparison purposes to determine if the file system entries for this item have changed. /// /// The file system stamp. [IgnoreDataMember] - public Guid FileSystemStamp + public string FileSystemStamp { get { - if (!_fileSystemStamp.HasValue) - { - _fileSystemStamp = GetFileSystemStamp(); - } - - return _fileSystemStamp.Value; + return _fileSystemStamp ?? (_fileSystemStamp = GetFileSystemStamp()); } } @@ -221,12 +217,12 @@ namespace MediaBrowser.Controller.Entities /// comparison purposes to determine if the file system entries for this item have changed. /// /// Guid. - private Guid GetFileSystemStamp() + private string GetFileSystemStamp() { // If there's no path or the item is a file, there's nothing to do if (LocationType != LocationType.FileSystem || !ResolveArgs.IsDirectory) { - return Guid.Empty; + return string.Empty; } var sb = new StringBuilder(); @@ -242,7 +238,7 @@ namespace MediaBrowser.Controller.Entities sb.Append(file.cFileName); } - return sb.ToString().GetMD5(); + return sb.ToString(); } /// @@ -820,21 +816,12 @@ namespace MediaBrowser.Controller.Entities } /// - /// The _user data id + /// Gets the user data key. /// - protected Guid _userDataId; //cache this so it doesn't have to be re-constructed on every reference - /// - /// Return the id that should be used to key user data for this item. - /// Default is just this Id but subclasses can use provider Ids for transportability. - /// - /// The user data id. - [IgnoreDataMember] - public virtual Guid UserDataId + /// System.String. + public virtual string GetUserDataKey() { - get - { - return _userDataId == Guid.Empty ? (_userDataId = Id) : _userDataId; - } + return Id.ToString(); } /// @@ -1151,14 +1138,16 @@ namespace MediaBrowser.Controller.Entities /// The user manager. /// Task. /// - public virtual async Task SetPlayedStatus(User user, bool wasPlayed, IUserManager userManager) + public virtual async Task SetPlayedStatus(User user, bool wasPlayed, IUserDataRepository userManager) { if (user == null) { throw new ArgumentNullException(); } - var data = await userManager.GetUserData(user.Id, UserDataId).ConfigureAwait(false); + var key = GetUserDataKey(); + + var data = await userManager.GetUserData(user.Id, key).ConfigureAwait(false); if (wasPlayed) { @@ -1181,7 +1170,7 @@ namespace MediaBrowser.Controller.Entities data.Played = wasPlayed; - await userManager.SaveUserData(user.Id, UserDataId, data, CancellationToken.None).ConfigureAwait(false); + await userManager.SaveUserData(user.Id, key, data, CancellationToken.None).ConfigureAwait(false); } /// diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index eefce2fd34..fed6bb7de3 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -3,6 +3,7 @@ using MediaBrowser.Common.Progress; using MediaBrowser.Controller.IO; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Localization; +using MediaBrowser.Controller.Persistence; using MediaBrowser.Controller.Resolvers; using MediaBrowser.Model.Entities; using System; @@ -809,7 +810,7 @@ namespace MediaBrowser.Controller.Entities /// if set to true [was played]. /// The user manager. /// Task. - public override async Task SetPlayedStatus(User user, bool wasPlayed, IUserManager userManager) + public override async Task SetPlayedStatus(User user, bool wasPlayed, IUserDataRepository userManager) { await base.SetPlayedStatus(user, wasPlayed, userManager).ConfigureAwait(false); diff --git a/MediaBrowser.Controller/Entities/Genre.cs b/MediaBrowser.Controller/Entities/Genre.cs index d5e8afb202..619c7a12b6 100644 --- a/MediaBrowser.Controller/Entities/Genre.cs +++ b/MediaBrowser.Controller/Entities/Genre.cs @@ -6,5 +6,13 @@ namespace MediaBrowser.Controller.Entities /// public class Genre : BaseItem { + /// + /// Gets the user data key. + /// + /// System.String. + public override string GetUserDataKey() + { + return Name; + } } } diff --git a/MediaBrowser.Controller/Entities/Movies/Movie.cs b/MediaBrowser.Controller/Entities/Movies/Movie.cs index d085880775..b70ac2b3b8 100644 --- a/MediaBrowser.Controller/Entities/Movies/Movie.cs +++ b/MediaBrowser.Controller/Entities/Movies/Movie.cs @@ -1,7 +1,5 @@ -using MediaBrowser.Common.Extensions; -using MediaBrowser.Controller.IO; +using MediaBrowser.Controller.IO; using MediaBrowser.Model.Entities; -using System; using System.Collections.Generic; using System.IO; using System.Linq; @@ -30,21 +28,12 @@ namespace MediaBrowser.Controller.Entities.Movies } /// - /// Override to use tmdb or imdb id so it will stick if the item moves physical locations + /// Gets the user data key. /// - /// The user data id. - [IgnoreDataMember] - public override Guid UserDataId + /// System.String. + public override string GetUserDataKey() { - get - { - if (_userDataId == Guid.Empty) - { - var baseId = this.GetProviderId(MetadataProviders.Tmdb) ?? this.GetProviderId(MetadataProviders.Imdb); - _userDataId = baseId != null ? baseId.GetMD5() : Id; - } - return _userDataId; - } + return this.GetProviderId(MetadataProviders.Tmdb) ?? this.GetProviderId(MetadataProviders.Imdb) ?? base.GetUserDataKey(); } /// diff --git a/MediaBrowser.Controller/Entities/Person.cs b/MediaBrowser.Controller/Entities/Person.cs index 5c92c019b8..f5570448da 100644 --- a/MediaBrowser.Controller/Entities/Person.cs +++ b/MediaBrowser.Controller/Entities/Person.cs @@ -6,6 +6,14 @@ namespace MediaBrowser.Controller.Entities /// public class Person : BaseItem { + /// + /// Gets the user data key. + /// + /// System.String. + public override string GetUserDataKey() + { + return Name; + } } /// diff --git a/MediaBrowser.Controller/Entities/Studio.cs b/MediaBrowser.Controller/Entities/Studio.cs index a255849e61..06511d959e 100644 --- a/MediaBrowser.Controller/Entities/Studio.cs +++ b/MediaBrowser.Controller/Entities/Studio.cs @@ -6,5 +6,13 @@ namespace MediaBrowser.Controller.Entities /// public class Studio : BaseItem { + /// + /// Gets the user data key. + /// + /// System.String. + public override string GetUserDataKey() + { + return Name; + } } } diff --git a/MediaBrowser.Controller/Entities/TV/Episode.cs b/MediaBrowser.Controller/Entities/TV/Episode.cs index 7588e4e692..dd1434cea6 100644 --- a/MediaBrowser.Controller/Entities/TV/Episode.cs +++ b/MediaBrowser.Controller/Entities/TV/Episode.cs @@ -49,27 +49,19 @@ namespace MediaBrowser.Controller.Entities.TV } /// - /// Override to use the provider Ids + season and episode number so it will be portable + /// Gets the user data key. /// - /// The user data id. - [IgnoreDataMember] - public override Guid UserDataId + /// System.String. + public override string GetUserDataKey() { - get + if (Series != null) { - if (_userDataId == Guid.Empty) - { - var baseId = Series != null ? Series.GetProviderId(MetadataProviders.Tvdb) ?? Series.GetProviderId(MetadataProviders.Tvcom) : null; - if (baseId != null) - { - var seasonNo = Season != null ? Season.IndexNumber ?? 0 : 0; - var epNo = IndexNumber ?? 0; - baseId = baseId + seasonNo.ToString("000") + epNo.ToString("000"); - } - _userDataId = baseId != null ? baseId.GetMD5() : Id; - } - return _userDataId; + var seasonNo = Season != null ? Season.IndexNumber ?? 0 : 0; + var epNo = IndexNumber ?? 0; + return Series.GetUserDataKey() + seasonNo.ToString("000") + epNo.ToString("000"); } + + return base.GetUserDataKey(); } /// diff --git a/MediaBrowser.Controller/Entities/TV/Season.cs b/MediaBrowser.Controller/Entities/TV/Season.cs index 2f2bee1721..2f3f7387ca 100644 --- a/MediaBrowser.Controller/Entities/TV/Season.cs +++ b/MediaBrowser.Controller/Entities/TV/Season.cs @@ -67,27 +67,18 @@ namespace MediaBrowser.Controller.Entities.TV } /// - /// Override to use the provider Ids + season number so it will be portable + /// Gets the user data key. /// - /// The user data id. - [IgnoreDataMember] - public override Guid UserDataId + /// System.String. + public override string GetUserDataKey() { - get + if (Series != null) { - if (_userDataId == Guid.Empty) - { - var baseId = Series != null ? Series.GetProviderId(MetadataProviders.Tvdb) ?? Series.GetProviderId(MetadataProviders.Tvcom) : null; - if (baseId != null) - { - var seasonNo = IndexNumber ?? 0; - baseId = baseId + seasonNo.ToString("000"); - } - - _userDataId = baseId != null ? baseId.GetMD5() : Id; - } - return _userDataId; + var seasonNo = IndexNumber ?? 0; + return Series.GetUserDataKey() + seasonNo.ToString("000"); } + + return base.GetUserDataKey(); } /// diff --git a/MediaBrowser.Controller/Entities/TV/Series.cs b/MediaBrowser.Controller/Entities/TV/Series.cs index 8a56e45cdc..15b97f694b 100644 --- a/MediaBrowser.Controller/Entities/TV/Series.cs +++ b/MediaBrowser.Controller/Entities/TV/Series.cs @@ -44,21 +44,12 @@ namespace MediaBrowser.Controller.Entities.TV } /// - /// Override to use the provider Ids so it will be portable + /// Gets the user data key. /// - /// The user data id. - [IgnoreDataMember] - public override Guid UserDataId + /// System.String. + public override string GetUserDataKey() { - get - { - if (_userDataId == Guid.Empty) - { - var baseId = this.GetProviderId(MetadataProviders.Tvdb) ?? this.GetProviderId(MetadataProviders.Tvcom); - _userDataId = baseId != null ? baseId.GetMD5() : Id; - } - return _userDataId; - } + return this.GetProviderId(MetadataProviders.Tvdb) ?? this.GetProviderId(MetadataProviders.Tvcom) ?? base.GetUserDataKey(); } // Studio, Genre and Rating will all be the same so makes no sense to index by these diff --git a/MediaBrowser.Controller/Entities/Year.cs b/MediaBrowser.Controller/Entities/Year.cs index 9150057c82..1e4e6cb06b 100644 --- a/MediaBrowser.Controller/Entities/Year.cs +++ b/MediaBrowser.Controller/Entities/Year.cs @@ -6,5 +6,13 @@ namespace MediaBrowser.Controller.Entities /// public class Year : BaseItem { + /// + /// Gets the user data key. + /// + /// System.String. + public override string GetUserDataKey() + { + return Name; + } } } diff --git a/MediaBrowser.Controller/Library/IUserManager.cs b/MediaBrowser.Controller/Library/IUserManager.cs index ad46cf7c33..0fad1d05dc 100644 --- a/MediaBrowser.Controller/Library/IUserManager.cs +++ b/MediaBrowser.Controller/Library/IUserManager.cs @@ -173,24 +173,5 @@ namespace MediaBrowser.Controller.Library /// The new password. /// Task. Task ChangePassword(User user, string newPassword); - - /// - /// Saves the user data. - /// - /// The user id. - /// The user data id. - /// The user data. - /// The cancellation token. - /// Task. - Task SaveUserData(Guid userId, Guid userDataId, UserItemData userData, - CancellationToken cancellationToken); - - /// - /// Gets the user data. - /// - /// The user id. - /// The user data id. - /// Task{UserItemData}. - Task GetUserData(Guid userId, Guid userDataId); } } diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index 558a9d8e36..71245a3bb4 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -72,6 +72,7 @@ + @@ -107,7 +108,7 @@ - + diff --git a/MediaBrowser.Controller/Persistence/IUserDataRepository.cs b/MediaBrowser.Controller/Persistence/IUserDataRepository.cs index 592206faf9..1b4efc58b1 100644 --- a/MediaBrowser.Controller/Persistence/IUserDataRepository.cs +++ b/MediaBrowser.Controller/Persistence/IUserDataRepository.cs @@ -1,5 +1,5 @@ -using MediaBrowser.Controller.Entities; -using System; +using System; +using MediaBrowser.Controller.Entities; using System.Threading; using System.Threading.Tasks; @@ -14,19 +14,19 @@ namespace MediaBrowser.Controller.Persistence /// Saves the user data. /// /// The user id. - /// The user data id. + /// The key. /// The user data. /// The cancellation token. /// Task. - Task SaveUserData(Guid userId, Guid userDataId, UserItemData userData, + Task SaveUserData(Guid userId, string key, UserItemData userData, CancellationToken cancellationToken); /// /// Gets the user data. /// /// The user id. - /// The user data id. + /// The key. /// Task{UserItemData}. - Task GetUserData(Guid userId, Guid userDataId); + Task GetUserData(Guid userId, string key); } } diff --git a/MediaBrowser.Controller/Providers/BaseMetadataProvider.cs b/MediaBrowser.Controller/Providers/BaseMetadataProvider.cs index aaf3fe6bfb..3f71e398a3 100644 --- a/MediaBrowser.Controller/Providers/BaseMetadataProvider.cs +++ b/MediaBrowser.Controller/Providers/BaseMetadataProvider.cs @@ -29,19 +29,7 @@ namespace MediaBrowser.Controller.Providers /// /// The _id /// - protected Guid _id; - /// - /// Gets the id. - /// - /// The id. - public virtual Guid Id - { - get - { - if (_id == Guid.Empty) _id = GetType().FullName.GetMD5(); - return _id; - } - } + protected readonly Guid Id; /// /// Supportses the specified item. @@ -105,6 +93,7 @@ namespace MediaBrowser.Controller.Providers Logger = logManager.GetLogger(GetType().Name); LogManager = logManager; ConfigurationManager = configurationManager; + Id = GetType().FullName.GetMD5(); Initialize(); } @@ -130,8 +119,14 @@ namespace MediaBrowser.Controller.Providers { throw new ArgumentNullException("item"); } - - var data = item.ProviderData.GetValueOrDefault(Id, new BaseProviderInfo { ProviderId = Id }); + + BaseProviderInfo data; + + if (!item.ProviderData.TryGetValue(Id, out data)) + { + data = new BaseProviderInfo(); + } + data.LastRefreshed = value; data.LastRefreshStatus = status; data.ProviderVersion = providerVersion; @@ -155,7 +150,7 @@ namespace MediaBrowser.Controller.Providers { SetLastRefreshed(item, value, ProviderVersion, status); } - + /// /// Returns whether or not this provider should be re-fetched. Default functionality can /// compare a provided date with a last refresh time. This can be overridden for more complex @@ -171,9 +166,14 @@ namespace MediaBrowser.Controller.Providers throw new ArgumentNullException(); } - var providerInfo = item.ProviderData.GetValueOrDefault(Id, new BaseProviderInfo()); + BaseProviderInfo data; - return NeedsRefreshInternal(item, providerInfo); + if (!item.ProviderData.TryGetValue(Id, out data)) + { + data = new BaseProviderInfo(); + } + + return NeedsRefreshInternal(item, data); } /// @@ -194,7 +194,7 @@ namespace MediaBrowser.Controller.Providers { throw new ArgumentNullException("providerInfo"); } - + if (CompareDate(item) > providerInfo.LastRefreshed) { return true; @@ -209,7 +209,7 @@ namespace MediaBrowser.Controller.Providers { return true; } - + return false; } @@ -221,7 +221,7 @@ namespace MediaBrowser.Controller.Providers /// true if [has file system stamp changed] [the specified item]; otherwise, false. protected bool HasFileSystemStampChanged(BaseItem item, BaseProviderInfo providerInfo) { - return GetCurrentFileSystemStamp(item) != providerInfo.FileSystemStamp; + return !string.Equals(GetCurrentFileSystemStamp(item), providerInfo.FileSystemStamp); } /// @@ -279,7 +279,7 @@ namespace MediaBrowser.Controller.Providers /// /// The item. /// Guid. - private Guid GetCurrentFileSystemStamp(BaseItem item) + private string GetCurrentFileSystemStamp(BaseItem item) { if (UseParentFileSystemStamp(item) && item.Parent != null) { diff --git a/MediaBrowser.Controller/Providers/BaseProviderInfo.cs b/MediaBrowser.Controller/Providers/BaseProviderInfo.cs index 877ba5c4bf..5a72491c1e 100644 --- a/MediaBrowser.Controller/Providers/BaseProviderInfo.cs +++ b/MediaBrowser.Controller/Providers/BaseProviderInfo.cs @@ -7,11 +7,6 @@ namespace MediaBrowser.Controller.Providers /// public class BaseProviderInfo { - /// - /// Gets or sets the provider id. - /// - /// The provider id. - public Guid ProviderId { get; set; } /// /// Gets or sets the last refreshed. /// @@ -21,7 +16,7 @@ namespace MediaBrowser.Controller.Providers /// Gets or sets the file system stamp. /// /// The file system stamp. - public Guid FileSystemStamp { get; set; } + public string FileSystemStamp { get; set; } /// /// Gets or sets the last refresh status. /// @@ -32,11 +27,6 @@ namespace MediaBrowser.Controller.Providers /// /// The provider version. public string ProviderVersion { get; set; } - /// - /// Gets or sets the data hash. - /// - /// The data hash. - public Guid DataHash { get; set; } } /// diff --git a/MediaBrowser.Controller/Providers/Movies/FanArtMovieProvider.cs b/MediaBrowser.Controller/Providers/Movies/FanArtMovieProvider.cs index 3152ceac93..94fe386806 100644 --- a/MediaBrowser.Controller/Providers/Movies/FanArtMovieProvider.cs +++ b/MediaBrowser.Controller/Providers/Movies/FanArtMovieProvider.cs @@ -104,7 +104,14 @@ namespace MediaBrowser.Controller.Providers.Movies cancellationToken.ThrowIfCancellationRequested(); var movie = item; - if (ShouldFetch(movie, movie.ProviderData.GetValueOrDefault(Id, new BaseProviderInfo { ProviderId = Id }))) + + BaseProviderInfo providerData; + + if (!item.ProviderData.TryGetValue(Id, out providerData)) + { + providerData = new BaseProviderInfo(); + } + if (ShouldFetch(movie, providerData)) { var language = ConfigurationManager.Configuration.PreferredMetadataLanguage.ToLower(); var url = string.Format(FanArtBaseUrl, APIKey, movie.GetProviderId(MetadataProviders.Tmdb)); diff --git a/MediaBrowser.Controller/Providers/Movies/MovieDbProvider.cs b/MediaBrowser.Controller/Providers/Movies/MovieDbProvider.cs index fb8370248c..8e20f0fada 100644 --- a/MediaBrowser.Controller/Providers/Movies/MovieDbProvider.cs +++ b/MediaBrowser.Controller/Providers/Movies/MovieDbProvider.cs @@ -22,10 +22,11 @@ namespace MediaBrowser.Controller.Providers.Movies { class MovieDbProviderException : ApplicationException { - public MovieDbProviderException(string msg) : base(msg) + public MovieDbProviderException(string msg) + : base(msg) { } - + } /// /// Class MovieDbProvider @@ -33,7 +34,7 @@ namespace MediaBrowser.Controller.Providers.Movies public class MovieDbProvider : BaseMetadataProvider, IDisposable { protected readonly IProviderManager ProviderManager; - + /// /// The movie db /// @@ -198,7 +199,7 @@ namespace MediaBrowser.Controller.Providers.Movies base_url = "http://cf2.imgobject.com/t/p/" } - }; + }; } } @@ -223,7 +224,14 @@ namespace MediaBrowser.Controller.Providers.Movies //in addition to ours, we need to set the last refreshed time for the local data provider //so it won't see the new files we download and process them all over again if (JsonProvider == null) JsonProvider = new MovieProviderFromJson(LogManager, ConfigurationManager, JsonSerializer, HttpClient, ProviderManager); - var data = item.ProviderData.GetValueOrDefault(JsonProvider.Id, new BaseProviderInfo { ProviderId = JsonProvider.Id }); + + BaseProviderInfo data; + + if (!item.ProviderData.TryGetValue(JsonProvider.Id, out data)) + { + data = new BaseProviderInfo(); + } + data.LastRefreshed = value; item.ProviderData[JsonProvider.Id] = data; } diff --git a/MediaBrowser.Controller/Providers/Music/FanArtAlbumProvider.cs b/MediaBrowser.Controller/Providers/Music/FanArtAlbumProvider.cs index b533848412..72169f245e 100644 --- a/MediaBrowser.Controller/Providers/Music/FanArtAlbumProvider.cs +++ b/MediaBrowser.Controller/Providers/Music/FanArtAlbumProvider.cs @@ -1,4 +1,5 @@ -using MediaBrowser.Common.Extensions; +using System.Collections.Generic; +using MediaBrowser.Common.Extensions; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; @@ -52,14 +53,15 @@ namespace MediaBrowser.Controller.Providers.Music //Look at our parent for our album cover var artist = (MusicArtist)item.Parent; - var cover = artist.AlbumCovers != null ? artist.AlbumCovers.GetValueOrDefault(mbid, null) : null; + + var cover = artist.AlbumCovers != null ? GetValueOrDefault(artist.AlbumCovers, mbid, null) : null; if (cover == null) { // Not there - maybe it is new since artist last refreshed so refresh it and try again await artist.RefreshMetadata(cancellationToken).ConfigureAwait(false); cancellationToken.ThrowIfCancellationRequested(); - cover = artist.AlbumCovers != null ? artist.AlbumCovers.GetValueOrDefault(mbid, null) : null; + cover = artist.AlbumCovers != null ? GetValueOrDefault(artist.AlbumCovers, mbid, null) : null; } if (cover == null) { @@ -71,5 +73,25 @@ namespace MediaBrowser.Controller.Providers.Music item.SetImage(ImageType.Primary, await _providerManager.DownloadAndSaveImage(item, cover, "folder.jpg", FanArtResourcePool, cancellationToken).ConfigureAwait(false)); return true; } + + /// + /// Helper method for Dictionaries since they throw on not-found keys + /// + /// + /// + /// The dictionary. + /// The key. + /// The default value. + /// ``1. + private static U GetValueOrDefault(Dictionary dictionary, T key, U defaultValue) + { + U val; + if (!dictionary.TryGetValue(key, out val)) + { + val = defaultValue; + } + return val; + + } } } diff --git a/MediaBrowser.Controller/Providers/Music/FanArtArtistProvider.cs b/MediaBrowser.Controller/Providers/Music/FanArtArtistProvider.cs index ec7a96d99d..1dd5c7cd25 100644 --- a/MediaBrowser.Controller/Providers/Music/FanArtArtistProvider.cs +++ b/MediaBrowser.Controller/Providers/Music/FanArtArtistProvider.cs @@ -86,7 +86,15 @@ namespace MediaBrowser.Controller.Providers.Music cancellationToken.ThrowIfCancellationRequested(); var artist = (MusicArtist)item; - if (ShouldFetch(artist, artist.ProviderData.GetValueOrDefault(Id, new BaseProviderInfo { ProviderId = Id }))) + + BaseProviderInfo providerData; + + if (!item.ProviderData.TryGetValue(Id, out providerData)) + { + providerData = new BaseProviderInfo(); + } + + if (ShouldFetch(artist, providerData)) { var url = string.Format(FanArtBaseUrl, APIKey, artist.GetProviderId(MetadataProviders.Musicbrainz)); var doc = new XmlDocument(); diff --git a/MediaBrowser.Controller/Providers/Music/LastfmBaseProvider.cs b/MediaBrowser.Controller/Providers/Music/LastfmBaseProvider.cs index f58bd3bb77..f7e0eef48d 100644 --- a/MediaBrowser.Controller/Providers/Music/LastfmBaseProvider.cs +++ b/MediaBrowser.Controller/Providers/Music/LastfmBaseProvider.cs @@ -229,7 +229,13 @@ namespace MediaBrowser.Controller.Providers.Music cancellationToken.ThrowIfCancellationRequested(); - var providerData = item.ProviderData.GetValueOrDefault(Id, new BaseProviderInfo { ProviderId = Id }); + BaseProviderInfo providerData; + + if (!item.ProviderData.TryGetValue(Id, out providerData)) + { + providerData = new BaseProviderInfo(); + } + if (!ConfigurationManager.Configuration.SaveLocalMeta || !HasLocalMeta(item) || (force && !HasLocalMeta(item)) || (RefreshOnVersionChange && providerData.ProviderVersion != ProviderVersion)) { try diff --git a/MediaBrowser.Controller/Providers/TV/FanArtTVProvider.cs b/MediaBrowser.Controller/Providers/TV/FanArtTVProvider.cs index 4d06143fce..a7fc4586f1 100644 --- a/MediaBrowser.Controller/Providers/TV/FanArtTVProvider.cs +++ b/MediaBrowser.Controller/Providers/TV/FanArtTVProvider.cs @@ -60,7 +60,15 @@ namespace MediaBrowser.Controller.Providers.TV cancellationToken.ThrowIfCancellationRequested(); var series = (Series)item; - if (ShouldFetch(series, series.ProviderData.GetValueOrDefault(Id, new BaseProviderInfo { ProviderId = Id }))) + + BaseProviderInfo providerData; + + if (!item.ProviderData.TryGetValue(Id, out providerData)) + { + providerData = new BaseProviderInfo(); + } + + if (ShouldFetch(series, providerData)) { string language = ConfigurationManager.Configuration.PreferredMetadataLanguage.ToLower(); string url = string.Format(FanArtBaseUrl, APIKey, series.GetProviderId(MetadataProviders.Tvdb)); diff --git a/MediaBrowser.Controller/Sorting/IUserBaseItemComparer.cs b/MediaBrowser.Controller/Sorting/IUserBaseItemComparer.cs index 76d84a653d..d464a64a07 100644 --- a/MediaBrowser.Controller/Sorting/IUserBaseItemComparer.cs +++ b/MediaBrowser.Controller/Sorting/IUserBaseItemComparer.cs @@ -1,5 +1,6 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Persistence; namespace MediaBrowser.Controller.Sorting { @@ -19,5 +20,11 @@ namespace MediaBrowser.Controller.Sorting /// /// The user manager. IUserManager UserManager { get; set; } + + /// + /// Gets or sets the user data repository. + /// + /// The user data repository. + IUserDataRepository UserDataRepository { get; set; } } } diff --git a/MediaBrowser.Model/Configuration/ServerConfiguration.cs b/MediaBrowser.Model/Configuration/ServerConfiguration.cs index eb2b4ddebe..0c18564ec8 100644 --- a/MediaBrowser.Model/Configuration/ServerConfiguration.cs +++ b/MediaBrowser.Model/Configuration/ServerConfiguration.cs @@ -153,27 +153,6 @@ namespace MediaBrowser.Model.Configuration [ProtoMember(52)] public bool DownloadHDFanArt { get; set; } - /// - /// Gets or sets the name of the item repository that should be used - /// - /// The item repository. - [ProtoMember(24)] - public string ItemRepository { get; set; } - - /// - /// Gets or sets the name of the user repository that should be used - /// - /// The user repository. - [ProtoMember(25)] - public string UserRepository { get; set; } - - /// - /// Gets or sets the name of the user data repository that should be used - /// - /// The user data repository. - [ProtoMember(26)] - public string UserDataRepository { get; set; } - /// /// Characters to be replaced with a ' ' in strings to create a sort name /// @@ -202,13 +181,6 @@ namespace MediaBrowser.Model.Configuration [ProtoMember(30)] public bool ShowLogWindow { get; set; } - /// - /// Gets or sets the name of the user data repository that should be used - /// - /// The display preferences repository. - [ProtoMember(31)] - public string DisplayPreferencesRepository { get; set; } - /// /// The list of types that will NOT be allowed to have internet providers run against them even if they are turned on. /// diff --git a/MediaBrowser.Model/Connectivity/ClientConnectionInfo.cs b/MediaBrowser.Model/Connectivity/ClientConnectionInfo.cs index 565ce6ec24..a5e44f22ec 100644 --- a/MediaBrowser.Model/Connectivity/ClientConnectionInfo.cs +++ b/MediaBrowser.Model/Connectivity/ClientConnectionInfo.cs @@ -15,7 +15,7 @@ namespace MediaBrowser.Model.Connectivity /// /// The user id. [ProtoMember(1)] - public Guid UserId { get; set; } + public string UserId { get; set; } /// /// Gets or sets the type of the client. diff --git a/MediaBrowser.Model/DTO/UserDto.cs b/MediaBrowser.Model/DTO/UserDto.cs index 979422dbe8..b2afa90c0f 100644 --- a/MediaBrowser.Model/DTO/UserDto.cs +++ b/MediaBrowser.Model/DTO/UserDto.cs @@ -24,7 +24,7 @@ namespace MediaBrowser.Model.Dto /// /// The id. [ProtoMember(2)] - public Guid Id { get; set; } + public string Id { get; set; } /// /// Gets or sets the primary image tag. diff --git a/MediaBrowser.Model/Plugins/PluginInfo.cs b/MediaBrowser.Model/Plugins/PluginInfo.cs index 2df635db02..fd4cfa78c2 100644 --- a/MediaBrowser.Model/Plugins/PluginInfo.cs +++ b/MediaBrowser.Model/Plugins/PluginInfo.cs @@ -57,7 +57,7 @@ namespace MediaBrowser.Model.Plugins /// /// The unique id. [ProtoMember(9)] - public Guid Id { get; set; } + public string Id { get; set; } /// /// Whether or not this plug-in should be automatically updated when a diff --git a/MediaBrowser.Model/Querying/ItemQuery.cs b/MediaBrowser.Model/Querying/ItemQuery.cs index 3a1d14065e..86886d751a 100644 --- a/MediaBrowser.Model/Querying/ItemQuery.cs +++ b/MediaBrowser.Model/Querying/ItemQuery.cs @@ -12,7 +12,7 @@ namespace MediaBrowser.Model.Querying /// The user to localize search results for /// /// The user id. - public Guid UserId { get; set; } + public string UserId { get; set; } /// /// Specify this to localize the search to a specific item or folder. Omit to use the root. diff --git a/MediaBrowser.Model/Querying/ItemsByNameQuery.cs b/MediaBrowser.Model/Querying/ItemsByNameQuery.cs index 0bebb085e1..eae2dc0426 100644 --- a/MediaBrowser.Model/Querying/ItemsByNameQuery.cs +++ b/MediaBrowser.Model/Querying/ItemsByNameQuery.cs @@ -1,5 +1,4 @@ using MediaBrowser.Model.Entities; -using System; namespace MediaBrowser.Model.Querying { @@ -12,7 +11,7 @@ namespace MediaBrowser.Model.Querying /// Gets or sets the user id. /// /// The user id. - public Guid UserId { get; set; } + public string UserId { get; set; } /// /// Gets or sets the start index. /// diff --git a/MediaBrowser.Model/System/SystemInfo.cs b/MediaBrowser.Model/System/SystemInfo.cs index 20716ecc54..afe0740882 100644 --- a/MediaBrowser.Model/System/SystemInfo.cs +++ b/MediaBrowser.Model/System/SystemInfo.cs @@ -71,6 +71,6 @@ namespace MediaBrowser.Model.System /// /// The id. [ProtoMember(9)] - public Guid Id { get; set; } + public string Id { get; set; } } } diff --git a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs index d397b15480..3bb5472dfc 100644 --- a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs +++ b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs @@ -101,6 +101,8 @@ namespace MediaBrowser.Server.Implementations.Library /// private readonly IUserManager _userManager; + private readonly IUserDataRepository _userDataRepository; + /// /// Gets or sets the configuration manager. /// @@ -136,12 +138,14 @@ namespace MediaBrowser.Server.Implementations.Library /// The task manager. /// The user manager. /// The configuration manager. - public LibraryManager(ILogger logger, ITaskManager taskManager, IUserManager userManager, IServerConfigurationManager configurationManager) + /// The user data repository. + public LibraryManager(ILogger logger, ITaskManager taskManager, IUserManager userManager, IServerConfigurationManager configurationManager, IUserDataRepository userDataRepository) { _logger = logger; _taskManager = taskManager; _userManager = userManager; ConfigurationManager = configurationManager; + _userDataRepository = userDataRepository; ByReferenceItems = new ConcurrentDictionary(); ConfigurationManager.ConfigurationUpdated += ConfigurationUpdated; @@ -903,6 +907,7 @@ namespace MediaBrowser.Server.Implementations.Library userComparer.User = user; userComparer.UserManager = _userManager; + userComparer.UserDataRepository = _userDataRepository; return userComparer; } diff --git a/MediaBrowser.Server.Implementations/Library/UserManager.cs b/MediaBrowser.Server.Implementations/Library/UserManager.cs index 311a31264f..dbb2d7b320 100644 --- a/MediaBrowser.Server.Implementations/Library/UserManager.cs +++ b/MediaBrowser.Server.Implementations/Library/UserManager.cs @@ -1,6 +1,7 @@ using MediaBrowser.Common.Events; using MediaBrowser.Common.Extensions; using MediaBrowser.Controller.Configuration; +using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Persistence; @@ -86,20 +87,14 @@ namespace MediaBrowser.Server.Implementations.Library /// private readonly ILogger _logger; + private readonly IUserDataRepository _userDataRepository; + /// /// Gets or sets the configuration manager. /// /// The configuration manager. private IServerConfigurationManager ConfigurationManager { get; set; } - private readonly ConcurrentDictionary> _userData = new ConcurrentDictionary>(); - - /// - /// Gets the active user data repository - /// - /// The user data repository. - public IUserDataRepository UserDataRepository { get; set; } - /// /// Gets the active user repository /// @@ -321,13 +316,13 @@ namespace MediaBrowser.Server.Implementations.Library var connection = _activeConnections.GetOrAdd(key, keyName => new ClientConnectionInfo { - UserId = userId, + UserId = userId.ToString(), Client = clientType, DeviceName = deviceName, DeviceId = deviceId }); - connection.UserId = userId; + connection.UserId = userId.ToString(); return connection; } @@ -591,12 +586,14 @@ namespace MediaBrowser.Server.Implementations.Library UpdateNowPlayingItemId(user, clientType, deviceId, deviceName, item, positionTicks); + var key = item.GetUserDataKey(); + if (positionTicks.HasValue) { - var data = await GetUserData(user.Id, item.UserDataId).ConfigureAwait(false); + var data = await _userDataRepository.GetUserData(user.Id, key).ConfigureAwait(false); UpdatePlayState(item, data, positionTicks.Value, false); - await SaveUserData(user.Id, item.UserDataId, data, CancellationToken.None).ConfigureAwait(false); + await _userDataRepository.SaveUserData(user.Id, key, data, CancellationToken.None).ConfigureAwait(false); } EventHelper.QueueEventIfNotNull(PlaybackProgress, this, new PlaybackProgressEventArgs @@ -631,7 +628,9 @@ namespace MediaBrowser.Server.Implementations.Library RemoveNowPlayingItemId(user, clientType, deviceId, deviceName, item); - var data = await GetUserData(user.Id, item.UserDataId).ConfigureAwait(false); + var key = item.GetUserDataKey(); + + var data = await _userDataRepository.GetUserData(user.Id, key).ConfigureAwait(false); if (positionTicks.HasValue) { @@ -644,7 +643,7 @@ namespace MediaBrowser.Server.Implementations.Library data.Played = true; } - await SaveUserData(user.Id, item.UserDataId, data, CancellationToken.None).ConfigureAwait(false); + await _userDataRepository.SaveUserData(user.Id, key, data, CancellationToken.None).ConfigureAwait(false); EventHelper.QueueEventIfNotNull(PlaybackStopped, this, new PlaybackProgressEventArgs { @@ -703,59 +702,5 @@ namespace MediaBrowser.Server.Implementations.Library data.LastPlayedDate = DateTime.UtcNow; } } - - /// - /// Saves display preferences for an item - /// - /// The user id. - /// The user data id. - /// The user data. - /// The cancellation token. - /// Task. - public async Task SaveUserData(Guid userId, Guid userDataId, UserItemData userData, CancellationToken cancellationToken) - { - var key = userId + userDataId.ToString(); - try - { - await 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; - } - } - - /// - /// Gets the user data. - /// - /// The user id. - /// The user data id. - /// Task{UserItemData}. - public Task GetUserData(Guid userId, Guid userDataId) - { - var key = userId + userDataId.ToString(); - - return _userData.GetOrAdd(key, keyName => RetrieveUserData(userId, userDataId)); - } - - /// - /// Retrieves the user data. - /// - /// The user id. - /// The user data id. - /// Task{UserItemData}. - private async Task RetrieveUserData(Guid userId, Guid userDataId) - { - var userdata = await UserDataRepository.GetUserData(userId, userDataId).ConfigureAwait(false); - - return userdata ?? new UserItemData(); - } } } diff --git a/MediaBrowser.Server.Implementations/Providers/ProviderManager.cs b/MediaBrowser.Server.Implementations/Providers/ProviderManager.cs index 8b135db5a7..ff7222e7c1 100644 --- a/MediaBrowser.Server.Implementations/Providers/ProviderManager.cs +++ b/MediaBrowser.Server.Implementations/Providers/ProviderManager.cs @@ -88,12 +88,6 @@ namespace MediaBrowser.Server.Implementations.Providers Task.Run(() => ValidateCurrentlyRunningProviders()); } - /// - /// Gets or sets the supported providers key. - /// - /// The supported providers key. - private Guid SupportedProvidersKey { get; set; } - /// /// Adds the metadata providers. /// @@ -103,6 +97,11 @@ namespace MediaBrowser.Server.Implementations.Providers MetadataProviders = providers.OrderBy(e => e.Priority).ToArray(); } + /// + /// The _supported providers key + /// + private readonly Guid _supportedProvidersKey = "SupportedProviders".GetMD5(); + /// /// Runs all metadata providers for an entity, and returns true or false indicating if at least one was refreshed and requires persistence /// @@ -126,19 +125,14 @@ namespace MediaBrowser.Server.Implementations.Providers BaseProviderInfo supportedProvidersInfo; - if (SupportedProvidersKey == Guid.Empty) - { - SupportedProvidersKey = "SupportedProviders".GetMD5(); - } + var supportedProvidersValue = string.Join("+", supportedProviders.Select(i => i.GetType().Name)); + var providersChanged = false; - var supportedProvidersHash = string.Join("+", supportedProviders.Select(i => i.GetType().Name)).GetMD5(); - bool providersChanged = false; - - item.ProviderData.TryGetValue(SupportedProvidersKey, out supportedProvidersInfo); + item.ProviderData.TryGetValue(_supportedProvidersKey, out supportedProvidersInfo); if (supportedProvidersInfo != null) { // Force refresh if the supported providers have changed - providersChanged = force = force || supportedProvidersInfo.FileSystemStamp != supportedProvidersHash; + providersChanged = force = force || !string.Equals(supportedProvidersInfo.FileSystemStamp, supportedProvidersValue); // If providers have changed, clear provider info and update the supported providers hash if (providersChanged) @@ -150,7 +144,7 @@ namespace MediaBrowser.Server.Implementations.Providers if (providersChanged) { - supportedProvidersInfo.FileSystemStamp = supportedProvidersHash; + supportedProvidersInfo.FileSystemStamp = supportedProvidersValue; } if (force) item.ClearMetaValues(); @@ -206,7 +200,7 @@ namespace MediaBrowser.Server.Implementations.Providers if (providersChanged) { - item.ProviderData[SupportedProvidersKey] = supportedProvidersInfo; + item.ProviderData[_supportedProvidersKey] = supportedProvidersInfo; } return result || providersChanged; diff --git a/MediaBrowser.Server.Implementations/Sorting/DatePlayedComparer.cs b/MediaBrowser.Server.Implementations/Sorting/DatePlayedComparer.cs index 905d5413a7..c634c760e4 100644 --- a/MediaBrowser.Server.Implementations/Sorting/DatePlayedComparer.cs +++ b/MediaBrowser.Server.Implementations/Sorting/DatePlayedComparer.cs @@ -1,5 +1,6 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Persistence; using MediaBrowser.Controller.Sorting; using MediaBrowser.Model.Querying; using System; @@ -23,6 +24,12 @@ namespace MediaBrowser.Server.Implementations.Sorting /// The user manager. public IUserManager UserManager { get; set; } + /// + /// Gets or sets the user data repository. + /// + /// The user data repository. + public IUserDataRepository UserDataRepository { get; set; } + /// /// Compares the specified x. /// @@ -41,7 +48,7 @@ namespace MediaBrowser.Server.Implementations.Sorting /// DateTime. private DateTime GetDate(BaseItem x) { - var userdata = UserManager.GetUserData(User.Id, x.UserDataId).Result; + var userdata = UserDataRepository.GetUserData(User.Id, x.GetUserDataKey()).Result; if (userdata != null && userdata.LastPlayedDate.HasValue) { diff --git a/MediaBrowser.Server.Implementations/Sorting/PlayCountComparer.cs b/MediaBrowser.Server.Implementations/Sorting/PlayCountComparer.cs index 82e76e78d4..a7cbd21499 100644 --- a/MediaBrowser.Server.Implementations/Sorting/PlayCountComparer.cs +++ b/MediaBrowser.Server.Implementations/Sorting/PlayCountComparer.cs @@ -1,5 +1,6 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Persistence; using MediaBrowser.Controller.Sorting; using MediaBrowser.Model.Querying; @@ -34,7 +35,7 @@ namespace MediaBrowser.Server.Implementations.Sorting /// DateTime. private int GetValue(BaseItem x) { - var userdata = UserManager.GetUserData(User.Id, x.UserDataId).Result; + var userdata = UserDataRepository.GetUserData(User.Id, x.GetUserDataKey()).Result; return userdata == null ? 0 : userdata.PlayCount; } @@ -48,6 +49,12 @@ namespace MediaBrowser.Server.Implementations.Sorting get { return ItemSortBy.PlayCount; } } + /// + /// Gets or sets the user data repository. + /// + /// The user data repository. + public IUserDataRepository UserDataRepository { get; set; } + /// /// Gets or sets the user manager. /// diff --git a/MediaBrowser.Server.Implementations/Sqlite/SQLiteDisplayPreferencesRepository.cs b/MediaBrowser.Server.Implementations/Sqlite/SQLiteDisplayPreferencesRepository.cs index 5016358007..fbb0e4f8c5 100644 --- a/MediaBrowser.Server.Implementations/Sqlite/SQLiteDisplayPreferencesRepository.cs +++ b/MediaBrowser.Server.Implementations/Sqlite/SQLiteDisplayPreferencesRepository.cs @@ -14,7 +14,7 @@ namespace MediaBrowser.Server.Implementations.Sqlite /// /// Class SQLiteDisplayPreferencesRepository /// - class SQLiteDisplayPreferencesRepository : SqliteRepository, IDisplayPreferencesRepository + public class SQLiteDisplayPreferencesRepository : SqliteRepository, IDisplayPreferencesRepository { /// /// The repository name diff --git a/MediaBrowser.Server.Implementations/Sqlite/SQLiteUserDataRepository.cs b/MediaBrowser.Server.Implementations/Sqlite/SQLiteUserDataRepository.cs index 467628a78f..4df81aacca 100644 --- a/MediaBrowser.Server.Implementations/Sqlite/SQLiteUserDataRepository.cs +++ b/MediaBrowser.Server.Implementations/Sqlite/SQLiteUserDataRepository.cs @@ -4,6 +4,7 @@ using MediaBrowser.Controller.Persistence; using MediaBrowser.Model.Logging; using MediaBrowser.Model.Serialization; using System; +using System.Collections.Concurrent; using System.Data; using System.IO; using System.Threading; @@ -16,6 +17,8 @@ namespace MediaBrowser.Server.Implementations.Sqlite /// public class SQLiteUserDataRepository : SqliteRepository, IUserDataRepository { + private readonly ConcurrentDictionary> _userData = new ConcurrentDictionary>(); + /// /// The repository name /// @@ -45,9 +48,6 @@ namespace MediaBrowser.Server.Implementations.Sqlite } } - /// - /// The _protobuf serializer - /// private readonly IJsonSerializer _jsonSerializer; /// @@ -90,8 +90,8 @@ namespace MediaBrowser.Server.Implementations.Sqlite string[] queries = { - "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 userdata (key nvarchar, userId GUID, data BLOB)", + "create unique index if not exists userdataindex on userdata (key, userId)", "create table if not exists schema_version (table_name primary key, version)", //pragmas "pragma temp_store = memory" @@ -104,20 +104,18 @@ namespace MediaBrowser.Server.Implementations.Sqlite /// Saves the user data. /// /// The user id. - /// The user data id. + /// The key. /// The user data. /// The cancellation token. /// Task. - /// - /// userData + /// userData /// or /// cancellationToken /// or /// userId /// or - /// userDataId - /// - public async Task SaveUserData(Guid userId, Guid userDataId, UserItemData userData, CancellationToken cancellationToken) + /// userDataId + public async Task SaveUserData(Guid userId, string key, UserItemData userData, CancellationToken cancellationToken) { if (userData == null) { @@ -131,20 +129,49 @@ namespace MediaBrowser.Server.Implementations.Sqlite { throw new ArgumentNullException("userId"); } - if (userDataId == Guid.Empty) + if (string.IsNullOrEmpty(key)) { - throw new ArgumentNullException("userDataId"); + throw new ArgumentNullException("key"); } cancellationToken.ThrowIfCancellationRequested(); + try + { + await PersistUserData(userId, key, 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; + } + } + + /// + /// Persists the user data. + /// + /// The user id. + /// The key. + /// The user data. + /// The cancellation token. + /// Task. + public async Task PersistUserData(Guid userId, string key, UserItemData userData, CancellationToken cancellationToken) + { + cancellationToken.ThrowIfCancellationRequested(); + var serialized = _jsonSerializer.SerializeToBytes(userData); cancellationToken.ThrowIfCancellationRequested(); var cmd = connection.CreateCommand(); - cmd.CommandText = "replace into userdata (id, userId, data) values (@1, @2, @3)"; - cmd.AddParam("@1", userDataId); + cmd.CommandText = "replace into userdata (key, userId, data) values (@1, @2, @3)"; + cmd.AddParam("@1", key); cmd.AddParam("@2", userId); cmd.AddParam("@3", serialized); @@ -174,29 +201,40 @@ namespace MediaBrowser.Server.Implementations.Sqlite /// Gets the user data. /// /// The user id. - /// The user data id. + /// The key. /// Task{UserItemData}. /// /// userId /// or - /// userDataId + /// key /// - public async Task GetUserData(Guid userId, Guid userDataId) + public Task GetUserData(Guid userId, string key) { if (userId == Guid.Empty) { throw new ArgumentNullException("userId"); } - if (userDataId == Guid.Empty) + if (string.IsNullOrEmpty(key)) { - throw new ArgumentNullException("userDataId"); + throw new ArgumentNullException("key"); } + + return _userData.GetOrAdd(key, keyName => RetrieveUserData(userId, key)); + } + /// + /// Retrieves the user data. + /// + /// The user id. + /// The key. + /// Task{UserItemData}. + private async Task RetrieveUserData(Guid userId, string key) + { var cmd = connection.CreateCommand(); - cmd.CommandText = "select data from userdata where id = @id and userId=@userId"; + cmd.CommandText = "select data from userdata where key = @key and userId=@userId"; - var idParam = cmd.Parameters.Add("@id", DbType.Guid); - idParam.Value = userDataId; + var idParam = cmd.Parameters.Add("@key", DbType.Guid); + idParam.Value = key; var userIdParam = cmd.Parameters.Add("@userId", DbType.Guid); userIdParam.Value = userId; @@ -212,7 +250,7 @@ namespace MediaBrowser.Server.Implementations.Sqlite } } - return null; + return new UserItemData(); } } } diff --git a/MediaBrowser.ServerApplication/ApplicationHost.cs b/MediaBrowser.ServerApplication/ApplicationHost.cs index afc68fe67b..59395e4698 100644 --- a/MediaBrowser.ServerApplication/ApplicationHost.cs +++ b/MediaBrowser.ServerApplication/ApplicationHost.cs @@ -37,6 +37,7 @@ using MediaBrowser.Server.Implementations.Library; using MediaBrowser.Server.Implementations.MediaEncoder; using MediaBrowser.Server.Implementations.Providers; using MediaBrowser.Server.Implementations.ServerManager; +using MediaBrowser.Server.Implementations.Sqlite; using MediaBrowser.Server.Implementations.Udp; using MediaBrowser.Server.Implementations.Updates; using MediaBrowser.Server.Implementations.WebSocket; @@ -152,6 +153,12 @@ namespace MediaBrowser.ServerApplication /// The media encoder. private IMediaEncoder MediaEncoder { get; set; } + /// + /// Gets or sets the user data repository. + /// + /// The user data repository. + private IUserDataRepository UserDataRepository { get; set; } + /// /// The full path to our startmenu shortcut /// @@ -216,7 +223,10 @@ namespace MediaBrowser.ServerApplication UserManager = new UserManager(Logger, ServerConfigurationManager); RegisterSingleInstance(UserManager); - LibraryManager = new LibraryManager(Logger, TaskManager, UserManager, ServerConfigurationManager); + UserDataRepository = new SQLiteUserDataRepository(ApplicationPaths, JsonSerializer, LogManager); + RegisterSingleInstance(UserDataRepository); + + LibraryManager = new LibraryManager(Logger, TaskManager, UserManager, ServerConfigurationManager, UserDataRepository); RegisterSingleInstance(LibraryManager); InstallationManager = new InstallationManager(HttpClient, PackageManager, JsonSerializer, Logger, this); @@ -273,9 +283,7 @@ namespace MediaBrowser.ServerApplication /// Task. private async Task ConfigureDisplayPreferencesRepositories() { - var repositories = GetExports(); - - var repository = GetRepository(repositories, ServerConfigurationManager.Configuration.DisplayPreferencesRepository); + var repository = new SQLiteDisplayPreferencesRepository(ApplicationPaths, JsonSerializer, LogManager); await repository.Initialize().ConfigureAwait(false); @@ -288,9 +296,7 @@ namespace MediaBrowser.ServerApplication /// Task. private async Task ConfigureItemRepositories() { - var repositories = GetExports(); - - var repository = GetRepository(repositories, ServerConfigurationManager.Configuration.ItemRepository); + var repository = new SQLiteItemRepository(ApplicationPaths, JsonSerializer, LogManager); await repository.Initialize().ConfigureAwait(false); @@ -301,22 +307,14 @@ namespace MediaBrowser.ServerApplication /// Configures the user data repositories. /// /// Task. - private async Task ConfigureUserDataRepositories() + private Task ConfigureUserDataRepositories() { - var repositories = GetExports(); - - var repository = GetRepository(repositories, ServerConfigurationManager.Configuration.UserDataRepository); - - await repository.Initialize().ConfigureAwait(false); - - ((UserManager)UserManager).UserDataRepository = repository; + return UserDataRepository.Initialize(); } private async Task ConfigureUserRepositories() { - var repositories = GetExports(); - - var repository = GetRepository(repositories, ServerConfigurationManager.Configuration.UserRepository); + var repository = new SQLiteUserRepository(ApplicationPaths, JsonSerializer, LogManager); await repository.Initialize().ConfigureAwait(false); @@ -470,7 +468,7 @@ namespace MediaBrowser.ServerApplication yield return GetType().Assembly; } - private readonly Guid _systemId = Environment.MachineName.GetMD5(); + private readonly string _systemId = Environment.MachineName.GetMD5().ToString(); /// /// Gets the system status. diff --git a/MediaBrowser.ServerApplication/EntryPoints/WebSocketEvents.cs b/MediaBrowser.ServerApplication/EntryPoints/WebSocketEvents.cs index 98d7fb4775..19c42e8d8d 100644 --- a/MediaBrowser.ServerApplication/EntryPoints/WebSocketEvents.cs +++ b/MediaBrowser.ServerApplication/EntryPoints/WebSocketEvents.cs @@ -3,6 +3,7 @@ using MediaBrowser.Common.Net; using MediaBrowser.Common.Plugins; using MediaBrowser.Common.ScheduledTasks; using MediaBrowser.Controller; +using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Plugins; @@ -174,7 +175,7 @@ namespace MediaBrowser.ServerApplication.EntryPoints /// The e. void userManager_UserUpdated(object sender, GenericEventArgs e) { - var dto = new DtoBuilder(_logger, _libraryManager, _userManager).GetUserDto(e.Argument); + var dto = new UserDtoBuilder(_logger).GetUserDto(e.Argument); _serverManager.SendWebSocketMessage("UserUpdated", dto); } diff --git a/MediaBrowser.WebDashboard/Api/DashboardService.cs b/MediaBrowser.WebDashboard/Api/DashboardService.cs index 7756fb5b9a..c773503b01 100644 --- a/MediaBrowser.WebDashboard/Api/DashboardService.cs +++ b/MediaBrowser.WebDashboard/Api/DashboardService.cs @@ -4,6 +4,7 @@ using MediaBrowser.Common.Net; using MediaBrowser.Common.ScheduledTasks; using MediaBrowser.Controller; using MediaBrowser.Controller.Configuration; +using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Plugins; using MediaBrowser.Model.Logging; @@ -192,9 +193,9 @@ namespace MediaBrowser.WebDashboard.Api { var connections = userManager.RecentConnections.ToArray(); - var dtoBuilder = new DtoBuilder(logger, libraryManager, userManager); + var dtoBuilder = new UserDtoBuilder(logger); - var users = userManager.Users.Where(u => connections.Any(c => c.UserId == u.Id)).Select(dtoBuilder.GetUserDto); + var users = userManager.Users.Where(u => connections.Any(c => new Guid(c.UserId) == u.Id)).Select(dtoBuilder.GetUserDto); return new DashboardInfo {