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; using System; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; namespace MediaBrowser.Api.UserLibrary { /// /// Class GetItem /// [Route("/Users/{UserId}/Items/{Id}", "GET")] [Api(Description = "Gets an item from a user's library")] public class GetItem : IReturn { /// /// Gets or sets the user id. /// /// The user id. [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")] public Guid UserId { get; set; } /// /// Gets or sets the id. /// /// The id. [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")] public string Id { get; set; } } /// /// Class GetItem /// [Route("/Users/{UserId}/Items/Root", "GET")] [Api(Description = "Gets the root folder from a user's library")] public class GetRootFolder : IReturn { /// /// Gets or sets the user id. /// /// The user id. [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")] public Guid UserId { get; set; } } /// /// Class GetIntros /// [Route("/Users/{UserId}/Items/{Id}/Intros", "GET")] [Api(("Gets intros to play before the main media item plays"))] public class GetIntros : IReturn> { /// /// Gets or sets the user id. /// /// The user id. [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")] public Guid UserId { get; set; } /// /// Gets or sets the item id. /// /// The item id. [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")] public string Id { get; set; } } /// /// Class MarkFavoriteItem /// [Route("/Users/{UserId}/FavoriteItems/{Id}", "POST")] [Api(Description = "Marks an item as a favorite")] public class MarkFavoriteItem : IReturnVoid { /// /// Gets or sets the user id. /// /// The user id. [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")] public Guid UserId { get; set; } /// /// Gets or sets the id. /// /// The id. [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")] public string Id { get; set; } } /// /// Class UnmarkFavoriteItem /// [Route("/Users/{UserId}/FavoriteItems/{Id}", "DELETE")] [Api(Description = "Unmarks an item as a favorite")] public class UnmarkFavoriteItem : IReturnVoid { /// /// Gets or sets the user id. /// /// The user id. [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")] public Guid UserId { get; set; } /// /// Gets or sets the id. /// /// The id. [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")] public string Id { get; set; } } /// /// Class ClearUserItemRating /// [Route("/Users/{UserId}/Items/{Id}/Rating", "DELETE")] [Api(Description = "Deletes a user's saved personal rating for an item")] public class DeleteUserItemRating : IReturnVoid { /// /// Gets or sets the user id. /// /// The user id. [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")] public Guid UserId { get; set; } /// /// Gets or sets the id. /// /// The id. [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")] public string Id { get; set; } } /// /// Class UpdateUserItemRating /// [Route("/Users/{UserId}/Items/{Id}/Rating", "POST")] [Api(Description = "Updates a user's rating for an item")] public class UpdateUserItemRating : IReturnVoid { /// /// Gets or sets the user id. /// /// The user id. [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")] public Guid UserId { get; set; } /// /// Gets or sets the id. /// /// The id. [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")] public string Id { get; set; } /// /// Gets or sets a value indicating whether this is likes. /// /// true if likes; otherwise, false. [ApiMember(Name = "Likes", Description = "Whether the user likes the item or not. true/false", IsRequired = true, DataType = "boolean", ParameterType = "query", Verb = "POST")] public bool Likes { get; set; } } /// /// Class MarkPlayedItem /// [Route("/Users/{UserId}/PlayedItems/{Id}", "POST")] [Api(Description = "Marks an item as played")] public class MarkPlayedItem : IReturnVoid { /// /// Gets or sets the user id. /// /// The user id. [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")] public Guid UserId { get; set; } /// /// Gets or sets the id. /// /// The id. [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")] public string Id { get; set; } } /// /// Class MarkUnplayedItem /// [Route("/Users/{UserId}/PlayedItems/{Id}", "DELETE")] [Api(Description = "Marks an item as unplayed")] public class MarkUnplayedItem : IReturnVoid { /// /// Gets or sets the user id. /// /// The user id. [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")] public Guid UserId { get; set; } /// /// Gets or sets the id. /// /// The id. [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")] public string Id { get; set; } } /// /// Class OnPlaybackStart /// [Route("/Users/{UserId}/PlayingItems/{Id}", "POST")] [Api(Description = "Reports that a user has begun playing an item")] public class OnPlaybackStart : IReturnVoid { /// /// Gets or sets the user id. /// /// The user id. [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")] public Guid UserId { get; set; } /// /// Gets or sets the id. /// /// The id. [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")] public string Id { get; set; } } /// /// Class OnPlaybackProgress /// [Route("/Users/{UserId}/PlayingItems/{Id}/Progress", "POST")] [Api(Description = "Reports a user's playback progress")] public class OnPlaybackProgress : IReturnVoid { /// /// Gets or sets the user id. /// /// The user id. [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")] public Guid UserId { get; set; } /// /// Gets or sets the id. /// /// The id. [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")] public string Id { get; set; } /// /// Gets or sets the position ticks. /// /// The position ticks. [ApiMember(Name = "PositionTicks", Description = "Optional. The current position, in ticks. 1 tick = 10000 ms", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "POST")] public long? PositionTicks { get; set; } } /// /// Class OnPlaybackStopped /// [Route("/Users/{UserId}/PlayingItems/{Id}", "DELETE")] [Api(Description = "Reports that a user has stopped playing an item")] public class OnPlaybackStopped : IReturnVoid { /// /// Gets or sets the user id. /// /// The user id. [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")] public Guid UserId { get; set; } /// /// Gets or sets the id. /// /// The id. [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")] public string Id { get; set; } /// /// Gets or sets the position ticks. /// /// The position ticks. [ApiMember(Name = "PositionTicks", Description = "Optional. The position, in ticks, where playback stopped. 1 tick = 10000 ms", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "DELETE")] public long? PositionTicks { get; set; } } /// /// Class GetLocalTrailers /// [Route("/Users/{UserId}/Items/{Id}/LocalTrailers", "GET")] [Api(Description = "Gets local trailers for an item")] public class GetLocalTrailers : IReturn> { /// /// Gets or sets the user id. /// /// The user id. [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")] public Guid UserId { get; set; } /// /// Gets or sets the id. /// /// The id. [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")] public string Id { get; set; } } /// /// Class GetThemeSongs /// [Route("/Users/{UserId}/Items/{Id}/ThemeSongs", "GET")] [Api(Description = "Gets theme songs for an item")] public class GetThemeSongs : IReturn { /// /// Gets or sets the user id. /// /// The user id. [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")] public Guid UserId { get; set; } /// /// Gets or sets the id. /// /// The id. [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")] public string Id { get; set; } } /// /// Class GetVideoBackdrops /// [Route("/Users/{UserId}/Items/{Id}/VideoBackdrops", "GET")] [Api(Description = "Gets video backdrops for an item")] public class GetVideoBackdrops : IReturn { /// /// Gets or sets the user id. /// /// The user id. [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")] public Guid UserId { get; set; } /// /// Gets or sets the id. /// /// The id. [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")] public string Id { get; set; } } /// /// Class GetSpecialFeatures /// [Route("/Users/{UserId}/Items/{Id}/SpecialFeatures", "GET")] [Api(Description = "Gets special features for a movie")] public class GetSpecialFeatures : IReturn> { /// /// Gets or sets the user id. /// /// The user id. [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")] public Guid UserId { get; set; } /// /// Gets or sets the id. /// /// The id. [ApiMember(Name = "Id", Description = "Movie Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")] public string Id { get; set; } } /// /// Class UserLibraryService /// public class UserLibraryService : BaseApiService { /// /// The _user manager /// private readonly IUserManager _userManager; /// /// The _user data repository /// private readonly IUserDataRepository _userDataRepository; /// /// The _library manager /// private readonly ILibraryManager _libraryManager; /// /// Initializes a new instance of the class. /// /// The user manager. /// The library manager. /// The user data repository. /// jsonSerializer public UserLibraryService(IUserManager userManager, ILibraryManager libraryManager, IUserDataRepository userDataRepository) : base() { _userManager = userManager; _libraryManager = libraryManager; _userDataRepository = userDataRepository; } /// /// Gets the specified request. /// /// The request. /// System.Object. public object Get(GetSpecialFeatures request) { var user = _userManager.GetUserById(request.UserId); var item = string.IsNullOrEmpty(request.Id) ? user.RootFolder : DtoBuilder.GetItemByClientId(request.Id, _userManager, _libraryManager, user.Id); // Get everything var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true)).ToList(); var movie = (Movie)item; var dtoBuilder = new DtoBuilder(Logger, _libraryManager, _userDataRepository); var items = movie.SpecialFeatures.Select(i => dtoBuilder.GetBaseItemDto(i, user, fields)).AsParallel().Select(t => t.Result).ToList(); return ToOptimizedResult(items); } /// /// Gets the specified request. /// /// The request. /// System.Object. public object Get(GetLocalTrailers request) { var user = _userManager.GetUserById(request.UserId); var item = string.IsNullOrEmpty(request.Id) ? user.RootFolder : DtoBuilder.GetItemByClientId(request.Id, _userManager, _libraryManager, user.Id); // Get everything var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true)).ToList(); var dtoBuilder = new DtoBuilder(Logger, _libraryManager, _userDataRepository); var items = item.LocalTrailers.Select(i => dtoBuilder.GetBaseItemDto(i, user, fields)).AsParallel().Select(t => t.Result).ToList(); return ToOptimizedResult(items); } /// /// Gets the specified request. /// /// The request. /// System.Object. public object Get(GetThemeSongs request) { var user = _userManager.GetUserById(request.UserId); var item = string.IsNullOrEmpty(request.Id) ? user.RootFolder : DtoBuilder.GetItemByClientId(request.Id, _userManager, _libraryManager, user.Id); // Get everything var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true)).ToList(); var dtoBuilder = new DtoBuilder(Logger, _libraryManager, _userDataRepository); var items = item.ThemeSongs.Select(i => dtoBuilder.GetBaseItemDto(i, user, fields)).AsParallel().Select(t => t.Result).ToArray(); var result = new ThemeSongsResult { Items = items, TotalRecordCount = items.Length, OwnerId = DtoBuilder.GetClientItemId(item) }; return ToOptimizedResult(result); } /// /// Gets the specified request. /// /// The request. /// System.Object. public object Get(GetVideoBackdrops request) { var user = _userManager.GetUserById(request.UserId); var item = string.IsNullOrEmpty(request.Id) ? user.RootFolder : DtoBuilder.GetItemByClientId(request.Id, _userManager, _libraryManager, user.Id); // Get everything var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true)).ToList(); var dtoBuilder = new DtoBuilder(Logger, _libraryManager, _userDataRepository); var items = item.VideoBackdrops.Select(i => dtoBuilder.GetBaseItemDto(i, user, fields)).AsParallel().Select(t => t.Result).ToArray(); var result = new VideoBackdropsResult { Items = items, TotalRecordCount = items.Length, OwnerId = DtoBuilder.GetClientItemId(item) }; return ToOptimizedResult(result); } /// /// Gets the specified request. /// /// The request. /// System.Object. public object Get(GetItem request) { var user = _userManager.GetUserById(request.UserId); var item = string.IsNullOrEmpty(request.Id) ? user.RootFolder : DtoBuilder.GetItemByClientId(request.Id, _userManager, _libraryManager, user.Id); // Get everything var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true)).ToList(); var dtoBuilder = new DtoBuilder(Logger, _libraryManager, _userDataRepository); var result = dtoBuilder.GetBaseItemDto(item, user, fields).Result; return ToOptimizedResult(result); } /// /// Gets the specified request. /// /// The request. /// System.Object. public object Get(GetRootFolder request) { var user = _userManager.GetUserById(request.UserId); var item = user.RootFolder; // Get everything var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true)).ToList(); var dtoBuilder = new DtoBuilder(Logger, _libraryManager, _userDataRepository); var result = dtoBuilder.GetBaseItemDto(item, user, fields).Result; return ToOptimizedResult(result); } /// /// Gets the specified request. /// /// The request. /// System.Object. public object Get(GetIntros request) { var user = _userManager.GetUserById(request.UserId); var item = string.IsNullOrEmpty(request.Id) ? user.RootFolder : DtoBuilder.GetItemByClientId(request.Id, _userManager, _libraryManager, user.Id); var result = _libraryManager.GetIntros(item, user); return ToOptimizedResult(result); } /// /// Posts the specified request. /// /// The request. public void Post(MarkFavoriteItem request) { var user = _userManager.GetUserById(request.UserId); var item = string.IsNullOrEmpty(request.Id) ? user.RootFolder : DtoBuilder.GetItemByClientId(request.Id, _userManager, _libraryManager, user.Id); // Get the user data for this item var key = item.GetUserDataKey(); var data = _userDataRepository.GetUserData(user.Id, key).Result; // Set favorite status data.IsFavorite = true; var task = _userDataRepository.SaveUserData(user.Id, key, data, CancellationToken.None); Task.WaitAll(task); } /// /// Deletes the specified request. /// /// The request. public void Delete(UnmarkFavoriteItem request) { var user = _userManager.GetUserById(request.UserId); 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 = _userDataRepository.GetUserData(user.Id, key).Result; // Set favorite status data.IsFavorite = false; var task = _userDataRepository.SaveUserData(user.Id, key, data, CancellationToken.None); Task.WaitAll(task); } /// /// Deletes the specified request. /// /// The request. public void Delete(DeleteUserItemRating request) { var user = _userManager.GetUserById(request.UserId); 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 = _userDataRepository.GetUserData(user.Id, key).Result; data.Rating = null; var task = _userDataRepository.SaveUserData(user.Id, key, data, CancellationToken.None); Task.WaitAll(task); } /// /// Posts the specified request. /// /// The request. public void Post(UpdateUserItemRating request) { var user = _userManager.GetUserById(request.UserId); 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 = _userDataRepository.GetUserData(user.Id, key).Result; data.Likes = request.Likes; var task = _userDataRepository.SaveUserData(user.Id, key, data, CancellationToken.None); Task.WaitAll(task); } /// /// Posts the specified request. /// /// The request. public void Post(MarkPlayedItem request) { var user = _userManager.GetUserById(request.UserId); var task = UpdatePlayedStatus(user, request.Id, true); Task.WaitAll(task); } /// /// Posts the specified request. /// /// The request. public void Post(OnPlaybackStart request) { var user = _userManager.GetUserById(request.UserId); var item = DtoBuilder.GetItemByClientId(request.Id, _userManager, _libraryManager, user.Id); var auth = RequestFilterAttribute.GetAuthorization(RequestContext); if (auth != null) { _userManager.OnPlaybackStart(user, item, auth["Client"], auth["DeviceId"], auth["Device"] ?? string.Empty); } } /// /// Posts the specified request. /// /// The request. public void Post(OnPlaybackProgress request) { var user = _userManager.GetUserById(request.UserId); var item = DtoBuilder.GetItemByClientId(request.Id, _userManager, _libraryManager, user.Id); var auth = RequestFilterAttribute.GetAuthorization(RequestContext); if (auth != null) { var task = _userManager.OnPlaybackProgress(user, item, request.PositionTicks, auth["Client"], auth["DeviceId"], auth["Device"] ?? string.Empty); Task.WaitAll(task); } } /// /// Posts the specified request. /// /// The request. public void Delete(OnPlaybackStopped request) { var user = _userManager.GetUserById(request.UserId); var item = DtoBuilder.GetItemByClientId(request.Id, _userManager, _libraryManager, user.Id); var auth = RequestFilterAttribute.GetAuthorization(RequestContext); if (auth != null) { var task = _userManager.OnPlaybackStopped(user, item, request.PositionTicks, auth["Client"], auth["DeviceId"], auth["Device"] ?? string.Empty); Task.WaitAll(task); } } /// /// Deletes the specified request. /// /// The request. public void Delete(MarkUnplayedItem request) { var user = _userManager.GetUserById(request.UserId); var task = UpdatePlayedStatus(user, request.Id, false); Task.WaitAll(task); } /// /// Updates the played status. /// /// The user. /// The item id. /// if set to true [was played]. /// Task. private Task UpdatePlayedStatus(User user, string itemId, bool wasPlayed) { var item = DtoBuilder.GetItemByClientId(itemId, _userManager, _libraryManager, user.Id); return item.SetPlayedStatus(user, wasPlayed, _userDataRepository); } } }