removed excess hashing in providers and made user data key-based

This commit is contained in:
Luke Pulverenti 2013-04-13 14:02:30 -04:00
parent 6688d35e65
commit 785deff188
54 changed files with 512 additions and 678 deletions

View File

@ -2,6 +2,7 @@
using MediaBrowser.Common.IO; using MediaBrowser.Common.IO;
using MediaBrowser.Common.Net; using MediaBrowser.Common.Net;
using MediaBrowser.Controller; using MediaBrowser.Controller;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
using MediaBrowser.Model.Entities; using MediaBrowser.Model.Entities;

View File

@ -1,6 +1,8 @@
using MediaBrowser.Common; using MediaBrowser.Common;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Persistence;
using MediaBrowser.Model.Dto; using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Querying; using MediaBrowser.Model.Querying;
using ServiceStack.ServiceHost; using ServiceStack.ServiceHost;
@ -104,16 +106,16 @@ namespace MediaBrowser.Api.Library
/// </summary> /// </summary>
private readonly IApplicationHost _appHost; private readonly IApplicationHost _appHost;
private readonly ILibraryManager _libraryManager; private readonly ILibraryManager _libraryManager;
private readonly IUserManager _userManager; private readonly IUserDataRepository _userDataRepository;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="LibraryService" /> class. /// Initializes a new instance of the <see cref="LibraryService" /> class.
/// </summary> /// </summary>
/// <param name="appHost">The app host.</param> /// <param name="appHost">The app host.</param>
/// <param name="libraryManager">The library manager.</param> /// <param name="libraryManager">The library manager.</param>
/// <param name="userManager">The user manager.</param> /// <param name="userDataRepository">The user data repository.</param>
/// <exception cref="System.ArgumentNullException">appHost</exception> /// <exception cref="System.ArgumentNullException">appHost</exception>
public LibraryService(IApplicationHost appHost, ILibraryManager libraryManager, IUserManager userManager) public LibraryService(IApplicationHost appHost, ILibraryManager libraryManager, IUserDataRepository userDataRepository)
{ {
if (appHost == null) if (appHost == null)
{ {
@ -122,7 +124,7 @@ namespace MediaBrowser.Api.Library
_appHost = appHost; _appHost = appHost;
_libraryManager = libraryManager; _libraryManager = libraryManager;
_userManager = userManager; _userDataRepository = userDataRepository;
} }
/// <summary> /// <summary>
@ -137,7 +139,7 @@ namespace MediaBrowser.Api.Library
// Get everything // Get everything
var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true)); 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); return ToOptimizedResult(result);
} }
@ -154,7 +156,7 @@ namespace MediaBrowser.Api.Library
// Get everything // Get everything
var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true)); 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); return ToOptimizedResult(result);
} }
@ -171,7 +173,7 @@ namespace MediaBrowser.Api.Library
// Get everything // Get everything
var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true)); 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); return ToOptimizedResult(result);
} }
@ -188,7 +190,7 @@ namespace MediaBrowser.Api.Library
// Get everything // Get everything
var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true)); 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); return ToOptimizedResult(result);
} }

View File

@ -2,6 +2,7 @@
using MediaBrowser.Common.IO; using MediaBrowser.Common.IO;
using MediaBrowser.Common.MediaInfo; using MediaBrowser.Common.MediaInfo;
using MediaBrowser.Controller; using MediaBrowser.Controller;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Providers.MediaInfo; using MediaBrowser.Controller.Providers.MediaInfo;

View File

@ -1,6 +1,7 @@
using System.Threading; using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Persistence;
using MediaBrowser.Model.Dto; using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Querying; using MediaBrowser.Model.Querying;
using ServiceStack.ServiceHost; using ServiceStack.ServiceHost;
@ -8,6 +9,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace MediaBrowser.Api.UserLibrary namespace MediaBrowser.Api.UserLibrary
@ -27,16 +29,19 @@ namespace MediaBrowser.Api.UserLibrary
/// The library manager /// The library manager
/// </summary> /// </summary>
protected readonly ILibraryManager LibraryManager; protected readonly ILibraryManager LibraryManager;
protected readonly IUserDataRepository UserDataRepository;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="BaseItemsByNameService{TItemType}" /> class. /// Initializes a new instance of the <see cref="BaseItemsByNameService{TItemType}" /> class.
/// </summary> /// </summary>
/// <param name="userManager">The user manager.</param> /// <param name="userManager">The user manager.</param>
/// <param name="libraryManager">The library manager.</param> /// <param name="libraryManager">The library manager.</param>
protected BaseItemsByNameService(IUserManager userManager, ILibraryManager libraryManager) /// <param name="userDataRepository">The user data repository.</param>
protected BaseItemsByNameService(IUserManager userManager, ILibraryManager libraryManager, IUserDataRepository userDataRepository)
{ {
UserManager = userManager; UserManager = userManager;
LibraryManager = libraryManager; LibraryManager = libraryManager;
UserDataRepository = userDataRepository;
} }
/// <summary> /// <summary>
@ -132,18 +137,19 @@ namespace MediaBrowser.Api.UserLibrary
/// <returns>IEnumerable{BaseItem}.</returns> /// <returns>IEnumerable{BaseItem}.</returns>
private IEnumerable<BaseItem> FilterItems(GetItemsByName request, IEnumerable<BaseItem> items, User user) private IEnumerable<BaseItem> FilterItems(GetItemsByName request, IEnumerable<BaseItem> items, User user)
{ {
items = items.AsParallel(); // Exclude item types
if (!string.IsNullOrEmpty(request.ExcludeItemTypes))
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))
{ {
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; return items;
} }
@ -185,7 +191,7 @@ namespace MediaBrowser.Api.UserLibrary
return null; 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)) if (fields.Contains(ItemFields.ItemCounts))
{ {
@ -211,13 +217,15 @@ namespace MediaBrowser.Api.UserLibrary
var item = await getItem().ConfigureAwait(false); var item = await getItem().ConfigureAwait(false);
var key = item.GetUserDataKey();
// Get the user data for this item // 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 // Set favorite status
data.IsFavorite = isFavorite; 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);
} }
} }

View File

