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.Net;
using MediaBrowser.Controller;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Model.Entities;

View File

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

View File

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

View File

@ -1,6 +1,7 @@
using System.Threading;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Persistence;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Querying;
using ServiceStack.ServiceHost;
@ -8,6 +9,7 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace MediaBrowser.Api.UserLibrary
@ -27,16 +29,19 @@ namespace MediaBrowser.Api.UserLibrary
/// The library manager
/// </summary>
protected readonly ILibraryManager LibraryManager;
protected readonly IUserDataRepository UserDataRepository;
/// <summary>
/// Initializes a new instance of the <see cref="BaseItemsByNameService{TItemType}" /> class.
/// </summary>
/// <param name="userManager">The user 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;
LibraryManager = libraryManager;
UserDataRepository = userDataRepository;
}
/// <summary>
@ -132,18 +137,19 @@ namespace MediaBrowser.Api.UserLibrary
/// <returns>IEnumerable{BaseItem}.</returns>
private IEnumerable<BaseItem> FilterItems(GetItemsByName request, IEnumerable<BaseItem> items, User user)
{
items = items.AsParallel();
items = ItemsService.ApplyAdditionalFilters(request, items);
// Apply filters
// Run them starting with the ones that are likely to reduce the list the most
foreach (var filter in request.GetFilters().OrderByDescending(f => (int)f))
// Exclude item types
if (!string.IsNullOrEmpty(request.ExcludeItemTypes))
{
items = ItemsService.ApplyFilter(items, filter, user, UserManager);
var vals = request.ExcludeItemTypes.Split(',');
items = items.Where(f => !vals.Contains(f.GetType().Name, StringComparer.OrdinalIgnoreCase));
}
items = items.AsEnumerable();
// Include item types
if (!string.IsNullOrEmpty(request.IncludeItemTypes))
{
var vals = request.IncludeItemTypes.Split(',');
items = items.Where(f => vals.Contains(f.GetType().Name, StringComparer.OrdinalIgnoreCase));
}
return items;
}
@ -185,7 +191,7 @@ namespace MediaBrowser.Api.UserLibrary
return null;
}
var dto = await new DtoBuilder(Logger, LibraryManager, UserManager).GetBaseItemDto(item, user, fields).ConfigureAwait(false);
var dto = await new DtoBuilder(Logger, LibraryManager, UserDataRepository).GetBaseItemDto(item, user, fields).ConfigureAwait(false);
if (fields.Contains(ItemFields.ItemCounts))
{
@ -211,13 +217,15 @@ namespace MediaBrowser.Api.UserLibrary
var item = await getItem().ConfigureAwait(false);
var key = item.GetUserDataKey();
// Get the user data for this item
var data = await UserManager.GetUserData(user.Id, item.UserDataId).ConfigureAwait(false);
var data = await UserDataRepository.GetUserData(user.Id, key).ConfigureAwait(false);
// Set favorite status
data.IsFavorite = isFavorite;
await UserManager.SaveUserData(user.Id, item.UserDataId, data, CancellationToken.None).ConfigureAwait(false);
await UserDataRepository.SaveUserData(user.Id, key, data, CancellationToken.None).ConfigureAwait(false);
}
}

View File

