using MediaBrowser.Controller.Channels; using MediaBrowser.Controller.Dto; 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.LiveTv; using MediaBrowser.Controller.Net; using MediaBrowser.Controller.Persistence; using MediaBrowser.Controller.Playlists; using MediaBrowser.Controller.Session; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Querying; using ServiceStack; using System; using System.Collections; using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; namespace MediaBrowser.Api.Library { [Route("/Items/{Id}/File", "GET", Summary = "Gets the original file of an item")] [Authenticated] public class GetFile { /// /// 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 GetCriticReviews /// [Route("/Items/{Id}/CriticReviews", "GET", Summary = "Gets critic reviews for an item")] [Authenticated] public class GetCriticReviews : IReturn> { /// /// 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; } /// /// Skips over a given number of items within the results. Use for paging. /// /// The start index. [ApiMember(Name = "StartIndex", Description = "Optional. The record index to start at. All items with a lower index will be dropped from the results.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")] public int? StartIndex { get; set; } /// /// The maximum number of items to return /// /// The limit. [ApiMember(Name = "Limit", Description = "Optional. The maximum number of records to return", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")] public int? Limit { get; set; } } /// /// Class GetThemeSongs /// [Route("/Items/{Id}/ThemeSongs", "GET", Summary = "Gets theme songs for an item")] [Authenticated] public class GetThemeSongs : IReturn { /// /// Gets or sets the user id. /// /// The user id. [ApiMember(Name = "UserId", Description = "Optional. Filter by user id, and attach user data", IsRequired = false, DataType = "string", ParameterType = "query", 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; } [ApiMember(Name = "InheritFromParent", Description = "Determines whether or not parent items should be searched for theme media.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] public bool InheritFromParent { get; set; } } /// /// Class GetThemeVideos /// [Route("/Items/{Id}/ThemeVideos", "GET", Summary = "Gets theme videos for an item")] [Authenticated] public class GetThemeVideos : IReturn { /// /// Gets or sets the user id. /// /// The user id. [ApiMember(Name = "UserId", Description = "Optional. Filter by user id, and attach user data", IsRequired = false, DataType = "string", ParameterType = "query", 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; } [ApiMember(Name = "InheritFromParent", Description = "Determines whether or not parent items should be searched for theme media.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] public bool InheritFromParent { get; set; } } /// /// Class GetThemeVideos /// [Route("/Items/{Id}/ThemeMedia", "GET", Summary = "Gets theme videos and songs for an item")] [Authenticated] public class GetThemeMedia : IReturn { /// /// Gets or sets the user id. /// /// The user id. [ApiMember(Name = "UserId", Description = "Optional. Filter by user id, and attach user data", IsRequired = false, DataType = "string", ParameterType = "query", 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; } [ApiMember(Name = "InheritFromParent", Description = "Determines whether or not parent items should be searched for theme media.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] public bool InheritFromParent { get; set; } } [Route("/Library/Refresh", "POST", Summary = "Starts a library scan")] [Authenticated(Roles = "Admin")] public class RefreshLibrary : IReturnVoid { } [Route("/Items/{Id}", "DELETE", Summary = "Deletes an item from the library and file system")] [Authenticated] public class DeleteItem : IReturnVoid { [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")] public string Id { get; set; } } [Route("/Items/Counts", "GET")] [Authenticated] public class GetItemCounts : IReturn { [ApiMember(Name = "UserId", Description = "Optional. Get counts from a specific user's library.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] public Guid? UserId { get; set; } [ApiMember(Name = "IsFavorite", Description = "Optional. Get counts of favorite items", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")] public bool? IsFavorite { get; set; } } [Route("/Items/{Id}/Ancestors", "GET", Summary = "Gets all parents of an item")] [Authenticated] public class GetAncestors : IReturn { /// /// Gets or sets the user id. /// /// The user id. [ApiMember(Name = "UserId", Description = "Optional. Filter by user id, and attach user data", IsRequired = false, DataType = "string", ParameterType = "query", 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; } } [Route("/Items/YearIndex", "GET", Summary = "Gets a year index based on an item query.")] [Authenticated] public class GetYearIndex : IReturn> { /// /// Gets or sets the user id. /// /// The user id. [ApiMember(Name = "UserId", Description = "Optional. Filter by user id, and attach user data", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] public Guid? UserId { get; set; } [ApiMember(Name = "IncludeItemTypes", Description = "Optional. If specified, results will be filtered based on item type. This allows multiple, comma delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)] public string IncludeItemTypes { get; set; } } /// /// Class GetPhyscialPaths /// [Route("/Library/PhysicalPaths", "GET", Summary = "Gets a list of physical paths from virtual folders")] [Authenticated(Roles = "Admin")] public class GetPhyscialPaths : IReturn> { } [Route("/Library/MediaFolders", "GET", Summary = "Gets all user media folders.")] [Authenticated] public class GetMediaFolders : IReturn { [ApiMember(Name = "IsHidden", Description = "Optional. Filter by folders that are marked hidden, or not.", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")] public bool? IsHidden { get; set; } } [Route("/Library/Series/Added", "POST", Summary = "Reports that new episodes of a series have been added by an external source")] [Route("/Library/Series/Updated", "POST", Summary = "Reports that new episodes of a series have been added by an external source")] [Authenticated] public class PostUpdatedSeries : IReturnVoid { [ApiMember(Name = "TvdbId", Description = "Tvdb Id", IsRequired = false, DataType = "string", ParameterType = "path", Verb = "GET")] public string TvdbId { get; set; } } /// /// Class LibraryService /// public class LibraryService : BaseApiService { /// /// The _item repo /// private readonly IItemRepository _itemRepo; private readonly ILibraryManager _libraryManager; private readonly IUserManager _userManager; private readonly IUserDataManager _userDataManager; private readonly IDtoService _dtoService; private readonly IChannelManager _channelManager; private readonly ISessionManager _sessionManager; private readonly IAuthorizationContext _authContext; /// /// Initializes a new instance of the class. /// public LibraryService(IItemRepository itemRepo, ILibraryManager libraryManager, IUserManager userManager, IDtoService dtoService, IUserDataManager userDataManager, IChannelManager channelManager, ISessionManager sessionManager, IAuthorizationContext authContext) { _itemRepo = itemRepo; _libraryManager = libraryManager; _userManager = userManager; _dtoService = dtoService; _userDataManager = userDataManager; _channelManager = channelManager; _sessionManager = sessionManager; _authContext = authContext; } public object Get(GetMediaFolders request) { var items = _libraryManager.GetUserRootFolder().Children.OrderBy(i => i.SortName).ToList(); if (request.IsHidden.HasValue) { var val = request.IsHidden.Value; items = items.Where(i => i.IsHidden == val).ToList(); } var dtoOptions = GetDtoOptions(request); var result = new ItemsResult { TotalRecordCount = items.Count, Items = items.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions)).ToArray() }; return ToOptimizedResult(result); } public void Post(PostUpdatedSeries request) { Task.Run(() => _libraryManager.ValidateMediaLibrary(new Progress(), CancellationToken.None)); } public object Get(GetFile request) { var item = _libraryManager.GetItemById(request.Id); var locationType = item.LocationType; if (locationType == LocationType.Remote || locationType == LocationType.Virtual) { throw new ArgumentException("This command cannot be used for remote or virtual items."); } if (Directory.Exists(item.Path)) { throw new ArgumentException("This command cannot be used for directories."); } return ToStaticFileResult(item.Path); } /// /// Gets the specified request. /// /// The request. /// System.Object. public object Get(GetPhyscialPaths request) { var result = _libraryManager.RootFolder.Children .SelectMany(c => c.PhysicalLocations) .ToList(); return ToOptimizedSerializedResultUsingCache(result); } /// /// Gets the specified request. /// /// The request. /// System.Object. public object Get(GetAncestors request) { var result = GetAncestors(request); return ToOptimizedSerializedResultUsingCache(result); } /// /// Gets the ancestors. /// /// The request. /// Task{BaseItemDto[]}. public List GetAncestors(GetAncestors request) { var item = _libraryManager.GetItemById(request.Id); var baseItemDtos = new List(); var user = request.UserId.HasValue ? _userManager.GetUserById(request.UserId.Value) : null; var dtoOptions = GetDtoOptions(request); BaseItem parent = item.Parent; while (parent != null) { if (user != null) { parent = TranslateParentItem(parent, user); } baseItemDtos.Add(_dtoService.GetBaseItemDto(parent, dtoOptions, user)); parent = parent.Parent; } return baseItemDtos.ToList(); } private BaseItem TranslateParentItem(BaseItem item, User user) { if (item.Parent is AggregateFolder) { return user.RootFolder.GetChildren(user, true).FirstOrDefault(i => i.PhysicalLocations.Contains(item.Path)); } return item; } /// /// Gets the specified request. /// /// The request. /// System.Object. public object Get(GetCriticReviews request) { var result = GetCriticReviews(request); return ToOptimizedSerializedResultUsingCache(result); } /// /// Gets the specified request. /// /// The request. /// System.Object. public object Get(GetItemCounts request) { var items = GetAllLibraryItems(request.UserId, _userManager, _libraryManager) .Where(i => i.LocationType != LocationType.Virtual) .ToList(); var filteredItems = request.UserId.HasValue ? FilterItems(items, request, request.UserId.Value).ToList() : items; var albums = filteredItems.OfType().ToList(); var episodes = filteredItems.OfType().ToList(); var games = filteredItems.OfType().ToList(); var movies = filteredItems.OfType().ToList(); var musicVideos = filteredItems.OfType().ToList(); var boxsets = filteredItems.OfType().ToList(); var books = filteredItems.OfType().ToList(); var songs = filteredItems.OfType