@ -1,6 +1,6 @@
using System.Threading; using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Persistence;
using ServiceStack.ServiceHost; using ServiceStack.ServiceHost;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@ -18,52 +18,14 @@ namespace MediaBrowser.Api.UserLibrary
public class GetGenres : GetItemsByName public class GetGenres : GetItemsByName
{ {
} }
[Route("/Users/{UserId}/FavoriteGenres/{Name}", "POST")]
[Api(Description = "Marks a genre as a favorite")]
public class MarkFavoriteGenre : IReturnVoid
{
/// <summary>
/// Gets or sets the user id.
/// </summary>
/// <value>The user id.</value>
[ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
public Guid UserId { get; set; }
/// <summary>
/// Gets or sets the name.
/// </summary>
/// <value>The name.</value>
[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
{
/// <summary>
/// Gets or sets the user id.
/// </summary>
/// <value>The user id.</value>
[ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")]
public Guid UserId { get; set; }
/// <summary>
/// Gets or sets the name.
/// </summary>
/// <value>The name.</value>
[ApiMember(Name = "Name", Description = "Name", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")]
public string Name { get; set; }
}
/// <summary> /// <summary>
/// Class GenresService /// Class GenresService
/// </summary> /// </summary>
public class GenresService : BaseItemsByNameService<Genre> public class GenresService : BaseItemsByNameService<Genre>
{ {
public GenresService(IUserManager userManager, ILibraryManager libraryManager) public GenresService(IUserManager userManager, ILibraryManager libraryManager, IUserDataRepository userDataRepository)
: base(userManager, libraryManager) : base(userManager, libraryManager, userDataRepository)
{ {
} }
@ -79,28 +41,6 @@ namespace MediaBrowser.Api.UserLibrary
return ToOptimizedResult(result); return ToOptimizedResult(result);
} }
/// <summary>
/// Posts the specified request.
/// </summary>
/// <param name="request">The request.</param>
public void Post(MarkFavoriteGenre request)
{
var task = MarkFavorite(() => LibraryManager.GetGenre(request.Name), request.UserId, true);
Task.WaitAll(task);
}
/// <summary>
/// Deletes the specified request.
/// </summary>
/// <param name="request">The request.</param>
public void Delete(UnmarkFavoriteGenre request)
{
var task = MarkFavorite(() => LibraryManager.GetGenre(request.Name), request.UserId, false);
Task.WaitAll(task);
}
/// <summary> /// <summary>
/// Gets all items. /// Gets all items.
/// </summary> /// </summary>

View File

@ -1,6 +1,8 @@
using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Persistence;
using MediaBrowser.Model.Entities; using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Querying; using MediaBrowser.Model.Querying;
using ServiceStack.ServiceHost; using ServiceStack.ServiceHost;
@ -148,6 +150,7 @@ namespace MediaBrowser.Api.UserLibrary
/// The _user manager /// The _user manager
/// </summary> /// </summary>
private readonly IUserManager _userManager; private readonly IUserManager _userManager;
private readonly IUserDataRepository _userDataRepository;
/// <summary> /// <summary>
/// The _library manager /// The _library manager
@ -161,11 +164,13 @@ namespace MediaBrowser.Api.UserLibrary
/// <param name="userManager">The user manager.</param> /// <param name="userManager">The user manager.</param>
/// <param name="libraryManager">The library manager.</param> /// <param name="libraryManager">The library manager.</param>
/// <param name="searchEngine">The search engine.</param> /// <param name="searchEngine">The search engine.</param>
public ItemsService(IUserManager userManager, ILibraryManager libraryManager, ILibrarySearchEngine searchEngine) /// <param name="userDataRepository">The user data repository.</param>
public ItemsService(IUserManager userManager, ILibraryManager libraryManager, ILibrarySearchEngine searchEngine, IUserDataRepository userDataRepository)
{ {
_userManager = userManager; _userManager = userManager;
_libraryManager = libraryManager; _libraryManager = libraryManager;
_searchEngine = searchEngine; _searchEngine = searchEngine;
_userDataRepository = userDataRepository;
} }
/// <summary> /// <summary>
@ -199,7 +204,7 @@ namespace MediaBrowser.Api.UserLibrary
// Run them starting with the ones that are likely to reduce the list the most // 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)) 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(); items = items.AsEnumerable();
@ -214,7 +219,7 @@ namespace MediaBrowser.Api.UserLibrary
var fields = request.GetItemFields().ToList(); 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); var returnItems = await Task.WhenAll(pagedItems.Select(i => dtoBuilder.GetBaseItemDto(i, user, fields))).ConfigureAwait(false);
@ -274,9 +279,9 @@ namespace MediaBrowser.Api.UserLibrary
/// <param name="items">The items.</param> /// <param name="items">The items.</param>
/// <param name="filter">The filter.</param> /// <param name="filter">The filter.</param>
/// <param name="user">The user.</param> /// <param name="user">The user.</param>
/// <param name="userManager">The user manager.</param> /// <param name="repository">The repository.</param>
/// <returns>IEnumerable{BaseItem}.</returns> /// <returns>IEnumerable{BaseItem}.</returns>
internal static IEnumerable<BaseItem> ApplyFilter(IEnumerable<BaseItem> items, ItemFilter filter, User user, IUserManager userManager) internal static IEnumerable<BaseItem> ApplyFilter(IEnumerable<BaseItem> items, ItemFilter filter, User user, IUserDataRepository repository)
{ {
// Avoids implicitly captured closure // Avoids implicitly captured closure
var currentUser = user; var currentUser = user;
@ -286,7 +291,7 @@ namespace MediaBrowser.Api.UserLibrary
case ItemFilter.Likes: case ItemFilter.Likes:
return items.Where(item => 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; return userdata != null && userdata.Likes.HasValue && userdata.Likes.Value;
}); });
@ -294,7 +299,7 @@ namespace MediaBrowser.Api.UserLibrary
case ItemFilter.Dislikes: case ItemFilter.Dislikes:
return items.Where(item => 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; return userdata != null && userdata.Likes.HasValue && !userdata.Likes.Value;
}); });
@ -302,7 +307,7 @@ namespace MediaBrowser.Api.UserLibrary
case ItemFilter.IsFavorite: case ItemFilter.IsFavorite:
return items.Where(item => 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; return userdata != null && userdata.IsFavorite;
}); });
@ -313,7 +318,7 @@ namespace MediaBrowser.Api.UserLibrary
case ItemFilter.IsResumable: case ItemFilter.IsResumable:
return items.Where(item => 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; return userdata != null && userdata.PlaybackPositionTicks > 0;
}); });
@ -321,7 +326,7 @@ namespace MediaBrowser.Api.UserLibrary
case ItemFilter.IsPlayed: case ItemFilter.IsPlayed:
return items.Where(item => 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; return userdata != null && userdata.PlayCount > 0;
}); });
@ -329,7 +334,7 @@ namespace MediaBrowser.Api.UserLibrary
case ItemFilter.IsUnplayed: case ItemFilter.IsUnplayed:
return items.Where(item => 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; return userdata == null || userdata.PlayCount == 0;
}); });
@ -347,32 +352,11 @@ namespace MediaBrowser.Api.UserLibrary
/// <summary> /// <summary>
/// Applies the additional filters. /// Applies the additional filters.
/// </summary> /// </summary>
/// <param name="itemsRequest">The items request.</param> /// <param name="request">The request.</param>
/// <param name="items">The items.</param> /// <param name="items">The items.</param>
/// <returns>IEnumerable{BaseItem}.</returns> /// <returns>IEnumerable{BaseItem}.</returns>
internal static IEnumerable<BaseItem> ApplyAdditionalFilters(BaseItemsRequest itemsRequest, IEnumerable<BaseItem> items) internal static IEnumerable<BaseItem> ApplyAdditionalFilters(GetItems request, IEnumerable<BaseItem> 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 // Filter by Series Status
if (!string.IsNullOrEmpty(request.SeriesStatus)) if (!string.IsNullOrEmpty(request.SeriesStatus))
{ {

View File

@ -1,5 +1,6 @@
using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Persistence;
using ServiceStack.ServiceHost; using ServiceStack.ServiceHost;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@ -22,52 +23,14 @@ namespace MediaBrowser.Api.UserLibrary
/// <value>The person types.</value> /// <value>The person types.</value>
public string PersonTypes { get; set; } public string PersonTypes { get; set; }
} }
[Route("/Users/{UserId}/FavoritePersons/{Name}", "POST")]
[Api(Description = "Marks a person as a favorite")]
public class MarkFavoritePerson : IReturnVoid
{
/// <summary>
/// Gets or sets the user id.
/// </summary>
/// <value>The user id.</value>
[ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
public Guid UserId { get; set; }
/// <summary>
/// Gets or sets the name.
/// </summary>
/// <value>The name.</value>
[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
{
/// <summary>
/// Gets or sets the user id.
/// </summary>
/// <value>The user id.</value>
[ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")]
public Guid UserId { get; set; }
/// <summary>
/// Gets or sets the name.
/// </summary>
/// <value>The name.</value>
[ApiMember(Name = "Name", Description = "Name", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")]
public string Name { get; set; }
}
/// <summary> /// <summary>
/// Class PersonsService /// Class PersonsService
/// </summary> /// </summary>
public class PersonsService : BaseItemsByNameService<Person> public class PersonsService : BaseItemsByNameService<Person>
{ {
public PersonsService(IUserManager userManager, ILibraryManager libraryManager) public PersonsService(IUserManager userManager, ILibraryManager libraryManager, IUserDataRepository userDataRepository)
: base(userManager, libraryManager) : base(userManager, libraryManager, userDataRepository)
{ {
} }
@ -83,28 +46,6 @@ namespace MediaBrowser.Api.UserLibrary
return ToOptimizedResult(result); return ToOptimizedResult(result);
} }
/// <summary>
/// Posts the specified request.
/// </summary>
/// <param name="request">The request.</param>
public void Post(MarkFavoritePerson request)
{
var task = MarkFavorite(() => LibraryManager.GetPerson(request.Name), request.UserId, true);
Task.WaitAll(task);
}
/// <summary>
/// Deletes the specified request.
/// </summary>
/// <param name="request">The request.</param>
public void Delete(UnmarkFavoritePerson request)
{
var task = MarkFavorite(() => LibraryManager.GetPerson(request.Name), request.UserId, false);
Task.WaitAll(task);
}
/// <summary> /// <summary>
/// Gets all items. /// Gets all items.
/// </summary> /// </summary>

View File

@ -1,5 +1,6 @@
using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Persistence;
using ServiceStack.ServiceHost; using ServiceStack.ServiceHost;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@ -17,52 +18,14 @@ namespace MediaBrowser.Api.UserLibrary
public class GetStudios : GetItemsByName public class GetStudios : GetItemsByName
{ {
} }
[Route("/Users/{UserId}/FavoriteStudios/{Name}", "POST")]
[Api(Description = "Marks a studio as a favorite")]
public class MarkFavoriteStudio : IReturnVoid
{
/// <summary>
/// Gets or sets the user id.
/// </summary>
/// <value>The user id.</value>
[ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
public Guid UserId { get; set; }
/// <summary>
/// Gets or sets the name.
/// </summary>
/// <value>The name.</value>
[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
{
/// <summary>
/// Gets or sets the user id.
/// </summary>
/// <value>The user id.</value>
[ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")]
public Guid UserId { get; set; }
/// <summary>
/// Gets or sets the name.
/// </summary>
/// <value>The name.</value>
[ApiMember(Name = "Name", Description = "Name", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")]
public string Name { get; set; }
}
/// <summary> /// <summary>
/// Class StudiosService /// Class StudiosService
/// </summary> /// </summary>
public class StudiosService : BaseItemsByNameService<Studio> public class StudiosService : BaseItemsByNameService<Studio>
{ {
public StudiosService(IUserManager userManager, ILibraryManager libraryManager) public StudiosService(IUserManager userManager, ILibraryManager libraryManager, IUserDataRepository userDataRepository)
: base(userManager, libraryManager) : base(userManager, libraryManager, userDataRepository)
{ {
} }
@ -77,28 +40,6 @@ namespace MediaBrowser.Api.UserLibrary
return ToOptimizedResult(result); return ToOptimizedResult(result);
} }
/// <summary>
/// Posts the specified request.
/// </summary>
/// <param name="request">The request.</param>
public void Post(MarkFavoriteStudio request)
{
var task = MarkFavorite(() => LibraryManager.GetStudio(request.Name), request.UserId, true);
Task.WaitAll(task);
}
/// <summary>
/// Deletes the specified request.
/// </summary>
/// <param name="request">The request.</param>
public void Delete(UnmarkFavoriteStudio request)
{
var task = MarkFavorite(() => LibraryManager.GetStudio(request.Name), request.UserId, false);
Task.WaitAll(task);
}
/// <summary> /// <summary>
/// Gets all items. /// Gets all items.

View File

@ -1,6 +1,8 @@
using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Entities.Movies;
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Persistence;
using MediaBrowser.Model.Dto; using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Querying; using MediaBrowser.Model.Querying;
using ServiceStack.ServiceHost; using ServiceStack.ServiceHost;
@ -335,18 +337,19 @@ namespace MediaBrowser.Api.UserLibrary
/// The _user manager /// The _user manager
/// </summary> /// </summary>
private readonly IUserManager _userManager; private readonly IUserManager _userManager;
private readonly IUserDataRepository _userDataRepository;
private readonly ILibraryManager _libraryManager; private readonly ILibraryManager _libraryManager;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="UserLibraryService" /> class. /// Initializes a new instance of the <see cref="UserLibraryService" /> class.
/// </summary> /// </summary>
/// <exception cref="System.ArgumentNullException">jsonSerializer</exception> /// <exception cref="System.ArgumentNullException">jsonSerializer</exception>
public UserLibraryService(IUserManager userManager, ILibraryManager libraryManager) public UserLibraryService(IUserManager userManager, ILibraryManager libraryManager, IUserDataRepository userDataRepository)
: base() : base()
{ {
_userManager = userManager; _userManager = userManager;
_libraryManager = libraryManager; _libraryManager = libraryManager;
_userDataRepository = userDataRepository;
} }
/// <summary> /// <summary>
@ -365,7 +368,7 @@ namespace MediaBrowser.Api.UserLibrary
var movie = (Movie)item; 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(); 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 // Get everything
var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true)).ToList(); 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(); 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 // Get everything
var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true)).ToList(); 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; var result = dtoBuilder.GetBaseItemDto(item, user, fields).Result;
@ -423,7 +426,7 @@ namespace MediaBrowser.Api.UserLibrary
// Get everything // Get everything
var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true)).ToList(); 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; 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); var item = string.IsNullOrEmpty(request.Id) ? user.RootFolder : DtoBuilder.GetItemByClientId(request.Id, _userManager, _libraryManager, user.Id);
// Get the user data for this item // 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 // Set favorite status
data.IsFavorite = true; 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); 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 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 // 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 // Set favorite status
data.IsFavorite = false; 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); 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 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 // 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; 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); 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 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 // 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; 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); Task.WaitAll(task);
} }
@ -623,7 +634,7 @@ namespace MediaBrowser.Api.UserLibrary
{ {
var item = DtoBuilder.GetItemByClientId(itemId, _userManager, _libraryManager, user.Id); var item = DtoBuilder.GetItemByClientId(itemId, _userManager, _libraryManager, user.Id);
return item.SetPlayedStatus(user, wasPlayed, _userManager); return item.SetPlayedStatus(user, wasPlayed, _userDataRepository);
} }
} }
} }