@ -1,6 +1,6 @@
using System.Threading;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Persistence;
using ServiceStack.ServiceHost;
using System;
using System.Collections.Generic;
@ -18,52 +18,14 @@ namespace MediaBrowser.Api.UserLibrary
public class GetGenres : GetItemsByName
{
}
[Route("/Users/{UserId}/FavoriteGenres/{Name}", "POST")]
[Api(Description = "Marks a genre as a favorite")]
public class MarkFavoriteGenre : IReturnVoid
{
/// <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>
/// Class GenresService
/// </summary>
public class GenresService : BaseItemsByNameService<Genre>
{
public GenresService(IUserManager userManager, ILibraryManager libraryManager)
: base(userManager, libraryManager)
public GenresService(IUserManager userManager, ILibraryManager libraryManager, IUserDataRepository userDataRepository)
: base(userManager, libraryManager, userDataRepository)
{
}
@ -79,28 +41,6 @@ namespace MediaBrowser.Api.UserLibrary
return ToOptimizedResult(result);
}
/// <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>
/// Gets all items.
/// </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.Library;
using MediaBrowser.Controller.Persistence;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Querying;
using ServiceStack.ServiceHost;
@ -148,6 +150,7 @@ namespace MediaBrowser.Api.UserLibrary
/// The _user manager
/// </summary>
private readonly IUserManager _userManager;
private readonly IUserDataRepository _userDataRepository;
/// <summary>
/// The _library manager
@ -161,11 +164,13 @@ namespace MediaBrowser.Api.UserLibrary
/// <param name="userManager">The user manager.</param>
/// <param name="libraryManager">The library manager.</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;
_libraryManager = libraryManager;
_searchEngine = searchEngine;
_userDataRepository = userDataRepository;
}
/// <summary>
@ -199,7 +204,7 @@ namespace MediaBrowser.Api.UserLibrary
// Run them starting with the ones that are likely to reduce the list the most
foreach (var filter in request.GetFilters().OrderByDescending(f => (int)f))
{
items = ApplyFilter(items, filter, user, _userManager);
items = ApplyFilter(items, filter, user, _userDataRepository);
}
items = items.AsEnumerable();
@ -214,7 +219,7 @@ namespace MediaBrowser.Api.UserLibrary
var fields = request.GetItemFields().ToList();
var dtoBuilder = new DtoBuilder(Logger, _libraryManager, _userManager);
var dtoBuilder = new DtoBuilder(Logger, _libraryManager, _userDataRepository);
var returnItems = await Task.WhenAll(pagedItems.Select(i => dtoBuilder.GetBaseItemDto(i, user, fields))).ConfigureAwait(false);
@ -274,9 +279,9 @@ namespace MediaBrowser.Api.UserLibrary
/// <param name="items">The items.</param>
/// <param name="filter">The filter.</param>
/// <param name="user">The user.</param>
/// <param name="userManager">The user manager.</param>
/// <param name="repository">The repository.</param>
/// <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
var currentUser = user;
@ -286,7 +291,7 @@ namespace MediaBrowser.Api.UserLibrary
case ItemFilter.Likes:
return items.Where(item =>
{
var userdata = userManager.GetUserData(user.Id, item.UserDataId).Result;
var userdata = repository.GetUserData(user.Id, item.GetUserDataKey()).Result;
return userdata != null && userdata.Likes.HasValue && userdata.Likes.Value;
});
@ -294,7 +299,7 @@ namespace MediaBrowser.Api.UserLibrary
case ItemFilter.Dislikes:
return items.Where(item =>
{
var userdata = userManager.GetUserData(user.Id, item.UserDataId).Result;
var userdata = repository.GetUserData(user.Id, item.GetUserDataKey()).Result;
return userdata != null && userdata.Likes.HasValue && !userdata.Likes.Value;
});
@ -302,7 +307,7 @@ namespace MediaBrowser.Api.UserLibrary
case ItemFilter.IsFavorite:
return items.Where(item =>
{
var userdata = userManager.GetUserData(user.Id, item.UserDataId).Result;
var userdata = repository.GetUserData(user.Id, item.GetUserDataKey()).Result;
return userdata != null && userdata.IsFavorite;
});
@ -313,7 +318,7 @@ namespace MediaBrowser.Api.UserLibrary
case ItemFilter.IsResumable:
return items.Where(item =>
{
var userdata = userManager.GetUserData(user.Id, item.UserDataId).Result;
var userdata = repository.GetUserData(user.Id, item.GetUserDataKey()).Result;
return userdata != null && userdata.PlaybackPositionTicks > 0;
});
@ -321,7 +326,7 @@ namespace MediaBrowser.Api.UserLibrary
case ItemFilter.IsPlayed:
return items.Where(item =>
{
var userdata = userManager.GetUserData(user.Id, item.UserDataId).Result;
var userdata = repository.GetUserData(user.Id, item.GetUserDataKey()).Result;
return userdata != null && userdata.PlayCount > 0;
});
@ -329,7 +334,7 @@ namespace MediaBrowser.Api.UserLibrary
case ItemFilter.IsUnplayed:
return items.Where(item =>
{
var userdata = userManager.GetUserData(user.Id, item.UserDataId).Result;
var userdata = repository.GetUserData(user.Id, item.GetUserDataKey()).Result;
return userdata == null || userdata.PlayCount == 0;
});
@ -347,32 +352,11 @@ namespace MediaBrowser.Api.UserLibrary
/// <summary>
/// Applies the additional filters.
/// </summary>
/// <param name="itemsRequest">The items request.</param>
/// <param name="request">The request.</param>
/// <param name="items">The items.</param>
/// <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
if (!string.IsNullOrEmpty(request.SeriesStatus))
{

View File

@ -1,5 +1,6 @@
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Persistence;
using ServiceStack.ServiceHost;
using System;
using System.Collections.Generic;
@ -22,52 +23,14 @@ namespace MediaBrowser.Api.UserLibrary
/// <value>The person types.</value>
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>
/// Class PersonsService
/// </summary>
public class PersonsService : BaseItemsByNameService<Person>
{
public PersonsService(IUserManager userManager, ILibraryManager libraryManager)
: base(userManager, libraryManager)
public PersonsService(IUserManager userManager, ILibraryManager libraryManager, IUserDataRepository userDataRepository)
: base(userManager, libraryManager, userDataRepository)
{
}
@ -83,28 +46,6 @@ namespace MediaBrowser.Api.UserLibrary
return ToOptimizedResult(result);
}
/// <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>
/// Gets all items.
/// </summary>

View File

@ -1,5 +1,6 @@
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Persistence;
using ServiceStack.ServiceHost;
using System;
using System.Collections.Generic;
@ -17,52 +18,14 @@ namespace MediaBrowser.Api.UserLibrary
public class GetStudios : GetItemsByName
{
}
[Route("/Users/{UserId}/FavoriteStudios/{Name}", "POST")]
[Api(Description = "Marks a studio as a favorite")]
public class MarkFavoriteStudio : IReturnVoid
{
/// <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>
/// Class StudiosService
/// </summary>
public class StudiosService : BaseItemsByNameService<Studio>
{
public StudiosService(IUserManager userManager, ILibraryManager libraryManager)
: base(userManager, libraryManager)
public StudiosService(IUserManager userManager, ILibraryManager libraryManager, IUserDataRepository userDataRepository)
: base(userManager, libraryManager, userDataRepository)
{
}
@ -77,28 +40,6 @@ namespace MediaBrowser.Api.UserLibrary
return ToOptimizedResult(result);
}
/// <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>
/// 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.Library;
using MediaBrowser.Controller.Persistence;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Querying;
using ServiceStack.ServiceHost;
@ -335,18 +337,19 @@ namespace MediaBrowser.Api.UserLibrary
/// The _user manager
/// </summary>
private readonly IUserManager _userManager;
private readonly IUserDataRepository _userDataRepository;
private readonly ILibraryManager _libraryManager;
/// <summary>
/// Initializes a new instance of the <see cref="UserLibraryService" /> class.
/// </summary>
/// <exception cref="System.ArgumentNullException">jsonSerializer</exception>
public UserLibraryService(IUserManager userManager, ILibraryManager libraryManager)
public UserLibraryService(IUserManager userManager, ILibraryManager libraryManager, IUserDataRepository userDataRepository)
: base()
{
_userManager = userManager;
_libraryManager = libraryManager;
_userDataRepository = userDataRepository;
}
/// <summary>
@ -365,7 +368,7 @@ namespace MediaBrowser.Api.UserLibrary
var movie = (Movie)item;
var dtoBuilder = new DtoBuilder(Logger, _libraryManager, _userManager);
var dtoBuilder = new DtoBuilder(Logger, _libraryManager, _userDataRepository);
var items = movie.SpecialFeatures.Select(i => dtoBuilder.GetBaseItemDto(i, user, fields)).AsParallel().Select(t => t.Result).ToList();
@ -386,7 +389,7 @@ namespace MediaBrowser.Api.UserLibrary
// Get everything
var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true)).ToList();
var dtoBuilder = new DtoBuilder(Logger, _libraryManager, _userManager);
var dtoBuilder = new DtoBuilder(Logger, _libraryManager, _userDataRepository);
var items = item.LocalTrailers.Select(i => dtoBuilder.GetBaseItemDto(i, user, fields)).AsParallel().Select(t => t.Result).ToList();
@ -407,7 +410,7 @@ namespace MediaBrowser.Api.UserLibrary
// Get everything
var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true)).ToList();
var dtoBuilder = new DtoBuilder(Logger, _libraryManager, _userManager);
var dtoBuilder = new DtoBuilder(Logger, _libraryManager, _userDataRepository);
var result = dtoBuilder.GetBaseItemDto(item, user, fields).Result;
@ -423,7 +426,7 @@ namespace MediaBrowser.Api.UserLibrary
// Get everything
var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true)).ToList();
var dtoBuilder = new DtoBuilder(Logger, _libraryManager, _userManager);
var dtoBuilder = new DtoBuilder(Logger, _libraryManager, _userDataRepository);
var result = dtoBuilder.GetBaseItemDto(item, user, fields).Result;
@ -457,12 +460,14 @@ namespace MediaBrowser.Api.UserLibrary
var item = string.IsNullOrEmpty(request.Id) ? user.RootFolder : DtoBuilder.GetItemByClientId(request.Id, _userManager, _libraryManager, user.Id);
// Get the user data for this item
var data = _userManager.GetUserData(user.Id, item.UserDataId).Result;
var key = item.GetUserDataKey();
var data = _userDataRepository.GetUserData(user.Id, key).Result;
// Set favorite status
data.IsFavorite = true;
var task = _userManager.SaveUserData(user.Id, item.UserDataId, data, CancellationToken.None);
var task = _userDataRepository.SaveUserData(user.Id, key, data, CancellationToken.None);
Task.WaitAll(task);
}
@ -477,13 +482,15 @@ namespace MediaBrowser.Api.UserLibrary
var item = string.IsNullOrEmpty(request.Id) ? user.RootFolder : DtoBuilder.GetItemByClientId(request.Id, _userManager, _libraryManager, user.Id);
var key = item.GetUserDataKey();
// Get the user data for this item
var data = _userManager.GetUserData(user.Id, item.UserDataId).Result;
var data = _userDataRepository.GetUserData(user.Id, key).Result;
// Set favorite status
data.IsFavorite = false;
var task = _userManager.SaveUserData(user.Id, item.UserDataId, data, CancellationToken.None);
var task = _userDataRepository.SaveUserData(user.Id, key, data, CancellationToken.None);
Task.WaitAll(task);
}
@ -498,12 +505,14 @@ namespace MediaBrowser.Api.UserLibrary
var item = string.IsNullOrEmpty(request.Id) ? user.RootFolder : DtoBuilder.GetItemByClientId(request.Id, _userManager, _libraryManager, user.Id);
var key = item.GetUserDataKey();
// Get the user data for this item
var data = _userManager.GetUserData(user.Id, item.UserDataId).Result;
var data = _userDataRepository.GetUserData(user.Id, key).Result;
data.Rating = null;
var task = _userManager.SaveUserData(user.Id, item.UserDataId, data, CancellationToken.None);
var task = _userDataRepository.SaveUserData(user.Id, key, data, CancellationToken.None);
Task.WaitAll(task);
}
@ -518,12 +527,14 @@ namespace MediaBrowser.Api.UserLibrary
var item = string.IsNullOrEmpty(request.Id) ? user.RootFolder : DtoBuilder.GetItemByClientId(request.Id, _userManager, _libraryManager, user.Id);
var key = item.GetUserDataKey();
// Get the user data for this item
var data = _userManager.GetUserData(user.Id, item.UserDataId).Result;
var data = _userDataRepository.GetUserData(user.Id, key).Result;
data.Likes = request.Likes;
var task = _userManager.SaveUserData(user.Id, item.UserDataId, data, CancellationToken.None);
var task = _userDataRepository.SaveUserData(user.Id, key, data, CancellationToken.None);
Task.WaitAll(task);
}
@ -623,7 +634,7 @@ namespace MediaBrowser.Api.UserLibrary
{
var item = DtoBuilder.GetItemByClientId(itemId, _userManager, _libraryManager, user.Id);
return item.SetPlayedStatus(user, wasPlayed, _userManager);
return item.SetPlayedStatus(user, wasPlayed, _userDataRepository);
}
}
}

