using MediaBrowser.Common.Extensions;
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.Persistence;
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
{
[Route("/Items/{Id}/File", "GET")]
[Api(Description = "Gets the original file of an item")]
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; }
}
[Route("/Videos/{Id}/Subtitle/{Index}", "GET")]
[Api(Description = "Gets an external subtitle file")]
public class GetSubtitle
{
///
/// 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 = "Index", Description = "The subtitle stream index", IsRequired = true, DataType = "int", ParameterType = "path", Verb = "GET")]
public int Index { get; set; }
}
///
/// Class GetCriticReviews
///
[Route("/Items/{Id}/CriticReviews", "GET")]
[Api(Description = "Gets critic reviews for an item")]
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")]
[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 = "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")]
[Api(Description = "Gets theme videos for an item")]
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")]
[Api(Description = "Gets theme videos and songs for an item")]
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")]
[Api(Description = "Starts a library scan")]
public class RefreshLibrary : IReturnVoid
{
}
[Route("/Items/{Id}", "DELETE")]
[Api(Description = "Deletes an item from the library and file system")]
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")]
[Api(Description = "Gets counts of various item types")]
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")]
[Api(Description = "Gets all parents of an item")]
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")]
[Api(Description = "Gets a year index based on an item query.")]
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 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;
///
/// Initializes a new instance of the class.
///
public LibraryService(IItemRepository itemRepo, ILibraryManager libraryManager, IUserManager userManager,
IDtoService dtoService, IUserDataManager userDataManager)
{
_itemRepo = itemRepo;
_libraryManager = libraryManager;
_userManager = userManager;
_dtoService = dtoService;
_userDataManager = userDataManager;
}
public object Get(GetFile request)
{
var item = _dtoService.GetItemByDtoId(request.Id);
if (item.LocationType == LocationType.Remote || item.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);
}
public object Get(GetSubtitle request)
{
var subtitleStream = _itemRepo.GetMediaStreams(new MediaStreamQuery
{
Index = request.Index,
ItemId = new Guid(request.Id),
Type = MediaStreamType.Subtitle
}).FirstOrDefault();
if (subtitleStream == null)
{
throw new ResourceNotFoundException();
}
return ToStaticFileResult(subtitleStream.Path);
}
///
/// 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 = _dtoService.GetItemByDtoId(request.Id);
var baseItemDtos = new List();
var user = request.UserId.HasValue ? _userManager.GetUserById(request.UserId.Value) : null;
// Get everything
var fields = Enum.GetNames(typeof(ItemFields))
.Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true))
.ToList();
BaseItem parent = item.Parent;
while (parent != null)
{
if (user != null)
{
parent = TranslateParentItem(parent, user);
}
baseItemDtos.Add(_dtoService.GetBaseItemDto(parent, fields, user));
if (parent is UserRootFolder)
{
break;
}
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.LocationType == LocationType.FileSystem &&
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 adultVideos = filteredItems.OfType().ToList();
var boxsets = filteredItems.OfType().ToList();
var books = filteredItems.OfType().ToList();
var songs = filteredItems.OfType