View File

@ -1,5 +1,6 @@
using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Persistence;
using ServiceStack.ServiceHost; using ServiceStack.ServiceHost;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@ -28,9 +29,9 @@ namespace MediaBrowser.Api.UserLibrary
/// The us culture /// The us culture
/// </summary> /// </summary>
private static readonly CultureInfo UsCulture = new CultureInfo("en-US"); private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
public YearsService(IUserManager userManager, ILibraryManager libraryManager) public YearsService(IUserManager userManager, ILibraryManager libraryManager, IUserDataRepository userDataRepository)
: base(userManager, libraryManager) : base(userManager, libraryManager, userDataRepository)
{ {
} }

View File

@ -1,4 +1,5 @@
using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Extensions;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
using MediaBrowser.Model.Dto; using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Serialization; using MediaBrowser.Model.Serialization;
@ -165,7 +166,7 @@ namespace MediaBrowser.Api
/// <returns>System.Object.</returns> /// <returns>System.Object.</returns>
public object Get(GetUsers request) 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(); 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"); 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); return ToOptimizedResult(result);
} }
@ -300,7 +303,9 @@ namespace MediaBrowser.Api
newUser.UpdateConfiguration(dtoUser.Configuration, _xmlSerializer); 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); return ToOptimizedResult(result);
} }

View File

@ -1,6 +1,4 @@
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography; using System.Security.Cryptography;
using System.Text; using System.Text;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
@ -55,26 +53,6 @@ namespace MediaBrowser.Common.Extensions
return (aType.FullName + str.ToLower()).GetMD5(); return (aType.FullName + str.ToLower()).GetMD5();
} }
/// <summary>
/// Helper method for Dictionaries since they throw on not-found keys
/// </summary>
/// <typeparam name="T"></typeparam>
/// <typeparam name="U"></typeparam>
/// <param name="dictionary">The dictionary.</param>
/// <param name="key">The key.</param>
/// <param name="defaultValue">The default value.</param>
/// <returns>``1.</returns>
public static U GetValueOrDefault<T, U>(this Dictionary<T, U> dictionary, T key, U defaultValue)
{
U val;
if (!dictionary.TryGetValue(key, out val))
{
val = defaultValue;
}
return val;
}
/// <summary> /// <summary>
/// Gets the attribute value. /// Gets the attribute value.
/// </summary> /// </summary>

View File

@ -302,7 +302,7 @@ namespace MediaBrowser.Common.Plugins
AssemblyFileName = AssemblyFileName, AssemblyFileName = AssemblyFileName,
ConfigurationDateLastModified = ConfigurationDateLastModified, ConfigurationDateLastModified = ConfigurationDateLastModified,
Description = Description, Description = Description,
Id = Id, Id = Id.ToString(),
EnableAutoUpdate = Configuration.EnableAutoUpdate, EnableAutoUpdate = Configuration.EnableAutoUpdate,
UpdateClass = Configuration.UpdateClass, UpdateClass = Configuration.UpdateClass,
ConfigurationFileName = ConfigurationFileName ConfigurationFileName = ConfigurationFileName

View File

@ -3,6 +3,8 @@ using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Entities.Movies;
using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Persistence;
using MediaBrowser.Model.Drawing; using MediaBrowser.Model.Drawing;
using MediaBrowser.Model.Dto; using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities; using MediaBrowser.Model.Entities;
@ -14,7 +16,7 @@ using System.IO;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace MediaBrowser.Controller.Library namespace MediaBrowser.Controller.Dto
{ {
/// <summary> /// <summary>
/// Generates DTO's from domain entities /// Generates DTO's from domain entities
@ -28,13 +30,13 @@ namespace MediaBrowser.Controller.Library
private readonly ILogger _logger; private readonly ILogger _logger;
private readonly ILibraryManager _libraryManager; 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; _logger = logger;
_libraryManager = libraryManager; _libraryManager = libraryManager;
_userManager = userManager; _userDataRepository = userDataRepository;
} }
/// <summary> /// <summary>
@ -73,7 +75,7 @@ namespace MediaBrowser.Controller.Library
{ {
try try
{ {
AttachPrimaryImageAspectRatio(dto, item); AttachPrimaryImageAspectRatio(dto, item, _logger);
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -136,7 +138,7 @@ namespace MediaBrowser.Controller.Library
{ {
try try
{ {
AttachPrimaryImageAspectRatio(dto, item); AttachPrimaryImageAspectRatio(dto, item, _logger);
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -167,7 +169,7 @@ namespace MediaBrowser.Controller.Library
{ {
if (fields.Contains(ItemFields.UserData)) 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); dto.UserData = GetUserItemDataDto(userData);
} }
@ -186,18 +188,19 @@ namespace MediaBrowser.Controller.Library
// Skip sorting since all we want is a count // Skip sorting since all we want is a count
dto.ChildCount = folder.GetChildren(user).Count(); dto.ChildCount = folder.GetChildren(user).Count();
await SetSpecialCounts(folder, user, dto, _userManager).ConfigureAwait(false); await SetSpecialCounts(folder, user, dto, _userDataRepository).ConfigureAwait(false);
} }
} }
} }
/// <summary> /// <summary>
/// Attaches the primary image aspect ratio. /// Attaches the primary image aspect ratio.
/// </summary> /// </summary>
/// <param name="dto">The dto.</param> /// <param name="dto">The dto.</param>
/// <param name="item">The item.</param> /// <param name="item">The item.</param>
/// <param name="_logger">The _logger.</param>
/// <returns>Task.</returns> /// <returns>Task.</returns>
private void AttachPrimaryImageAspectRatio(IItemDto dto, BaseItem item) internal static void AttachPrimaryImageAspectRatio(IItemDto dto, BaseItem item, ILogger _logger)
{ {
var path = item.PrimaryImagePath; var path = item.PrimaryImagePath;
@ -503,9 +506,9 @@ namespace MediaBrowser.Controller.Library
/// <param name="folder">The folder.</param> /// <param name="folder">The folder.</param>
/// <param name="user">The user.</param> /// <param name="user">The user.</param>
/// <param name="dto">The dto.</param> /// <param name="dto">The dto.</param>
/// <param name="userManager">The user manager.</param> /// <param name="userDataRepository">The user data repository.</param>
/// <returns>Task.</returns> /// <returns>Task.</returns>
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 rcentlyAddedItemCount = 0;
var recursiveItemCount = 0; var recursiveItemCount = 0;
@ -515,7 +518,7 @@ namespace MediaBrowser.Controller.Library
// Loop through each recursive child // Loop through each recursive child
foreach (var child in folder.GetRecursiveChildren(user).Where(i => !i.IsFolder)) 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++; recursiveItemCount++;
@ -785,49 +788,6 @@ namespace MediaBrowser.Controller.Library
return item.Id.ToString(); return item.Id.ToString();
} }
/// <summary>
/// Converts a User to a DTOUser
/// </summary>
/// <param name="user">The user.</param>
/// <returns>DtoUser.</returns>
/// <exception cref="System.ArgumentNullException">user</exception>
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;
}
/// <summary> /// <summary>
/// Gets a BaseItem based upon it's client-side item id /// Gets a BaseItem based upon it's client-side item id
/// </summary> /// </summary>

View File

@ -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
{
/// <summary>
/// Class UserDtoBuilder
/// </summary>
public class UserDtoBuilder
{
/// <summary>
/// The _logger
/// </summary>
private readonly ILogger _logger;
/// <summary>
/// Initializes a new instance of the <see cref="UserDtoBuilder"/> class.
/// </summary>
/// <param name="logger">The logger.</param>
public UserDtoBuilder(ILogger logger)
{
_logger = logger;
}
/// <summary>
/// Converts a User to a DTOUser
/// </summary>
/// <param name="user">The user.</param>
/// <returns>DtoUser.</returns>
/// <exception cref="System.ArgumentNullException">user</exception>
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;
}
}
}

View File