View File

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

View File

@ -1,4 +1,5 @@
using MediaBrowser.Common.Extensions;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Library;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Serialization;
@ -165,7 +166,7 @@ namespace MediaBrowser.Api
/// <returns>System.Object.</returns>
public object Get(GetUsers request)
{
var dtoBuilder = new DtoBuilder(Logger, _libraryManager, _userManager);
var dtoBuilder = new UserDtoBuilder(Logger);
var users = _userManager.Users.OrderBy(u => u.Name).Select(dtoBuilder.GetUserDto).ToArray();
@ -186,7 +187,9 @@ namespace MediaBrowser.Api
throw new ResourceNotFoundException("User not found");
}
var result = new DtoBuilder(Logger, _libraryManager, _userManager).GetUserDto(user);
var dtoBuilder = new UserDtoBuilder(Logger);
var result = dtoBuilder.GetUserDto(user);
return ToOptimizedResult(result);
}
@ -300,7 +303,9 @@ namespace MediaBrowser.Api
newUser.UpdateConfiguration(dtoUser.Configuration, _xmlSerializer);
var result = new DtoBuilder(Logger, _libraryManager, _userManager).GetUserDto(newUser);
var dtoBuilder = new UserDtoBuilder(Logger);
var result = dtoBuilder.GetUserDto(newUser);
return ToOptimizedResult(result);
}

