| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512 | using System;using System.Collections.Generic;using System.Diagnostics;using System.Globalization;using System.Linq;using MediaBrowser.Controller.Dto;using MediaBrowser.Controller.Entities;using MediaBrowser.Controller.Entities.Audio;using MediaBrowser.Controller.Library;using MediaBrowser.Controller.Net;using MediaBrowser.Model.Dto;using MediaBrowser.Model.Entities;using MediaBrowser.Model.Globalization;using MediaBrowser.Model.Querying;using MediaBrowser.Model.Services;using Microsoft.Extensions.Logging;namespace MediaBrowser.Api.UserLibrary{    /// <summary>    /// Class GetItems    /// </summary>    [Route("/Items", "GET", Summary = "Gets items based on a query.")]    [Route("/Users/{UserId}/Items", "GET", Summary = "Gets items based on a query.")]    public class GetItems : BaseItemsRequest, IReturn<QueryResult<BaseItemDto>>    {    }    [Route("/Users/{UserId}/Items/Resume", "GET", Summary = "Gets items based on a query.")]    public class GetResumeItems : BaseItemsRequest, IReturn<QueryResult<BaseItemDto>>    {    }    /// <summary>    /// Class ItemsService    /// </summary>    [Authenticated]    public class ItemsService : BaseApiService    {        /// <summary>        /// The _user manager        /// </summary>        private readonly IUserManager _userManager;        /// <summary>        /// The _library manager        /// </summary>        private readonly ILibraryManager _libraryManager;        private readonly ILocalizationManager _localization;        private readonly IDtoService _dtoService;        private readonly IAuthorizationContext _authContext;        /// <summary>        /// Initializes a new instance of the <see cref="ItemsService" /> class.        /// </summary>        /// <param name="userManager">The user manager.</param>        /// <param name="libraryManager">The library manager.</param>        /// <param name="localization">The localization.</param>        /// <param name="dtoService">The dto service.</param>        public ItemsService(IUserManager userManager, ILibraryManager libraryManager, ILocalizationManager localization, IDtoService dtoService, IAuthorizationContext authContext)        {            if (userManager == null)            {                throw new ArgumentNullException(nameof(userManager));            }            if (libraryManager == null)            {                throw new ArgumentNullException(nameof(libraryManager));            }            if (localization == null)            {                throw new ArgumentNullException(nameof(localization));            }            if (dtoService == null)            {                throw new ArgumentNullException(nameof(dtoService));            }            _userManager = userManager;            _libraryManager = libraryManager;            _localization = localization;            _dtoService = dtoService;            _authContext = authContext;        }        public object Get(GetResumeItems request)        {            var user = _userManager.GetUserById(request.UserId);            var parentIdGuid = string.IsNullOrWhiteSpace(request.ParentId) ? Guid.Empty : new Guid(request.ParentId);            var options = GetDtoOptions(_authContext, request);            var ancestorIds = Array.Empty<Guid>();            var excludeFolderIds = user.Configuration.LatestItemsExcludes;            if (parentIdGuid.Equals(Guid.Empty) && excludeFolderIds.Length > 0)            {                ancestorIds = _libraryManager.GetUserRootFolder().GetChildren(user, true)                    .Where(i => i is Folder)                    .Where(i => !excludeFolderIds.Contains(i.Id.ToString("N", CultureInfo.InvariantCulture)))                    .Select(i => i.Id)                    .ToArray();            }            var itemsResult = _libraryManager.GetItemsResult(new InternalItemsQuery(user)            {                OrderBy = new[] { (ItemSortBy.DatePlayed, SortOrder.Descending) },                IsResumable = true,                StartIndex = request.StartIndex,                Limit = request.Limit,                ParentId = parentIdGuid,                Recursive = true,                DtoOptions = options,                MediaTypes = request.GetMediaTypes(),                IsVirtualItem = false,                CollapseBoxSetItems = false,                EnableTotalRecordCount = request.EnableTotalRecordCount,                AncestorIds = ancestorIds,                IncludeItemTypes = request.GetIncludeItemTypes(),                ExcludeItemTypes = request.GetExcludeItemTypes(),                SearchTerm = request.SearchTerm            });            var returnItems = _dtoService.GetBaseItemDtos(itemsResult.Items, options, user);            var result = new QueryResult<BaseItemDto>            {                TotalRecordCount = itemsResult.TotalRecordCount,                Items = returnItems            };            return ToOptimizedResult(result);        }        /// <summary>        /// Gets the specified request.        /// </summary>        /// <param name="request">The request.</param>        /// <returns>System.Object.</returns>        public object Get(GetItems request)        {            if (request == null)            {                throw new ArgumentNullException(nameof(request));            }            var result = GetItems(request);            return ToOptimizedResult(result);        }        /// <summary>        /// Gets the items.        /// </summary>        /// <param name="request">The request.</param>        private QueryResult<BaseItemDto> GetItems(GetItems request)        {            var user = request.UserId == Guid.Empty ? null : _userManager.GetUserById(request.UserId);            var dtoOptions = GetDtoOptions(_authContext, request);            var result = GetQueryResult(request, dtoOptions, user);            if (result == null)            {                throw new InvalidOperationException("GetItemsToSerialize returned null");            }            if (result.Items == null)            {                throw new InvalidOperationException("GetItemsToSerialize result.Items returned null");            }            var dtoList = _dtoService.GetBaseItemDtos(result.Items, dtoOptions, user);            return new QueryResult<BaseItemDto>            {                TotalRecordCount = result.TotalRecordCount,                Items = dtoList            };        }        /// <summary>        /// Gets the items to serialize.        /// </summary>        private QueryResult<BaseItem> GetQueryResult(GetItems request, DtoOptions dtoOptions, User user)        {            if (string.Equals(request.IncludeItemTypes, "Playlist", StringComparison.OrdinalIgnoreCase)                || string.Equals(request.IncludeItemTypes, "BoxSet", StringComparison.OrdinalIgnoreCase))            {                request.ParentId = null;            }            BaseItem item = null;            if (!string.IsNullOrEmpty(request.ParentId))            {                item = _libraryManager.GetItemById(request.ParentId);            }            if (item == null)            {                item = _libraryManager.GetUserRootFolder();            }            Folder folder = item as Folder;            if (folder == null)            {                folder = _libraryManager.GetUserRootFolder();            }            var hasCollectionType = folder as IHasCollectionType;            if (hasCollectionType != null                && string.Equals(hasCollectionType.CollectionType, CollectionType.Playlists, StringComparison.OrdinalIgnoreCase))            {                request.Recursive = true;                request.IncludeItemTypes = "Playlist";            }            bool isInEnabledFolder = user.Policy.EnabledFolders.Any(i => new Guid(i) == item.Id);            var collectionFolders = _libraryManager.GetCollectionFolders(item);            foreach (var collectionFolder in collectionFolders)            {                if (user.Policy.EnabledFolders.Contains(                    collectionFolder.Id.ToString("N", CultureInfo.InvariantCulture),                    StringComparer.OrdinalIgnoreCase))                {                    isInEnabledFolder = true;                }            }            if (!(item is UserRootFolder) && !user.Policy.EnableAllFolders && !isInEnabledFolder)            {                Logger.LogWarning("{UserName} is not permitted to access Library {ItemName}.", user.Name, item.Name);                return new QueryResult<BaseItem>                {                    Items = Array.Empty<BaseItem>(),                    TotalRecordCount = 0                };            }            if (request.Recursive || !string.IsNullOrEmpty(request.Ids) || !(item is UserRootFolder))            {                return folder.GetItems(GetItemsQuery(request, dtoOptions, user));            }            var itemsArray = folder.GetChildren(user, true).ToArray();            return new QueryResult<BaseItem>            {                Items = itemsArray,                TotalRecordCount = itemsArray.Length            };        }        private InternalItemsQuery GetItemsQuery(GetItems request, DtoOptions dtoOptions, User user)        {            var query = new InternalItemsQuery(user)            {                IsPlayed = request.IsPlayed,                MediaTypes = request.GetMediaTypes(),                IncludeItemTypes = request.GetIncludeItemTypes(),                ExcludeItemTypes = request.GetExcludeItemTypes(),                Recursive = request.Recursive,                OrderBy = request.GetOrderBy(),                IsFavorite = request.IsFavorite,                Limit = request.Limit,                StartIndex = request.StartIndex,                IsMissing = request.IsMissing,                IsUnaired = request.IsUnaired,                CollapseBoxSetItems = request.CollapseBoxSetItems,                NameLessThan = request.NameLessThan,                NameStartsWith = request.NameStartsWith,                NameStartsWithOrGreater = request.NameStartsWithOrGreater,                HasImdbId = request.HasImdbId,                IsPlaceHolder = request.IsPlaceHolder,                IsLocked = request.IsLocked,                MinWidth = request.MinWidth,                MinHeight = request.MinHeight,                MaxWidth = request.MaxWidth,                MaxHeight = request.MaxHeight,                Is3D = request.Is3D,                HasTvdbId = request.HasTvdbId,                HasTmdbId = request.HasTmdbId,                HasOverview = request.HasOverview,                HasOfficialRating = request.HasOfficialRating,                HasParentalRating = request.HasParentalRating,                HasSpecialFeature = request.HasSpecialFeature,                HasSubtitles = request.HasSubtitles,                HasThemeSong = request.HasThemeSong,                HasThemeVideo = request.HasThemeVideo,                HasTrailer = request.HasTrailer,                IsHD = request.IsHD,                Is4K = request.Is4K,                Tags = request.GetTags(),                OfficialRatings = request.GetOfficialRatings(),                Genres = request.GetGenres(),                ArtistIds = GetGuids(request.ArtistIds),                AlbumArtistIds = GetGuids(request.AlbumArtistIds),                ContributingArtistIds = GetGuids(request.ContributingArtistIds),                GenreIds = GetGuids(request.GenreIds),                StudioIds = GetGuids(request.StudioIds),                Person = request.Person,                PersonIds = GetGuids(request.PersonIds),                PersonTypes = request.GetPersonTypes(),                Years = request.GetYears(),                ImageTypes = request.GetImageTypes(),                VideoTypes = request.GetVideoTypes(),                AdjacentTo = request.AdjacentTo,                ItemIds = GetGuids(request.Ids),                MinCommunityRating = request.MinCommunityRating,                MinCriticRating = request.MinCriticRating,                ParentId = string.IsNullOrWhiteSpace(request.ParentId) ? Guid.Empty : new Guid(request.ParentId),                ParentIndexNumber = request.ParentIndexNumber,                EnableTotalRecordCount = request.EnableTotalRecordCount,                ExcludeItemIds = GetGuids(request.ExcludeItemIds),                DtoOptions = dtoOptions,                SearchTerm = request.SearchTerm            };            if (!string.IsNullOrWhiteSpace(request.Ids) || !string.IsNullOrWhiteSpace(request.SearchTerm))            {                query.CollapseBoxSetItems = false;            }            foreach (var filter in request.GetFilters())            {                switch (filter)                {                    case ItemFilter.Dislikes:                        query.IsLiked = false;                        break;                    case ItemFilter.IsFavorite:                        query.IsFavorite = true;                        break;                    case ItemFilter.IsFavoriteOrLikes:                        query.IsFavoriteOrLiked = true;                        break;                    case ItemFilter.IsFolder:                        query.IsFolder = true;                        break;                    case ItemFilter.IsNotFolder:                        query.IsFolder = false;                        break;                    case ItemFilter.IsPlayed:                        query.IsPlayed = true;                        break;                    case ItemFilter.IsResumable:                        query.IsResumable = true;                        break;                    case ItemFilter.IsUnplayed:                        query.IsPlayed = false;                        break;                    case ItemFilter.Likes:                        query.IsLiked = true;                        break;                }            }            if (!string.IsNullOrEmpty(request.MinDateLastSaved))            {                query.MinDateLastSaved = DateTime.Parse(request.MinDateLastSaved, null, DateTimeStyles.RoundtripKind).ToUniversalTime();            }            if (!string.IsNullOrEmpty(request.MinDateLastSavedForUser))            {                query.MinDateLastSavedForUser = DateTime.Parse(request.MinDateLastSavedForUser, null, DateTimeStyles.RoundtripKind).ToUniversalTime();            }            if (!string.IsNullOrEmpty(request.MinPremiereDate))            {                query.MinPremiereDate = DateTime.Parse(request.MinPremiereDate, null, DateTimeStyles.RoundtripKind).ToUniversalTime();            }            if (!string.IsNullOrEmpty(request.MaxPremiereDate))            {                query.MaxPremiereDate = DateTime.Parse(request.MaxPremiereDate, null, DateTimeStyles.RoundtripKind).ToUniversalTime();            }            // Filter by Series Status            if (!string.IsNullOrEmpty(request.SeriesStatus))            {                query.SeriesStatuses = request.SeriesStatus.Split(',').Select(d => (SeriesStatus)Enum.Parse(typeof(SeriesStatus), d, true)).ToArray();            }            // ExcludeLocationTypes            if (!string.IsNullOrEmpty(request.ExcludeLocationTypes))            {                var excludeLocationTypes = request.ExcludeLocationTypes.Split(',').Select(d => (LocationType)Enum.Parse(typeof(LocationType), d, true)).ToArray();                if (excludeLocationTypes.Contains(LocationType.Virtual))                {                    query.IsVirtualItem = false;                }            }            if (!string.IsNullOrEmpty(request.LocationTypes))            {                var requestedLocationTypes =                    request.LocationTypes.Split(',');                if (requestedLocationTypes.Length > 0 && requestedLocationTypes.Length < 4)                {                    query.IsVirtualItem = requestedLocationTypes.Contains(LocationType.Virtual.ToString());                }            }            // Min official rating            if (!string.IsNullOrWhiteSpace(request.MinOfficialRating))            {                query.MinParentalRating = _localization.GetRatingLevel(request.MinOfficialRating);            }            // Max official rating            if (!string.IsNullOrWhiteSpace(request.MaxOfficialRating))            {                query.MaxParentalRating = _localization.GetRatingLevel(request.MaxOfficialRating);            }            // Artists            if (!string.IsNullOrEmpty(request.Artists))            {                query.ArtistIds = request.Artists.Split('|').Select(i =>                {                    try                    {                        return _libraryManager.GetArtist(i, new DtoOptions(false));                    }                    catch                    {                        return null;                    }                }).Where(i => i != null).Select(i => i.Id).ToArray();            }            // ExcludeArtistIds            if (!string.IsNullOrWhiteSpace(request.ExcludeArtistIds))            {                query.ExcludeArtistIds = GetGuids(request.ExcludeArtistIds);            }            if (!string.IsNullOrWhiteSpace(request.AlbumIds))            {                query.AlbumIds = GetGuids(request.AlbumIds);            }            // Albums            if (!string.IsNullOrEmpty(request.Albums))            {                query.AlbumIds = request.Albums.Split('|').SelectMany(i =>                {                    return _libraryManager.GetItemIds(new InternalItemsQuery                    {                        IncludeItemTypes = new[] { typeof(MusicAlbum).Name },                        Name = i,                        Limit = 1                    });                }).ToArray();            }            // Studios            if (!string.IsNullOrEmpty(request.Studios))            {                query.StudioIds = request.Studios.Split('|').Select(i =>                {                    try                    {                        return _libraryManager.GetStudio(i);                    }                    catch                    {                        return null;                    }                }).Where(i => i != null).Select(i => i.Id).ToArray();            }            // Apply default sorting if none requested            if (query.OrderBy.Length == 0)            {                // Albums by artist                if (query.ArtistIds.Length > 0 && query.IncludeItemTypes.Length == 1 && string.Equals(query.IncludeItemTypes[0], "MusicAlbum", StringComparison.OrdinalIgnoreCase))                {                    query.OrderBy = new[]                    {                        new ValueTuple<string, SortOrder>(ItemSortBy.ProductionYear, SortOrder.Descending),                        new ValueTuple<string, SortOrder>(ItemSortBy.SortName, SortOrder.Ascending)                    };                }            }            return query;        }    }    /// <summary>    /// Class DateCreatedComparer    /// </summary>    public class DateCreatedComparer : IComparer<BaseItem>    {        /// <summary>        /// Compares the specified x.        /// </summary>        /// <param name="x">The x.</param>        /// <param name="y">The y.</param>        /// <returns>System.Int32.</returns>        public int Compare(BaseItem x, BaseItem y)        {            return x.DateCreated.CompareTo(y.DateCreated);        }    }}
 |