@ -3,6 +3,7 @@ using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.IO; using MediaBrowser.Controller.IO;
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Localization; using MediaBrowser.Controller.Localization;
using MediaBrowser.Controller.Persistence;
using MediaBrowser.Controller.Providers; using MediaBrowser.Controller.Providers;
using MediaBrowser.Controller.Resolvers; using MediaBrowser.Controller.Resolvers;
using MediaBrowser.Model.Entities; using MediaBrowser.Model.Entities;
@ -183,23 +184,18 @@ namespace MediaBrowser.Controller.Entities
/// <summary> /// <summary>
/// The _file system stamp /// The _file system stamp
/// </summary> /// </summary>
private Guid? _fileSystemStamp; private string _fileSystemStamp;
/// <summary> /// <summary>
/// Gets a directory stamp, in the form of a string, that can be used for /// 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. /// comparison purposes to determine if the file system entries for this item have changed.
/// </summary> /// </summary>
/// <value>The file system stamp.</value> /// <value>The file system stamp.</value>
[IgnoreDataMember] [IgnoreDataMember]
public Guid FileSystemStamp public string FileSystemStamp
{ {
get get
{ {
if (!_fileSystemStamp.HasValue) return _fileSystemStamp ?? (_fileSystemStamp = GetFileSystemStamp());
{
_fileSystemStamp = GetFileSystemStamp();
}
return _fileSystemStamp.Value;
} }
} }
@ -221,12 +217,12 @@ namespace MediaBrowser.Controller.Entities
/// comparison purposes to determine if the file system entries for this item have changed. /// comparison purposes to determine if the file system entries for this item have changed.
/// </summary> /// </summary>
/// <returns>Guid.</returns> /// <returns>Guid.</returns>
private Guid GetFileSystemStamp() private string GetFileSystemStamp()
{ {
// If there's no path or the item is a file, there's nothing to do // If there's no path or the item is a file, there's nothing to do
if (LocationType != LocationType.FileSystem || !ResolveArgs.IsDirectory) if (LocationType != LocationType.FileSystem || !ResolveArgs.IsDirectory)
{ {
return Guid.Empty; return string.Empty;
} }
var sb = new StringBuilder(); var sb = new StringBuilder();
@ -242,7 +238,7 @@ namespace MediaBrowser.Controller.Entities
sb.Append(file.cFileName); sb.Append(file.cFileName);
} }
return sb.ToString().GetMD5(); return sb.ToString();
} }
/// <summary> /// <summary>
@ -820,21 +816,12 @@ namespace MediaBrowser.Controller.Entities
} }
/// <summary> /// <summary>
/// The _user data id /// Gets the user data key.
/// </summary> /// </summary>
protected Guid _userDataId; //cache this so it doesn't have to be re-constructed on every reference /// <returns>System.String.</returns>
/// <summary> public virtual string GetUserDataKey()
/// 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.
/// </summary>
/// <value>The user data id.</value>
[IgnoreDataMember]
public virtual Guid UserDataId
{ {
get return Id.ToString();
{
return _userDataId == Guid.Empty ? (_userDataId = Id) : _userDataId;
}
} }
/// <summary> /// <summary>
@ -1151,14 +1138,16 @@ namespace MediaBrowser.Controller.Entities
/// <param name="userManager">The user manager.</param> /// <param name="userManager">The user manager.</param>
/// <returns>Task.</returns> /// <returns>Task.</returns>
/// <exception cref="System.ArgumentNullException"></exception> /// <exception cref="System.ArgumentNullException"></exception>
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) if (user == null)
{ {
throw new ArgumentNullException(); 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) if (wasPlayed)
{ {
@ -1181,7 +1170,7 @@ namespace MediaBrowser.Controller.Entities
data.Played = wasPlayed; 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);
} }
/// <summary> /// <summary>

View File

@ -3,6 +3,7 @@ using MediaBrowser.Common.Progress;
using MediaBrowser.Controller.IO; using MediaBrowser.Controller.IO;
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Localization; using MediaBrowser.Controller.Localization;
using MediaBrowser.Controller.Persistence;
using MediaBrowser.Controller.Resolvers; using MediaBrowser.Controller.Resolvers;
using MediaBrowser.Model.Entities; using MediaBrowser.Model.Entities;
using System; using System;
@ -809,7 +810,7 @@ namespace MediaBrowser.Controller.Entities
/// <param name="wasPlayed">if set to <c>true</c> [was played].</param> /// <param name="wasPlayed">if set to <c>true</c> [was played].</param>
/// <param name="userManager">The user manager.</param> /// <param name="userManager">The user manager.</param>
/// <returns>Task.</returns> /// <returns>Task.</returns>
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); await base.SetPlayedStatus(user, wasPlayed, userManager).ConfigureAwait(false);

View File

@ -6,5 +6,13 @@ namespace MediaBrowser.Controller.Entities
/// </summary> /// </summary>
public class Genre : BaseItem public class Genre : BaseItem
{ {
/// <summary>
/// Gets the user data key.
/// </summary>
/// <returns>System.String.</returns>
public override string GetUserDataKey()
{
return Name;
}
} }
} }

View File

@ -1,7 +1,5 @@
using MediaBrowser.Common.Extensions; using MediaBrowser.Controller.IO;
using MediaBrowser.Controller.IO;
using MediaBrowser.Model.Entities; using MediaBrowser.Model.Entities;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
@ -30,21 +28,12 @@ namespace MediaBrowser.Controller.Entities.Movies
} }
/// <summary> /// <summary>
/// Override to use tmdb or imdb id so it will stick if the item moves physical locations /// Gets the user data key.
/// </summary> /// </summary>
/// <value>The user data id.</value> /// <returns>System.String.</returns>
[IgnoreDataMember] public override string GetUserDataKey()
public override Guid UserDataId
{ {
get return this.GetProviderId(MetadataProviders.Tmdb) ?? this.GetProviderId(MetadataProviders.Imdb) ?? base.GetUserDataKey();
{
if (_userDataId == Guid.Empty)
{
var baseId = this.GetProviderId(MetadataProviders.Tmdb) ?? this.GetProviderId(MetadataProviders.Imdb);
_userDataId = baseId != null ? baseId.GetMD5() : Id;
}
return _userDataId;
}
} }
/// <summary> /// <summary>

View File

@ -6,6 +6,14 @@ namespace MediaBrowser.Controller.Entities
/// </summary> /// </summary>
public class Person : BaseItem public class Person : BaseItem
{ {
/// <summary>
/// Gets the user data key.
/// </summary>
/// <returns>System.String.</returns>
public override string GetUserDataKey()
{
return Name;
}
} }
/// <summary> /// <summary>

View File

@ -6,5 +6,13 @@ namespace MediaBrowser.Controller.Entities
/// </summary> /// </summary>
public class Studio : BaseItem public class Studio : BaseItem
{ {
/// <summary>
/// Gets the user data key.
/// </summary>
/// <returns>System.String.</returns>
public override string GetUserDataKey()
{
return Name;
}
} }
} }

View File

@ -49,27 +49,19 @@ namespace MediaBrowser.Controller.Entities.TV
} }
/// <summary> /// <summary>
/// Override to use the provider Ids + season and episode number so it will be portable /// Gets the user data key.
/// </summary> /// </summary>
/// <value>The user data id.</value> /// <returns>System.String.</returns>
[IgnoreDataMember] public override string GetUserDataKey()
public override Guid UserDataId
{ {
get if (Series != null)
{ {
if (_userDataId == Guid.Empty) var seasonNo = Season != null ? Season.IndexNumber ?? 0 : 0;
{ var epNo = IndexNumber ?? 0;
var baseId = Series != null ? Series.GetProviderId(MetadataProviders.Tvdb) ?? Series.GetProviderId(MetadataProviders.Tvcom) : null; return Series.GetUserDataKey() + seasonNo.ToString("000") + epNo.ToString("000");
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;
} }
return base.GetUserDataKey();
} }
/// <summary> /// <summary>

View File

@ -67,27 +67,18 @@ namespace MediaBrowser.Controller.Entities.TV
} }
/// <summary> /// <summary>
/// Override to use the provider Ids + season number so it will be portable /// Gets the user data key.
/// </summary> /// </summary>
/// <value>The user data id.</value> /// <returns>System.String.</returns>
[IgnoreDataMember] public override string GetUserDataKey()
public override Guid UserDataId
{ {
get if (Series != null)
{ {
if (_userDataId == Guid.Empty) var seasonNo = IndexNumber ?? 0;
{ return Series.GetUserDataKey() + seasonNo.ToString("000");
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;
} }
return base.GetUserDataKey();
} }
/// <summary> /// <summary>

View File

@ -44,21 +44,12 @@ namespace MediaBrowser.Controller.Entities.TV
} }
/// <summary> /// <summary>
/// Override to use the provider Ids so it will be portable /// Gets the user data key.
/// </summary> /// </summary>
/// <value>The user data id.</value> /// <returns>System.String.</returns>
[IgnoreDataMember] public override string GetUserDataKey()
public override Guid UserDataId
{ {
get return this.GetProviderId(MetadataProviders.Tvdb) ?? this.GetProviderId(MetadataProviders.Tvcom) ?? base.GetUserDataKey();
{
if (_userDataId == Guid.Empty)
{
var baseId = this.GetProviderId(MetadataProviders.Tvdb) ?? this.GetProviderId(MetadataProviders.Tvcom);
_userDataId = baseId != null ? baseId.GetMD5() : Id;
}
return _userDataId;
}
} }
// Studio, Genre and Rating will all be the same so makes no sense to index by these // Studio, Genre and Rating will all be the same so makes no sense to index by these

View File

@ -6,5 +6,13 @@ namespace MediaBrowser.Controller.Entities
/// </summary> /// </summary>
public class Year : BaseItem public class Year : BaseItem
{ {
/// <summary>
/// Gets the user data key.
/// </summary>
/// <returns>System.String.</returns>
public override string GetUserDataKey()
{
return Name;
}
} }
} }

View File

@ -173,24 +173,5 @@ namespace MediaBrowser.Controller.Library
/// <param name="newPassword">The new password.</param> /// <param name="newPassword">The new password.</param>
/// <returns>Task.</returns> /// <returns>Task.</returns>
Task ChangePassword(User user, string newPassword); Task ChangePassword(User user, string newPassword);
/// <summary>
/// Saves the user data.
/// </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 user data.
/// </summary>
/// <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);
} }
} }

View File