View File

@ -1,6 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
@ -55,26 +53,6 @@ namespace MediaBrowser.Common.Extensions
return (aType.FullName + str.ToLower()).GetMD5();
}
/// <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>
/// Gets the attribute value.
/// </summary>

View File

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

View File

@ -3,6 +3,8 @@ using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Entities.Movies;
using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Persistence;
using MediaBrowser.Model.Drawing;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
@ -14,7 +16,7 @@ using System.IO;
using System.Linq;
using System.Threading.Tasks;
namespace MediaBrowser.Controller.Library
namespace MediaBrowser.Controller.Dto
{
/// <summary>
/// Generates DTO's from domain entities
@ -28,13 +30,13 @@ namespace MediaBrowser.Controller.Library
private readonly ILogger _logger;
private readonly ILibraryManager _libraryManager;
private readonly IUserManager _userManager;
private readonly IUserDataRepository _userDataRepository;
public DtoBuilder(ILogger logger, ILibraryManager libraryManager, IUserManager userManager)
public DtoBuilder(ILogger logger, ILibraryManager libraryManager, IUserDataRepository userDataRepository)
{
_logger = logger;
_libraryManager = libraryManager;
_userManager = userManager;
_userDataRepository = userDataRepository;
}
/// <summary>
@ -73,7 +75,7 @@ namespace MediaBrowser.Controller.Library
{
try
{
AttachPrimaryImageAspectRatio(dto, item);
AttachPrimaryImageAspectRatio(dto, item, _logger);
}
catch (Exception ex)
{
@ -136,7 +138,7 @@ namespace MediaBrowser.Controller.Library
{
try
{
AttachPrimaryImageAspectRatio(dto, item);
AttachPrimaryImageAspectRatio(dto, item, _logger);
}
catch (Exception ex)
{
@ -167,7 +169,7 @@ namespace MediaBrowser.Controller.Library
{
if (fields.Contains(ItemFields.UserData))
{
var userData = await _userManager.GetUserData(user.Id, item.UserDataId).ConfigureAwait(false);
var userData = await _userDataRepository.GetUserData(user.Id, item.GetUserDataKey()).ConfigureAwait(false);
dto.UserData = GetUserItemDataDto(userData);
}
@ -186,18 +188,19 @@ namespace MediaBrowser.Controller.Library
// Skip sorting since all we want is a count
dto.ChildCount = folder.GetChildren(user).Count();
await SetSpecialCounts(folder, user, dto, _userManager).ConfigureAwait(false);
await SetSpecialCounts(folder, user, dto, _userDataRepository).ConfigureAwait(false);
}
}
}
/// <summary>
/// Attaches the primary image aspect ratio.
/// </summary>
/// <param name="dto">The dto.</param>
/// <param name="item">The item.</param>
/// <param name="_logger">The _logger.</param>
/// <returns>Task.</returns>
private void AttachPrimaryImageAspectRatio(IItemDto dto, BaseItem item)
internal static void AttachPrimaryImageAspectRatio(IItemDto dto, BaseItem item, ILogger _logger)
{
var path = item.PrimaryImagePath;
@ -503,9 +506,9 @@ namespace MediaBrowser.Controller.Library
/// <param name="folder">The folder.</param>
/// <param name="user">The user.</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>
private static async Task SetSpecialCounts(Folder folder, User user, BaseItemDto dto, IUserManager userManager)
private static async Task SetSpecialCounts(Folder folder, User user, BaseItemDto dto, IUserDataRepository userDataRepository)
{
var rcentlyAddedItemCount = 0;
var recursiveItemCount = 0;
@ -515,7 +518,7 @@ namespace MediaBrowser.Controller.Library
// Loop through each recursive child
foreach (var child in folder.GetRecursiveChildren(user).Where(i => !i.IsFolder))
{
var userdata = await userManager.GetUserData(user.Id, child.UserDataId).ConfigureAwait(false);
var userdata = await userDataRepository.GetUserData(user.Id, child.GetUserDataKey()).ConfigureAwait(false);
recursiveItemCount++;
@ -785,49 +788,6 @@ namespace MediaBrowser.Controller.Library
return item.Id.ToString();
}
/// <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>
/// Gets a BaseItem based upon it's client-side item id
/// </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.Library;
using MediaBrowser.Controller.Localization;
using MediaBrowser.Controller.Persistence;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Controller.Resolvers;
using MediaBrowser.Model.Entities;
@ -183,23 +184,18 @@ namespace MediaBrowser.Controller.Entities
/// <summary>
/// The _file system stamp
/// </summary>
private Guid? _fileSystemStamp;
private string _fileSystemStamp;
/// <summary>
/// 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.
/// </summary>
/// <value>The file system stamp.</value>
[IgnoreDataMember]
public Guid FileSystemStamp
public string FileSystemStamp
{
get
{
if (!_fileSystemStamp.HasValue)
{
_fileSystemStamp = GetFileSystemStamp();
}
return _fileSystemStamp.Value;
return _fileSystemStamp ?? (_fileSystemStamp = GetFileSystemStamp());
}
}
@ -221,12 +217,12 @@ namespace MediaBrowser.Controller.Entities
/// comparison purposes to determine if the file system entries for this item have changed.
/// </summary>
/// <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 (LocationType != LocationType.FileSystem || !ResolveArgs.IsDirectory)
{
return Guid.Empty;
return string.Empty;
}
var sb = new StringBuilder();
@ -242,7 +238,7 @@ namespace MediaBrowser.Controller.Entities
sb.Append(file.cFileName);
}
return sb.ToString().GetMD5();
return sb.ToString();
}
/// <summary>
@ -820,21 +816,12 @@ namespace MediaBrowser.Controller.Entities
}
/// <summary>
/// The _user data id
/// Gets the user data key.
/// </summary>
protected Guid _userDataId; //cache this so it doesn't have to be re-constructed on every reference
/// <summary>
/// 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
/// <returns>System.String.</returns>
public virtual string GetUserDataKey()
{
get
{
return _userDataId == Guid.Empty ? (_userDataId = Id) : _userDataId;
}
return Id.ToString();
}
/// <summary>
@ -1151,14 +1138,16 @@ namespace MediaBrowser.Controller.Entities
/// <param name="userManager">The user manager.</param>
/// <returns>Task.</returns>
/// <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)
{
throw new ArgumentNullException();
}
var data = await userManager.GetUserData(user.Id, UserDataId).ConfigureAwait(false);
var key = GetUserDataKey();
var data = await userManager.GetUserData(user.Id, key).ConfigureAwait(false);
if (wasPlayed)
{
@ -1181,7 +1170,7 @@ namespace MediaBrowser.Controller.Entities
data.Played = wasPlayed;
await userManager.SaveUserData(user.Id, UserDataId, data, CancellationToken.None).ConfigureAwait(false);
await userManager.SaveUserData(user.Id, key, data, CancellationToken.None).ConfigureAwait(false);
}
/// <summary>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -6,5 +6,13 @@ namespace MediaBrowser.Controller.Entities
/// </summary>
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>
/// <returns>Task.</returns>
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\ImageHeader.cs" />
<Compile Include="Drawing\ImageManager.cs" />
<Compile Include="Dto\UserDtoBuilder.cs" />
<Compile Include="Entities\AggregateFolder.cs" />
<Compile Include="Entities\Audio\Audio.cs" />
<Compile Include="Entities\Audio\MusicAlbum.cs" />
@ -107,7 +108,7 @@
<Compile Include="IServerApplicationHost.cs" />
<Compile Include="IServerApplicationPaths.cs" />
<Compile Include="Library\ChildrenChangedEventArgs.cs" />
<Compile Include="Library\DtoBuilder.cs" />
<Compile Include="Dto\DtoBuilder.cs" />
<Compile Include="Providers\IProviderManager.cs" />
<Compile Include="Providers\MediaInfo\MediaEncoderHelpers.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.Tasks;
@ -14,19 +14,19 @@ namespace MediaBrowser.Controller.Persistence
/// Saves the user data.
/// </summary>
/// <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="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
Task SaveUserData(Guid userId, Guid userDataId, UserItemData userData,
Task SaveUserData(Guid userId, string key, 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>
/// <param name="key">The key.</param>
/// <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>
/// The _id
/// </summary>
protected 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;
}
}
protected readonly Guid Id;
/// <summary>
/// Supportses the specified item.
@ -105,6 +93,7 @@ namespace MediaBrowser.Controller.Providers
Logger = logManager.GetLogger(GetType().Name);
LogManager = logManager;
ConfigurationManager = configurationManager;
Id = GetType().FullName.GetMD5();
Initialize();
}
@ -130,8 +119,14 @@ namespace MediaBrowser.Controller.Providers
{
throw new ArgumentNullException("item");
}
var data = item.ProviderData.GetValueOrDefault(Id, new BaseProviderInfo { ProviderId = Id });
BaseProviderInfo data;
if (!item.ProviderData.TryGetValue(Id, out data))
{
data = new BaseProviderInfo();
}
data.LastRefreshed = value;
data.LastRefreshStatus = status;
data.ProviderVersion = providerVersion;
@ -155,7 +150,7 @@ namespace MediaBrowser.Controller.Providers
{
SetLastRefreshed(item, value, ProviderVersion, status);
}
/// <summary>
/// Returns whether or not this provider should be re-fetched. Default functionality can
/// compare a provided date with a last refresh time. This can be overridden for more complex
@ -171,9 +166,14 @@ namespace MediaBrowser.Controller.Providers
throw new ArgumentNullException();
}
var providerInfo = item.ProviderData.GetValueOrDefault(Id, new BaseProviderInfo());
BaseProviderInfo data;
return NeedsRefreshInternal(item, providerInfo);
if (!item.ProviderData.TryGetValue(Id, out data))
{
data = new BaseProviderInfo();
}
return NeedsRefreshInternal(item, data);
}
/// <summary>
@ -194,7 +194,7 @@ namespace MediaBrowser.Controller.Providers
{
throw new ArgumentNullException("providerInfo");
}
if (CompareDate(item) > providerInfo.LastRefreshed)
{
return true;
@ -209,7 +209,7 @@ namespace MediaBrowser.Controller.Providers
{
return true;
}
return false;
}
@ -221,7 +221,7 @@ namespace MediaBrowser.Controller.Providers
/// <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)
{
return GetCurrentFileSystemStamp(item) != providerInfo.FileSystemStamp;
return !string.Equals(GetCurrentFileSystemStamp(item), providerInfo.FileSystemStamp);
}
/// <summary>
@ -279,7 +279,7 @@ namespace MediaBrowser.Controller.Providers
/// </summary>
/// <param name="item">The item.</param>
/// <returns>Guid.</returns>
private Guid GetCurrentFileSystemStamp(BaseItem item)
private string GetCurrentFileSystemStamp(BaseItem item)
{
if (UseParentFileSystemStamp(item) && item.Parent != null)
{

View File

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

View File

@ -104,7 +104,14 @@ namespace MediaBrowser.Controller.Providers.Movies
cancellationToken.ThrowIfCancellationRequested();
var movie = item;
if (ShouldFetch(movie, movie.ProviderData.GetValueOrDefault(Id, new BaseProviderInfo { ProviderId = Id })))
BaseProviderInfo providerData;
if (!item.ProviderData.TryGetValue(Id, out providerData))
{
providerData = new BaseProviderInfo();
}
if (ShouldFetch(movie, providerData))
{
var language = ConfigurationManager.Configuration.PreferredMetadataLanguage.ToLower();
var url = string.Format(FanArtBaseUrl, APIKey, movie.GetProviderId(MetadataProviders.Tmdb));

View File

@ -22,10 +22,11 @@ namespace MediaBrowser.Controller.Providers.Movies
{
class MovieDbProviderException : ApplicationException
{
public MovieDbProviderException(string msg) : base(msg)
public MovieDbProviderException(string msg)
: base(msg)
{
}
}
/// <summary>
/// Class MovieDbProvider
@ -33,7 +34,7 @@ namespace MediaBrowser.Controller.Providers.Movies
public class MovieDbProvider : BaseMetadataProvider, IDisposable
{
protected readonly IProviderManager ProviderManager;
/// <summary>
/// The movie db
/// </summary>
@ -198,7 +199,7 @@ namespace MediaBrowser.Controller.Providers.Movies
base_url = "http://cf2.imgobject.com/t/p/"
}
};
};
}
}
@ -223,7 +224,14 @@ namespace MediaBrowser.Controller.Providers.Movies
//in addition to ours, we need to set the last refreshed time for the local data provider
//so it won't see the new files we download and process them all over again
if (JsonProvider == null) JsonProvider = new MovieProviderFromJson(LogManager, ConfigurationManager, JsonSerializer, HttpClient, ProviderManager);
var data = item.ProviderData.GetValueOrDefault(JsonProvider.Id, new BaseProviderInfo { ProviderId = JsonProvider.Id });
BaseProviderInfo data;
if (!item.ProviderData.TryGetValue(JsonProvider.Id, out data))
{
data = new BaseProviderInfo();
}
data.LastRefreshed = value;
item.ProviderData[JsonProvider.Id] = data;
}

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.Entities;
using MediaBrowser.Controller.Entities.Audio;
@ -52,14 +53,15 @@ namespace MediaBrowser.Controller.Providers.Music
//Look at our parent for our album cover
var artist = (MusicArtist)item.Parent;
var cover = artist.AlbumCovers != null ? artist.AlbumCovers.GetValueOrDefault(mbid, null) : null;
var cover = artist.AlbumCovers != null ? GetValueOrDefault(artist.AlbumCovers, mbid, null) : null;
if (cover == null)
{
// Not there - maybe it is new since artist last refreshed so refresh it and try again
await artist.RefreshMetadata(cancellationToken).ConfigureAwait(false);
cancellationToken.ThrowIfCancellationRequested();
cover = artist.AlbumCovers != null ? artist.AlbumCovers.GetValueOrDefault(mbid, null) : null;
cover = artist.AlbumCovers != null ? GetValueOrDefault(artist.AlbumCovers, mbid, null) : null;
}
if (cover == null)
{
@ -71,5 +73,25 @@ namespace MediaBrowser.Controller.Providers.Music
item.SetImage(ImageType.Primary, await _providerManager.DownloadAndSaveImage(item, cover, "folder.jpg", FanArtResourcePool, cancellationToken).ConfigureAwait(false));
return true;
}
/// <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();
var artist = (MusicArtist)item;
if (ShouldFetch(artist, artist.ProviderData.GetValueOrDefault(Id, new BaseProviderInfo { ProviderId = Id })))
BaseProviderInfo providerData;
if (!item.ProviderData.TryGetValue(Id, out providerData))
{
providerData = new BaseProviderInfo();
}
if (ShouldFetch(artist, providerData))
{
var url = string.Format(FanArtBaseUrl, APIKey, artist.GetProviderId(MetadataProviders.Musicbrainz));
var doc = new XmlDocument();

View File

@ -229,7 +229,13 @@ namespace MediaBrowser.Controller.Providers.Music
cancellationToken.ThrowIfCancellationRequested();
var providerData = item.ProviderData.GetValueOrDefault(Id, new BaseProviderInfo { ProviderId = Id });
BaseProviderInfo providerData;
if (!item.ProviderData.TryGetValue(Id, out providerData))
{
providerData = new BaseProviderInfo();
}
if (!ConfigurationManager.Configuration.SaveLocalMeta || !HasLocalMeta(item) || (force && !HasLocalMeta(item)) || (RefreshOnVersionChange && providerData.ProviderVersion != ProviderVersion))
{
try

View File

@ -60,7 +60,15 @@ namespace MediaBrowser.Controller.Providers.TV
cancellationToken.ThrowIfCancellationRequested();
var series = (Series)item;
if (ShouldFetch(series, series.ProviderData.GetValueOrDefault(Id, new BaseProviderInfo { ProviderId = Id })))
BaseProviderInfo providerData;
if (!item.ProviderData.TryGetValue(Id, out providerData))
{
providerData = new BaseProviderInfo();
}
if (ShouldFetch(series, providerData))
{
string language = ConfigurationManager.Configuration.PreferredMetadataLanguage.ToLower();
string url = string.Format(FanArtBaseUrl, APIKey, series.GetProviderId(MetadataProviders.Tvdb));

View File

@ -1,5 +1,6 @@
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Persistence;
namespace MediaBrowser.Controller.Sorting
{
@ -19,5 +20,11 @@ namespace MediaBrowser.Controller.Sorting
/// </summary>
/// <value>The user manager.</value>
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)]
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>
/// Characters to be replaced with a ' ' in strings to create a sort name
/// </summary>
@ -202,13 +181,6 @@ namespace MediaBrowser.Model.Configuration
[ProtoMember(30)]
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>
/// The list of types that will NOT be allowed to have internet providers run against them even if they are turned on.
/// </summary>

View File

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

View File

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

View File

@ -57,7 +57,7 @@ namespace MediaBrowser.Model.Plugins
/// </summary>
/// <value>The unique id.</value>
[ProtoMember(9)]
public Guid Id { get; set; }
public string Id { get; set; }
/// <summary>
/// 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
/// </summary>
/// <value>The user id.</value>
public Guid UserId { get; set; }
public string UserId { get; set; }
/// <summary>
/// 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 System;
namespace MediaBrowser.Model.Querying
{
@ -12,7 +11,7 @@ namespace MediaBrowser.Model.Querying
/// Gets or sets the user id.
/// </summary>
/// <value>The user id.</value>
public Guid UserId { get; set; }
public string UserId { get; set; }
/// <summary>
/// Gets or sets the start index.
/// </summary>

View File

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

View File

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

View File

@ -1,6 +1,7 @@
using MediaBrowser.Common.Events;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Persistence;
@ -86,20 +87,14 @@ namespace MediaBrowser.Server.Implementations.Library
/// </summary>
private readonly ILogger _logger;
private readonly IUserDataRepository _userDataRepository;
/// <summary>
/// Gets or sets the configuration manager.
/// </summary>
/// <value>The configuration manager.</value>
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>
/// Gets the active user repository
/// </summary>
@ -321,13 +316,13 @@ namespace MediaBrowser.Server.Implementations.Library
var connection = _activeConnections.GetOrAdd(key, keyName => new ClientConnectionInfo
{
UserId = userId,
UserId = userId.ToString(),
Client = clientType,
DeviceName = deviceName,
DeviceId = deviceId
});
connection.UserId = userId;
connection.UserId = userId.ToString();
return connection;
}
@ -591,12 +586,14 @@ namespace MediaBrowser.Server.Implementations.Library
UpdateNowPlayingItemId(user, clientType, deviceId, deviceName, item, positionTicks);
var key = item.GetUserDataKey();
if (positionTicks.HasValue)
{
var data = await GetUserData(user.Id, item.UserDataId).ConfigureAwait(false);
var data = await _userDataRepository.GetUserData(user.Id, key).ConfigureAwait(false);
UpdatePlayState(item, data, positionTicks.Value, false);
await SaveUserData(user.Id, item.UserDataId, data, CancellationToken.None).ConfigureAwait(false);
await _userDataRepository.SaveUserData(user.Id, key, data, CancellationToken.None).ConfigureAwait(false);
}
EventHelper.QueueEventIfNotNull(PlaybackProgress, this, new PlaybackProgressEventArgs
@ -631,7 +628,9 @@ namespace MediaBrowser.Server.Implementations.Library
RemoveNowPlayingItemId(user, clientType, deviceId, deviceName, item);
var data = await GetUserData(user.Id, item.UserDataId).ConfigureAwait(false);
var key = item.GetUserDataKey();
var data = await _userDataRepository.GetUserData(user.Id, key).ConfigureAwait(false);
if (positionTicks.HasValue)
{
@ -644,7 +643,7 @@ namespace MediaBrowser.Server.Implementations.Library
data.Played = true;
}
await SaveUserData(user.Id, item.UserDataId, data, CancellationToken.None).ConfigureAwait(false);
await _userDataRepository.SaveUserData(user.Id, key, data, CancellationToken.None).ConfigureAwait(false);
EventHelper.QueueEventIfNotNull(PlaybackStopped, this, new PlaybackProgressEventArgs
{
@ -703,59 +702,5 @@ namespace MediaBrowser.Server.Implementations.Library
data.LastPlayedDate = DateTime.UtcNow;
}
}
/// <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());
}
/// <summary>
/// Gets or sets the supported providers key.
/// </summary>
/// <value>The supported providers key.</value>
private Guid SupportedProvidersKey { get; set; }
/// <summary>
/// Adds the metadata providers.
/// </summary>
@ -103,6 +97,11 @@ namespace MediaBrowser.Server.Implementations.Providers
MetadataProviders = providers.OrderBy(e => e.Priority).ToArray();
}
/// <summary>
/// The _supported providers key
/// </summary>
private readonly Guid _supportedProvidersKey = "SupportedProviders".GetMD5();
/// <summary>
/// Runs all metadata providers for an entity, and returns true or false indicating if at least one was refreshed and requires persistence
/// </summary>
@ -126,19 +125,14 @@ namespace MediaBrowser.Server.Implementations.Providers
BaseProviderInfo supportedProvidersInfo;
if (SupportedProvidersKey == Guid.Empty)
{
SupportedProvidersKey = "SupportedProviders".GetMD5();
}
var supportedProvidersValue = string.Join("+", supportedProviders.Select(i => i.GetType().Name));
var providersChanged = false;
var supportedProvidersHash = string.Join("+", supportedProviders.Select(i => i.GetType().Name)).GetMD5();
bool providersChanged = false;
item.ProviderData.TryGetValue(SupportedProvidersKey, out supportedProvidersInfo);
item.ProviderData.TryGetValue(_supportedProvidersKey, out supportedProvidersInfo);
if (supportedProvidersInfo != null)
{
// Force refresh if the supported providers have changed
providersChanged = force = force || supportedProvidersInfo.FileSystemStamp != supportedProvidersHash;
providersChanged = force = force || !string.Equals(supportedProvidersInfo.FileSystemStamp, supportedProvidersValue);
// If providers have changed, clear provider info and update the supported providers hash
if (providersChanged)
@ -150,7 +144,7 @@ namespace MediaBrowser.Server.Implementations.Providers
if (providersChanged)
{
supportedProvidersInfo.FileSystemStamp = supportedProvidersHash;
supportedProvidersInfo.FileSystemStamp = supportedProvidersValue;
}
if (force) item.ClearMetaValues();
@ -206,7 +200,7 @@ namespace MediaBrowser.Server.Implementations.Providers
if (providersChanged)
{
item.ProviderData[SupportedProvidersKey] = supportedProvidersInfo;
item.ProviderData[_supportedProvidersKey] = supportedProvidersInfo;
}
return result || providersChanged;

View File

@ -1,5 +1,6 @@
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Persistence;
using MediaBrowser.Controller.Sorting;
using MediaBrowser.Model.Querying;
using System;
@ -23,6 +24,12 @@ namespace MediaBrowser.Server.Implementations.Sorting
/// <value>The user manager.</value>
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>
/// Compares the specified x.
/// </summary>
@ -41,7 +48,7 @@ namespace MediaBrowser.Server.Implementations.Sorting
/// <returns>DateTime.</returns>
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)
{

View File

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

View File

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

View File

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

View File

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

View File

@ -3,6 +3,7 @@ using MediaBrowser.Common.Net;
using MediaBrowser.Common.Plugins;
using MediaBrowser.Common.ScheduledTasks;
using MediaBrowser.Controller;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Plugins;
@ -174,7 +175,7 @@ namespace MediaBrowser.ServerApplication.EntryPoints
/// <param name="e">The e.</param>
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);
}

View File

@ -4,6 +4,7 @@ using MediaBrowser.Common.Net;
using MediaBrowser.Common.ScheduledTasks;
using MediaBrowser.Controller;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Plugins;
using MediaBrowser.Model.Logging;
@ -192,9 +193,9 @@ namespace MediaBrowser.WebDashboard.Api
{
var connections = userManager.RecentConnections.ToArray();
var dtoBuilder = new DtoBuilder(logger, libraryManager, userManager);
var dtoBuilder = new UserDtoBuilder(logger);
var users = userManager.Users.Where(u => connections.Any(c => c.UserId == u.Id)).Select(dtoBuilder.GetUserDto);
var users = userManager.Users.Where(u => connections.Any(c => new Guid(c.UserId) == u.Id)).Select(dtoBuilder.GetUserDto);
return new DashboardInfo
{