@ -72,6 +72,7 @@
<Compile Include="Drawing\ImageExtensions.cs" /> <Compile Include="Drawing\ImageExtensions.cs" />
<Compile Include="Drawing\ImageHeader.cs" /> <Compile Include="Drawing\ImageHeader.cs" />
<Compile Include="Drawing\ImageManager.cs" /> <Compile Include="Drawing\ImageManager.cs" />
<Compile Include="Dto\UserDtoBuilder.cs" />
<Compile Include="Entities\AggregateFolder.cs" /> <Compile Include="Entities\AggregateFolder.cs" />
<Compile Include="Entities\Audio\Audio.cs" /> <Compile Include="Entities\Audio\Audio.cs" />
<Compile Include="Entities\Audio\MusicAlbum.cs" /> <Compile Include="Entities\Audio\MusicAlbum.cs" />
@ -107,7 +108,7 @@
<Compile Include="IServerApplicationHost.cs" /> <Compile Include="IServerApplicationHost.cs" />
<Compile Include="IServerApplicationPaths.cs" /> <Compile Include="IServerApplicationPaths.cs" />
<Compile Include="Library\ChildrenChangedEventArgs.cs" /> <Compile Include="Library\ChildrenChangedEventArgs.cs" />
<Compile Include="Library\DtoBuilder.cs" /> <Compile Include="Dto\DtoBuilder.cs" />
<Compile Include="Providers\IProviderManager.cs" /> <Compile Include="Providers\IProviderManager.cs" />
<Compile Include="Providers\MediaInfo\MediaEncoderHelpers.cs" /> <Compile Include="Providers\MediaInfo\MediaEncoderHelpers.cs" />
<Compile Include="Providers\MetadataProviderPriority.cs" /> <Compile Include="Providers\MetadataProviderPriority.cs" />

View File

@ -1,5 +1,5 @@
using MediaBrowser.Controller.Entities; using System;
using System; using MediaBrowser.Controller.Entities;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -14,19 +14,19 @@ namespace MediaBrowser.Controller.Persistence
/// Saves the user data. /// Saves the user data.
/// </summary> /// </summary>
/// <param name="userId">The user id.</param> /// <param name="userId">The user id.</param>
/// <param name="userDataId">The user data id.</param> /// <param name="key">The key.</param>
/// <param name="userData">The user data.</param> /// <param name="userData">The user data.</param>
/// <param name="cancellationToken">The cancellation token.</param> /// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns> /// <returns>Task.</returns>
Task SaveUserData(Guid userId, Guid userDataId, UserItemData userData, Task SaveUserData(Guid userId, string key, UserItemData userData,
CancellationToken cancellationToken); CancellationToken cancellationToken);
/// <summary> /// <summary>
/// Gets the user data. /// Gets the user data.
/// </summary> /// </summary>
/// <param name="userId">The user id.</param> /// <param name="userId">The user id.</param>
/// <param name="userDataId">The user data id.</param> /// <param name="key">The key.</param>
/// <returns>Task{UserItemData}.</returns> /// <returns>Task{UserItemData}.</returns>
Task<UserItemData> GetUserData(Guid userId, Guid userDataId); Task<UserItemData> GetUserData(Guid userId, string key);
} }
} }

View File

@ -29,19 +29,7 @@ namespace MediaBrowser.Controller.Providers
/// <summary> /// <summary>
/// The _id /// The _id
/// </summary> /// </summary>
protected Guid _id; protected readonly Guid Id;
/// <summary>
/// Gets the id.
/// </summary>
/// <value>The id.</value>
public virtual Guid Id
{
get
{
if (_id == Guid.Empty) _id = GetType().FullName.GetMD5();
return _id;
}
}
/// <summary> /// <summary>
/// Supportses the specified item. /// Supportses the specified item.
@ -105,6 +93,7 @@ namespace MediaBrowser.Controller.Providers
Logger = logManager.GetLogger(GetType().Name); Logger = logManager.GetLogger(GetType().Name);
LogManager = logManager; LogManager = logManager;
ConfigurationManager = configurationManager; ConfigurationManager = configurationManager;
Id = GetType().FullName.GetMD5();
Initialize(); Initialize();
} }
@ -130,8 +119,14 @@ namespace MediaBrowser.Controller.Providers
{ {
throw new ArgumentNullException("item"); 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.LastRefreshed = value;
data.LastRefreshStatus = status; data.LastRefreshStatus = status;
data.ProviderVersion = providerVersion; data.ProviderVersion = providerVersion;
@ -155,7 +150,7 @@ namespace MediaBrowser.Controller.Providers
{ {
SetLastRefreshed(item, value, ProviderVersion, status); SetLastRefreshed(item, value, ProviderVersion, status);
} }
/// <summary> /// <summary>
/// Returns whether or not this provider should be re-fetched. Default functionality can /// 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 /// 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(); 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);
} }
/// <summary> /// <summary>
@ -194,7 +194,7 @@ namespace MediaBrowser.Controller.Providers
{ {
throw new ArgumentNullException("providerInfo"); throw new ArgumentNullException("providerInfo");
} }
if (CompareDate(item) > providerInfo.LastRefreshed) if (CompareDate(item) > providerInfo.LastRefreshed)
{ {
return true; return true;
@ -209,7 +209,7 @@ namespace MediaBrowser.Controller.Providers
{ {
return true; return true;
} }
return false; return false;
} }
@ -221,7 +221,7 @@ namespace MediaBrowser.Controller.Providers
/// <returns><c>true</c> if [has file system stamp changed] [the specified item]; otherwise, <c>false</c>.</returns> /// <returns><c>true</c> if [has file system stamp changed] [the specified item]; otherwise, <c>false</c>.</returns>
protected bool HasFileSystemStampChanged(BaseItem item, BaseProviderInfo providerInfo) protected bool HasFileSystemStampChanged(BaseItem item, BaseProviderInfo providerInfo)
{ {
return GetCurrentFileSystemStamp(item) != providerInfo.FileSystemStamp; return !string.Equals(GetCurrentFileSystemStamp(item), providerInfo.FileSystemStamp);
} }
/// <summary> /// <summary>
@ -279,7 +279,7 @@ namespace MediaBrowser.Controller.Providers
/// </summary> /// </summary>
/// <param name="item">The item.</param> /// <param name="item">The item.</param>
/// <returns>Guid.</returns> /// <returns>Guid.</returns>
private Guid GetCurrentFileSystemStamp(BaseItem item) private string GetCurrentFileSystemStamp(BaseItem item)
{ {
if (UseParentFileSystemStamp(item) && item.Parent != null) if (UseParentFileSystemStamp(item) && item.Parent != null)
{ {

View File

@ -7,11 +7,6 @@ namespace MediaBrowser.Controller.Providers
/// </summary> /// </summary>
public class BaseProviderInfo public class BaseProviderInfo
{ {
/// <summary>
/// Gets or sets the provider id.
/// </summary>
/// <value>The provider id.</value>
public Guid ProviderId { get; set; }
/// <summary> /// <summary>
/// Gets or sets the last refreshed. /// Gets or sets the last refreshed.
/// </summary> /// </summary>
@ -21,7 +16,7 @@ namespace MediaBrowser.Controller.Providers
/// Gets or sets the file system stamp. /// Gets or sets the file system stamp.
/// </summary> /// </summary>
/// <value>The file system stamp.</value> /// <value>The file system stamp.</value>
public Guid FileSystemStamp { get; set; } public string FileSystemStamp { get; set; }
/// <summary> /// <summary>
/// Gets or sets the last refresh status. /// Gets or sets the last refresh status.
/// </summary> /// </summary>
@ -32,11 +27,6 @@ namespace MediaBrowser.Controller.Providers
/// </summary> /// </summary>
/// <value>The provider version.</value> /// <value>The provider version.</value>
public string ProviderVersion { get; set; } public string ProviderVersion { get; set; }
/// <summary>
/// Gets or sets the data hash.
/// </summary>
/// <value>The data hash.</value>
public Guid DataHash { get; set; }
} }
/// <summary> /// <summary>

View File

@ -104,7 +104,14 @@ namespace MediaBrowser.Controller.Providers.Movies
cancellationToken.ThrowIfCancellationRequested(); cancellationToken.ThrowIfCancellationRequested();
var movie = item; 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 language = ConfigurationManager.Configuration.PreferredMetadataLanguage.ToLower();
var url = string.Format(FanArtBaseUrl, APIKey, movie.GetProviderId(MetadataProviders.Tmdb)); var url = string.Format(FanArtBaseUrl, APIKey, movie.GetProviderId(MetadataProviders.Tmdb));

View File

@ -22,10 +22,11 @@ namespace MediaBrowser.Controller.Providers.Movies
{ {
class MovieDbProviderException : ApplicationException class MovieDbProviderException : ApplicationException
{ {
public MovieDbProviderException(string msg) : base(msg) public MovieDbProviderException(string msg)
: base(msg)
{ {
} }
} }
/// <summary> /// <summary>
/// Class MovieDbProvider /// Class MovieDbProvider
@ -33,7 +34,7 @@ namespace MediaBrowser.Controller.Providers.Movies
public class MovieDbProvider : BaseMetadataProvider, IDisposable public class MovieDbProvider : BaseMetadataProvider, IDisposable
{ {
protected readonly IProviderManager ProviderManager; protected readonly IProviderManager ProviderManager;
/// <summary> /// <summary>
/// The movie db /// The movie db
/// </summary> /// </summary>
@ -198,7 +199,7 @@ namespace MediaBrowser.Controller.Providers.Movies
base_url = "http://cf2.imgobject.com/t/p/" 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 //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 //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); 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; data.LastRefreshed = value;
item.ProviderData[JsonProvider.Id] = data; item.ProviderData[JsonProvider.Id] = data;
} }

View File

@ -1,4 +1,5 @@
using MediaBrowser.Common.Extensions; using System.Collections.Generic;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Entities.Audio;
@ -52,14 +53,15 @@ namespace MediaBrowser.Controller.Providers.Music
//Look at our parent for our album cover //Look at our parent for our album cover
var artist = (MusicArtist)item.Parent; 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) if (cover == null)
{ {
// Not there - maybe it is new since artist last refreshed so refresh it and try again // Not there - maybe it is new since artist last refreshed so refresh it and try again
await artist.RefreshMetadata(cancellationToken).ConfigureAwait(false); await artist.RefreshMetadata(cancellationToken).ConfigureAwait(false);
cancellationToken.ThrowIfCancellationRequested(); 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) 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)); item.SetImage(ImageType.Primary, await _providerManager.DownloadAndSaveImage(item, cover, "folder.jpg", FanArtResourcePool, cancellationToken).ConfigureAwait(false));
return true; return true;
} }
/// <summary>
/// Helper method for Dictionaries since they throw on not-found keys
/// </summary>
/// <typeparam name="T"></typeparam>
/// <typeparam name="U"></typeparam>
/// <param name="dictionary">The dictionary.</param>
/// <param name="key">The key.</param>
/// <param name="defaultValue">The default value.</param>
/// <returns>``1.</returns>
private static U GetValueOrDefault<T, U>(Dictionary<T, U> dictionary, T key, U defaultValue)
{
U val;
if (!dictionary.TryGetValue(key, out val))
{
val = defaultValue;
}
return val;
}
} }
} }

View File

@ -86,7 +86,15 @@ namespace MediaBrowser.Controller.Providers.Music
cancellationToken.ThrowIfCancellationRequested(); cancellationToken.ThrowIfCancellationRequested();
var artist = (MusicArtist)item; 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 url = string.Format(FanArtBaseUrl, APIKey, artist.GetProviderId(MetadataProviders.Musicbrainz));
var doc = new XmlDocument(); var doc = new XmlDocument();

View File

@ -229,7 +229,13 @@ namespace MediaBrowser.Controller.Providers.Music
cancellationToken.ThrowIfCancellationRequested(); 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)) if (!ConfigurationManager.Configuration.SaveLocalMeta || !HasLocalMeta(item) || (force && !HasLocalMeta(item)) || (RefreshOnVersionChange && providerData.ProviderVersion != ProviderVersion))
{ {
try try

View File

@ -60,7 +60,15 @@ namespace MediaBrowser.Controller.Providers.TV
cancellationToken.ThrowIfCancellationRequested(); cancellationToken.ThrowIfCancellationRequested();
var series = (Series)item; 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 language = ConfigurationManager.Configuration.PreferredMetadataLanguage.ToLower();
string url = string.Format(FanArtBaseUrl, APIKey, series.GetProviderId(MetadataProviders.Tvdb)); string url = string.Format(FanArtBaseUrl, APIKey, series.GetProviderId(MetadataProviders.Tvdb));

View File

@ -1,5 +1,6 @@
using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Persistence;
namespace MediaBrowser.Controller.Sorting namespace MediaBrowser.Controller.Sorting
{ {
@ -19,5 +20,11 @@ namespace MediaBrowser.Controller.Sorting
/// </summary> /// </summary>
/// <value>The user manager.</value> /// <value>The user manager.</value>
IUserManager UserManager { get; set; } IUserManager UserManager { get; set; }
/// <summary>
/// Gets or sets the user data repository.
/// </summary>
/// <value>The user data repository.</value>
IUserDataRepository UserDataRepository { get; set; }
} }
} }

View File

@ -153,27 +153,6 @@ namespace MediaBrowser.Model.Configuration
[ProtoMember(52)] [ProtoMember(52)]
public bool DownloadHDFanArt { get; set; } public bool DownloadHDFanArt { get; set; }
/// <summary>
/// Gets or sets the name of the item repository that should be used
/// </summary>
/// <value>The item repository.</value>
[ProtoMember(24)]
public string ItemRepository { get; set; }
/// <summary>
/// Gets or sets the name of the user repository that should be used
/// </summary>
/// <value>The user repository.</value>
[ProtoMember(25)]
public string UserRepository { get; set; }
/// <summary>
/// Gets or sets the name of the user data repository that should be used
/// </summary>
/// <value>The user data repository.</value>
[ProtoMember(26)]
public string UserDataRepository { get; set; }
/// <summary> /// <summary>
/// Characters to be replaced with a ' ' in strings to create a sort name /// Characters to be replaced with a ' ' in strings to create a sort name
/// </summary> /// </summary>
@ -202,13 +181,6 @@ namespace MediaBrowser.Model.Configuration
[ProtoMember(30)] [ProtoMember(30)]
public bool ShowLogWindow { get; set; } public bool ShowLogWindow { get; set; }
/// <summary>
/// Gets or sets the name of the user data repository that should be used
/// </summary>
/// <value>The display preferences repository.</value>
[ProtoMember(31)]
public string DisplayPreferencesRepository { get; set; }
/// <summary> /// <summary>
/// The list of types that will NOT be allowed to have internet providers run against them even if they are turned on. /// The list of types that will NOT be allowed to have internet providers run against them even if they are turned on.
/// </summary> /// </summary>

View File

@ -15,7 +15,7 @@ namespace MediaBrowser.Model.Connectivity
/// </summary> /// </summary>
/// <value>The user id.</value> /// <value>The user id.</value>
[ProtoMember(1)] [ProtoMember(1)]
public Guid UserId { get; set; } public string UserId { get; set; }
/// <summary> /// <summary>
/// Gets or sets the type of the client. /// Gets or sets the type of the client.

View File

@ -24,7 +24,7 @@ namespace MediaBrowser.Model.Dto
/// </summary> /// </summary>
/// <value>The id.</value> /// <value>The id.</value>
[ProtoMember(2)] [ProtoMember(2)]
public Guid Id { get; set; } public string Id { get; set; }
/// <summary> /// <summary>
/// Gets or sets the primary image tag. /// Gets or sets the primary image tag.

View File

@ -57,7 +57,7 @@ namespace MediaBrowser.Model.Plugins
/// </summary> /// </summary>
/// <value>The unique id.</value> /// <value>The unique id.</value>
[ProtoMember(9)] [ProtoMember(9)]
public Guid Id { get; set; } public string Id { get; set; }
/// <summary> /// <summary>
/// Whether or not this plug-in should be automatically updated when a /// Whether or not this plug-in should be automatically updated when a

View File

@ -12,7 +12,7 @@ namespace MediaBrowser.Model.Querying
/// The user to localize search results for /// The user to localize search results for
/// </summary> /// </summary>
/// <value>The user id.</value> /// <value>The user id.</value>
public Guid UserId { get; set; } public string UserId { get; set; }
/// <summary> /// <summary>
/// Specify this to localize the search to a specific item or folder. Omit to use the root. /// Specify this to localize the search to a specific item or folder. Omit to use the root.

View File

@ -1,5 +1,4 @@
using MediaBrowser.Model.Entities; using MediaBrowser.Model.Entities;
using System;
namespace MediaBrowser.Model.Querying namespace MediaBrowser.Model.Querying
{ {
@ -12,7 +11,7 @@ namespace MediaBrowser.Model.Querying
/// Gets or sets the user id. /// Gets or sets the user id.
/// </summary> /// </summary>
/// <value>The user id.</value> /// <value>The user id.</value>
public Guid UserId { get; set; } public string UserId { get; set; }
/// <summary> /// <summary>
/// Gets or sets the start index. /// Gets or sets the start index.
/// </summary> /// </summary>

View File

@ -71,6 +71,6 @@ namespace MediaBrowser.Model.System
/// </summary> /// </summary>
/// <value>The id.</value> /// <value>The id.</value>
[ProtoMember(9)] [ProtoMember(9)]
public Guid Id { get; set; } public string Id { get; set; }
} }
} }

View File

@ -101,6 +101,8 @@ namespace MediaBrowser.Server.Implementations.Library
/// </summary> /// </summary>
private readonly IUserManager _userManager; private readonly IUserManager _userManager;
private readonly IUserDataRepository _userDataRepository;
/// <summary> /// <summary>
/// Gets or sets the configuration manager. /// Gets or sets the configuration manager.
/// </summary> /// </summary>
@ -136,12 +138,14 @@ namespace MediaBrowser.Server.Implementations.Library
/// <param name="taskManager">The task manager.</param> /// <param name="taskManager">The task manager.</param>
/// <param name="userManager">The user manager.</param> /// <param name="userManager">The user manager.</param>
/// <param name="configurationManager">The configuration manager.</param> /// <param name="configurationManager">The configuration manager.</param>
public LibraryManager(ILogger logger, ITaskManager taskManager, IUserManager userManager, IServerConfigurationManager configurationManager) /// <param name="userDataRepository">The user data repository.</param>
public LibraryManager(ILogger logger, ITaskManager taskManager, IUserManager userManager, IServerConfigurationManager configurationManager, IUserDataRepository userDataRepository)
{ {
_logger = logger; _logger = logger;
_taskManager = taskManager; _taskManager = taskManager;
_userManager = userManager; _userManager = userManager;
ConfigurationManager = configurationManager; ConfigurationManager = configurationManager;
_userDataRepository = userDataRepository;
ByReferenceItems = new ConcurrentDictionary<Guid, BaseItem>(); ByReferenceItems = new ConcurrentDictionary<Guid, BaseItem>();
ConfigurationManager.ConfigurationUpdated += ConfigurationUpdated; ConfigurationManager.ConfigurationUpdated += ConfigurationUpdated;
@ -903,6 +907,7 @@ namespace MediaBrowser.Server.Implementations.Library
userComparer.User = user; userComparer.User = user;
userComparer.UserManager = _userManager; userComparer.UserManager = _userManager;
userComparer.UserDataRepository = _userDataRepository;
return userComparer; return userComparer;
} }

View File

@ -1,6 +1,7 @@
using MediaBrowser.Common.Events; using MediaBrowser.Common.Events;
using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Extensions;
using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Persistence; using MediaBrowser.Controller.Persistence;
@ -86,20 +87,14 @@ namespace MediaBrowser.Server.Implementations.Library
/// </summary> /// </summary>
private readonly ILogger _logger; private readonly ILogger _logger;
private readonly IUserDataRepository _userDataRepository;
/// <summary> /// <summary>
/// Gets or sets the configuration manager. /// Gets or sets the configuration manager.
/// </summary> /// </summary>
/// <value>The configuration manager.</value> /// <value>The configuration manager.</value>
private IServerConfigurationManager ConfigurationManager { get; set; } private IServerConfigurationManager ConfigurationManager { get; set; }
private readonly ConcurrentDictionary<string, Task<UserItemData>> _userData = new ConcurrentDictionary<string, Task<UserItemData>>();
/// <summary>
/// Gets the active user data repository
/// </summary>
/// <value>The user data repository.</value>
public IUserDataRepository UserDataRepository { get; set; }
/// <summary> /// <summary>
/// Gets the active user repository /// Gets the active user repository
/// </summary> /// </summary>
@ -321,13 +316,13 @@ namespace MediaBrowser.Server.Implementations.Library
var connection = _activeConnections.GetOrAdd(key, keyName => new ClientConnectionInfo var connection = _activeConnections.GetOrAdd(key, keyName => new ClientConnectionInfo
{ {
UserId = userId, UserId = userId.ToString(),
Client = clientType, Client = clientType,
DeviceName = deviceName, DeviceName = deviceName,
DeviceId = deviceId DeviceId = deviceId
}); });
connection.UserId = userId; connection.UserId = userId.ToString();
return connection; return connection;
} }
@ -591,12 +586,14 @@ namespace MediaBrowser.Server.Implementations.Library
UpdateNowPlayingItemId(user, clientType, deviceId, deviceName, item, positionTicks); UpdateNowPlayingItemId(user, clientType, deviceId, deviceName, item, positionTicks);
var key = item.GetUserDataKey();
if (positionTicks.HasValue) 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); 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 EventHelper.QueueEventIfNotNull(PlaybackProgress, this, new PlaybackProgressEventArgs
@ -631,7 +628,9 @@ namespace MediaBrowser.Server.Implementations.Library
RemoveNowPlayingItemId(user, clientType, deviceId, deviceName, item); 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) if (positionTicks.HasValue)
{ {
@ -644,7 +643,7 @@ namespace MediaBrowser.Server.Implementations.Library
data.Played = true; 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 EventHelper.QueueEventIfNotNull(PlaybackStopped, this, new PlaybackProgressEventArgs
{ {
@ -703,59 +702,5 @@ namespace MediaBrowser.Server.Implementations.Library
data.LastPlayedDate = DateTime.UtcNow; data.LastPlayedDate = DateTime.UtcNow;
} }
} }
/// <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>
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;
}
}
/// <summary>
/// Gets the user data.
/// </summary>
/// <param name="userId">The user id.</param>
/// <param name="userDataId">The user data id.</param>
/// <returns>Task{UserItemData}.</returns>
public Task<UserItemData> GetUserData(Guid userId, Guid userDataId)
{
var key = userId + userDataId.ToString();
return _userData.GetOrAdd(key, keyName => RetrieveUserData(userId, userDataId));
}
/// <summary>
/// Retrieves the user data.
/// </summary>
/// <param name="userId">The user id.</param>
/// <param name="userDataId">The user data id.</param>
/// <returns>Task{UserItemData}.</returns>
private async Task<UserItemData> RetrieveUserData(Guid userId, Guid userDataId)
{
var userdata = await UserDataRepository.GetUserData(userId, userDataId).ConfigureAwait(false);
return userdata ?? new UserItemData();
}
} }
} }

View File

@ -88,12 +88,6 @@ namespace MediaBrowser.Server.Implementations.Providers
Task.Run(() => ValidateCurrentlyRunningProviders()); Task.Run(() => ValidateCurrentlyRunningProviders());
} }
/// <summary>
/// Gets or sets the supported providers key.
/// </summary>
/// <value>The supported providers key.</value>
private Guid SupportedProvidersKey { get; set; }
/// <summary> /// <summary>
/// Adds the metadata providers. /// Adds the metadata providers.
/// </summary> /// </summary>
@ -103,6 +97,11 @@ namespace MediaBrowser.Server.Implementations.Providers
MetadataProviders = providers.OrderBy(e => e.Priority).ToArray(); MetadataProviders = providers.OrderBy(e => e.Priority).ToArray();
} }
/// <summary>
/// The _supported providers key
/// </summary>
private readonly Guid _supportedProvidersKey = "SupportedProviders".GetMD5();
/// <summary> /// <summary>
/// Runs all metadata providers for an entity, and returns true or false indicating if at least one was refreshed and requires persistence /// Runs all metadata providers for an entity, and returns true or false indicating if at least one was refreshed and requires persistence
/// </summary> /// </summary>
@ -126,19 +125,14 @@ namespace MediaBrowser.Server.Implementations.Providers
BaseProviderInfo supportedProvidersInfo; BaseProviderInfo supportedProvidersInfo;
if (SupportedProvidersKey == Guid.Empty) var supportedProvidersValue = string.Join("+", supportedProviders.Select(i => i.GetType().Name));
{ var providersChanged = false;
SupportedProvidersKey = "SupportedProviders".GetMD5();
}
var supportedProvidersHash = string.Join("+", supportedProviders.Select(i => i.GetType().Name)).GetMD5(); item.ProviderData.TryGetValue(_supportedProvidersKey, out supportedProvidersInfo);
bool providersChanged = false;
item.ProviderData.TryGetValue(SupportedProvidersKey, out supportedProvidersInfo);
if (supportedProvidersInfo != null) if (supportedProvidersInfo != null)
{ {
// Force refresh if the supported providers have changed // 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 providers have changed, clear provider info and update the supported providers hash
if (providersChanged) if (providersChanged)
@ -150,7 +144,7 @@ namespace MediaBrowser.Server.Implementations.Providers
if (providersChanged) if (providersChanged)
{ {
supportedProvidersInfo.FileSystemStamp = supportedProvidersHash; supportedProvidersInfo.FileSystemStamp = supportedProvidersValue;
} }
if (force) item.ClearMetaValues(); if (force) item.ClearMetaValues();
@ -206,7 +200,7 @@ namespace MediaBrowser.Server.Implementations.Providers
if (providersChanged) if (providersChanged)
{ {
item.ProviderData[SupportedProvidersKey] = supportedProvidersInfo; item.ProviderData[_supportedProvidersKey] = supportedProvidersInfo;
} }
return result || providersChanged; return result || providersChanged;

View File

@ -1,5 +1,6 @@
using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Persistence;
using MediaBrowser.Controller.Sorting; using MediaBrowser.Controller.Sorting;
using MediaBrowser.Model.Querying; using MediaBrowser.Model.Querying;
using System; using System;
@ -23,6 +24,12 @@ namespace MediaBrowser.Server.Implementations.Sorting
/// <value>The user manager.</value> /// <value>The user manager.</value>
public IUserManager UserManager { get; set; } public IUserManager UserManager { get; set; }
/// <summary>
/// Gets or sets the user data repository.
/// </summary>
/// <value>The user data repository.</value>
public IUserDataRepository UserDataRepository { get; set; }
/// <summary> /// <summary>
/// Compares the specified x. /// Compares the specified x.
/// </summary> /// </summary>
@ -41,7 +48,7 @@ namespace MediaBrowser.Server.Implementations.Sorting
/// <returns>DateTime.</returns> /// <returns>DateTime.</returns>
private DateTime GetDate(BaseItem x) 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) if (userdata != null && userdata.LastPlayedDate.HasValue)
{ {

View File

@ -1,5 +1,6 @@
using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Persistence;
using MediaBrowser.Controller.Sorting; using MediaBrowser.Controller.Sorting;
using MediaBrowser.Model.Querying; using MediaBrowser.Model.Querying;
@ -34,7 +35,7 @@ namespace MediaBrowser.Server.Implementations.Sorting
/// <returns>DateTime.</returns> /// <returns>DateTime.</returns>
private int GetValue(BaseItem x) 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; return userdata == null ? 0 : userdata.PlayCount;
} }
@ -48,6 +49,12 @@ namespace MediaBrowser.Server.Implementations.Sorting
get { return ItemSortBy.PlayCount; } get { return ItemSortBy.PlayCount; }
} }
/// <summary>
/// Gets or sets the user data repository.
/// </summary>
/// <value>The user data repository.</value>
public IUserDataRepository UserDataRepository { get; set; }
/// <summary> /// <summary>
/// Gets or sets the user manager. /// Gets or sets the user manager.
/// </summary> /// </summary>

View File

@ -14,7 +14,7 @@ namespace MediaBrowser.Server.Implementations.Sqlite
/// <summary> /// <summary>
/// Class SQLiteDisplayPreferencesRepository /// Class SQLiteDisplayPreferencesRepository
/// </summary> /// </summary>
class SQLiteDisplayPreferencesRepository : SqliteRepository, IDisplayPreferencesRepository public class SQLiteDisplayPreferencesRepository : SqliteRepository, IDisplayPreferencesRepository
{ {
/// <summary> /// <summary>
/// The repository name /// The repository name

View File

@ -4,6 +4,7 @@ using MediaBrowser.Controller.Persistence;
using MediaBrowser.Model.Logging; using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Serialization; using MediaBrowser.Model.Serialization;
using System; using System;
using System.Collections.Concurrent;
using System.Data; using System.Data;
using System.IO; using System.IO;
using System.Threading; using System.Threading;
@ -16,6 +17,8 @@ namespace MediaBrowser.Server.Implementations.Sqlite
/// </summary> /// </summary>
public class SQLiteUserDataRepository : SqliteRepository, IUserDataRepository public class SQLiteUserDataRepository : SqliteRepository, IUserDataRepository
{ {
private readonly ConcurrentDictionary<string, Task<UserItemData>> _userData = new ConcurrentDictionary<string, Task<UserItemData>>();
/// <summary> /// <summary>
/// The repository name /// The repository name
/// </summary> /// </summary>
@ -45,9 +48,6 @@ namespace MediaBrowser.Server.Implementations.Sqlite
} }
} }
/// <summary>
/// The _protobuf serializer
/// </summary>
private readonly IJsonSerializer _jsonSerializer; private readonly IJsonSerializer _jsonSerializer;
/// <summary> /// <summary>
@ -90,8 +90,8 @@ namespace MediaBrowser.Server.Implementations.Sqlite
string[] queries = { string[] queries = {
"create table if not exists userdata (id GUID, userId GUID, data BLOB)", "create table if not exists userdata (key nvarchar, userId GUID, data BLOB)",
"create unique index if not exists userdataindex on userdata (id, userId)", "create unique index if not exists userdataindex on userdata (key, userId)",
"create table if not exists schema_version (table_name primary key, version)", "create table if not exists schema_version (table_name primary key, version)",
//pragmas //pragmas
"pragma temp_store = memory" "pragma temp_store = memory"
@ -104,20 +104,18 @@ namespace MediaBrowser.Server.Implementations.Sqlite
/// Saves the user data. /// Saves the user data.
/// </summary> /// </summary>
/// <param name="userId">The user id.</param> /// <param name="userId">The user id.</param>
/// <param name="userDataId">The user data id.</param> /// <param name="key">The key.</param>
/// <param name="userData">The user data.</param> /// <param name="userData">The user data.</param>
/// <param name="cancellationToken">The cancellation token.</param> /// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns> /// <returns>Task.</returns>
/// <exception cref="System.ArgumentNullException"> /// <exception cref="System.ArgumentNullException">userData
/// userData
/// or /// or
/// cancellationToken /// cancellationToken
/// or /// or
/// userId /// userId
/// or /// or
/// userDataId /// userDataId</exception>
/// </exception> public async Task SaveUserData(Guid userId, string key, UserItemData userData, CancellationToken cancellationToken)
public async Task SaveUserData(Guid userId, Guid userDataId, UserItemData userData, CancellationToken cancellationToken)
{ {
if (userData == null) if (userData == null)
{ {
@ -131,20 +129,49 @@ namespace MediaBrowser.Server.Implementations.Sqlite
{ {
throw new ArgumentNullException("userId"); throw new ArgumentNullException("userId");
} }
if (userDataId == Guid.Empty) if (string.IsNullOrEmpty(key))
{ {
throw new ArgumentNullException("userDataId"); throw new ArgumentNullException("key");
} }
cancellationToken.ThrowIfCancellationRequested(); 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;
}
}
/// <summary>
/// Persists the user data.
/// </summary>
/// <param name="userId">The user id.</param>
/// <param name="key">The key.</param>
/// <param name="userData">The user data.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
public async Task PersistUserData(Guid userId, string key, UserItemData userData, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
var serialized = _jsonSerializer.SerializeToBytes(userData); var serialized = _jsonSerializer.SerializeToBytes(userData);
cancellationToken.ThrowIfCancellationRequested(); cancellationToken.ThrowIfCancellationRequested();
var cmd = connection.CreateCommand(); var cmd = connection.CreateCommand();
cmd.CommandText = "replace into userdata (id, userId, data) values (@1, @2, @3)"; cmd.CommandText = "replace into userdata (key, userId, data) values (@1, @2, @3)";
cmd.AddParam("@1", userDataId); cmd.AddParam("@1", key);
cmd.AddParam("@2", userId); cmd.AddParam("@2", userId);
cmd.AddParam("@3", serialized); cmd.AddParam("@3", serialized);
@ -174,29 +201,40 @@ namespace MediaBrowser.Server.Implementations.Sqlite
/// Gets the user data. /// Gets the user data.
/// </summary> /// </summary>
/// <param name="userId">The user id.</param> /// <param name="userId">The user id.</param>
/// <param name="userDataId">The user data id.</param> /// <param name="key">The key.</param>
/// <returns>Task{UserItemData}.</returns> /// <returns>Task{UserItemData}.</returns>
/// <exception cref="System.ArgumentNullException"> /// <exception cref="System.ArgumentNullException">
/// userId /// userId
/// or /// or
/// userDataId /// key
/// </exception> /// </exception>
public async Task<UserItemData> GetUserData(Guid userId, Guid userDataId) public Task<UserItemData> GetUserData(Guid userId, string key)
{ {
if (userId == Guid.Empty) if (userId == Guid.Empty)
{ {
throw new ArgumentNullException("userId"); 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));
}
/// <summary>
/// Retrieves the user data.
/// </summary>
/// <param name="userId">The user id.</param>
/// <param name="key">The key.</param>
/// <returns>Task{UserItemData}.</returns>
private async Task<UserItemData> RetrieveUserData(Guid userId, string key)
{
var cmd = connection.CreateCommand(); 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); var idParam = cmd.Parameters.Add("@key", DbType.Guid);
idParam.Value = userDataId; idParam.Value = key;
var userIdParam = cmd.Parameters.Add("@userId", DbType.Guid); var userIdParam = cmd.Parameters.Add("@userId", DbType.Guid);
userIdParam.Value = userId; userIdParam.Value = userId;
@ -212,7 +250,7 @@ namespace MediaBrowser.Server.Implementations.Sqlite
} }
} }
return null; return new UserItemData();
} }
} }
} }

View File

@ -37,6 +37,7 @@ using MediaBrowser.Server.Implementations.Library;
using MediaBrowser.Server.Implementations.MediaEncoder; using MediaBrowser.Server.Implementations.MediaEncoder;
using MediaBrowser.Server.Implementations.Providers; using MediaBrowser.Server.Implementations.Providers;
using MediaBrowser.Server.Implementations.ServerManager; using MediaBrowser.Server.Implementations.ServerManager;
using MediaBrowser.Server.Implementations.Sqlite;
using MediaBrowser.Server.Implementations.Udp; using MediaBrowser.Server.Implementations.Udp;
using MediaBrowser.Server.Implementations.Updates; using MediaBrowser.Server.Implementations.Updates;
using MediaBrowser.Server.Implementations.WebSocket; using MediaBrowser.Server.Implementations.WebSocket;
@ -152,6 +153,12 @@ namespace MediaBrowser.ServerApplication
/// <value>The media encoder.</value> /// <value>The media encoder.</value>
private IMediaEncoder MediaEncoder { get; set; } private IMediaEncoder MediaEncoder { get; set; }
/// <summary>
/// Gets or sets the user data repository.
/// </summary>
/// <value>The user data repository.</value>
private IUserDataRepository UserDataRepository { get; set; }
/// <summary> /// <summary>
/// The full path to our startmenu shortcut /// The full path to our startmenu shortcut
/// </summary> /// </summary>
@ -216,7 +223,10 @@ namespace MediaBrowser.ServerApplication
UserManager = new UserManager(Logger, ServerConfigurationManager); UserManager = new UserManager(Logger, ServerConfigurationManager);
RegisterSingleInstance(UserManager); 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); RegisterSingleInstance(LibraryManager);
InstallationManager = new InstallationManager(HttpClient, PackageManager, JsonSerializer, Logger, this); InstallationManager = new InstallationManager(HttpClient, PackageManager, JsonSerializer, Logger, this);
@ -273,9 +283,7 @@ namespace MediaBrowser.ServerApplication
/// <returns>Task.</returns> /// <returns>Task.</returns>
private async Task ConfigureDisplayPreferencesRepositories() private async Task ConfigureDisplayPreferencesRepositories()
{ {
var repositories = GetExports<IDisplayPreferencesRepository>(); var repository = new SQLiteDisplayPreferencesRepository(ApplicationPaths, JsonSerializer, LogManager);
var repository = GetRepository(repositories, ServerConfigurationManager.Configuration.DisplayPreferencesRepository);
await repository.Initialize().ConfigureAwait(false); await repository.Initialize().ConfigureAwait(false);
@ -288,9 +296,7 @@ namespace MediaBrowser.ServerApplication
/// <returns>Task.</returns> /// <returns>Task.</returns>
private async Task ConfigureItemRepositories() private async Task ConfigureItemRepositories()
{ {
var repositories = GetExports<IItemRepository>(); var repository = new SQLiteItemRepository(ApplicationPaths, JsonSerializer, LogManager);
var repository = GetRepository(repositories, ServerConfigurationManager.Configuration.ItemRepository);
await repository.Initialize().ConfigureAwait(false); await repository.Initialize().ConfigureAwait(false);
@ -301,22 +307,14 @@ namespace MediaBrowser.ServerApplication
/// Configures the user data repositories. /// Configures the user data repositories.
/// </summary> /// </summary>
/// <returns>Task.</returns> /// <returns>Task.</returns>
private async Task ConfigureUserDataRepositories() private Task ConfigureUserDataRepositories()
{ {
var repositories = GetExports<IUserDataRepository>(); return UserDataRepository.Initialize();
var repository = GetRepository(repositories, ServerConfigurationManager.Configuration.UserDataRepository);
await repository.Initialize().ConfigureAwait(false);
((UserManager)UserManager).UserDataRepository = repository;
} }
private async Task ConfigureUserRepositories() private async Task ConfigureUserRepositories()
{ {
var repositories = GetExports<IUserRepository>(); var repository = new SQLiteUserRepository(ApplicationPaths, JsonSerializer, LogManager);
var repository = GetRepository(repositories, ServerConfigurationManager.Configuration.UserRepository);
await repository.Initialize().ConfigureAwait(false); await repository.Initialize().ConfigureAwait(false);
@ -470,7 +468,7 @@ namespace MediaBrowser.ServerApplication
yield return GetType().Assembly; yield return GetType().Assembly;
} }
private readonly Guid _systemId = Environment.MachineName.GetMD5(); private readonly string _systemId = Environment.MachineName.GetMD5().ToString();
/// <summary> /// <summary>
/// Gets the system status. /// Gets the system status.

View File

@ -3,6 +3,7 @@ using MediaBrowser.Common.Net;
using MediaBrowser.Common.Plugins; using MediaBrowser.Common.Plugins;
using MediaBrowser.Common.ScheduledTasks; using MediaBrowser.Common.ScheduledTasks;
using MediaBrowser.Controller; using MediaBrowser.Controller;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Plugins; using MediaBrowser.Controller.Plugins;
@ -174,7 +175,7 @@ namespace MediaBrowser.ServerApplication.EntryPoints
/// <param name="e">The e.</param> /// <param name="e">The e.</param>
void userManager_UserUpdated(object sender, GenericEventArgs<User> e) void userManager_UserUpdated(object sender, GenericEventArgs<User> e)
{ {
var dto = new DtoBuilder(_logger, _libraryManager, _userManager).GetUserDto(e.Argument); var dto = new UserDtoBuilder(_logger).GetUserDto(e.Argument);
_serverManager.SendWebSocketMessage("UserUpdated", dto); _serverManager.SendWebSocketMessage("UserUpdated", dto);
} }

View File

@ -4,6 +4,7 @@ using MediaBrowser.Common.Net;
using MediaBrowser.Common.ScheduledTasks; using MediaBrowser.Common.ScheduledTasks;
using MediaBrowser.Controller; using MediaBrowser.Controller;
using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Plugins; using MediaBrowser.Controller.Plugins;
using MediaBrowser.Model.Logging; using MediaBrowser.Model.Logging;
@ -192,9 +193,9 @@ namespace MediaBrowser.WebDashboard.Api
{ {
var connections = userManager.RecentConnections.ToArray(); 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 return new DashboardInfo
{ {