| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170 | using System;using System.Collections.Generic;using System.ComponentModel.DataAnnotations;using System.Globalization;using System.Linq;using Jellyfin.Api.Extensions;using Jellyfin.Api.Helpers;using Jellyfin.Api.ModelBinders;using Jellyfin.Api.Models.UserViewDtos;using Jellyfin.Data.Enums;using MediaBrowser.Common.Extensions;using MediaBrowser.Controller.Dto;using MediaBrowser.Controller.Entities;using MediaBrowser.Controller.Library;using MediaBrowser.Model.Dto;using MediaBrowser.Model.Library;using MediaBrowser.Model.Querying;using Microsoft.AspNetCore.Authorization;using Microsoft.AspNetCore.Http;using Microsoft.AspNetCore.Mvc;namespace Jellyfin.Api.Controllers;/// <summary>/// User views controller./// </summary>[Route("")][Authorize]public class UserViewsController : BaseJellyfinApiController{    private readonly IUserManager _userManager;    private readonly IUserViewManager _userViewManager;    private readonly IDtoService _dtoService;    private readonly ILibraryManager _libraryManager;    /// <summary>    /// Initializes a new instance of the <see cref="UserViewsController"/> class.    /// </summary>    /// <param name="userManager">Instance of the <see cref="IUserManager"/> interface.</param>    /// <param name="userViewManager">Instance of the <see cref="IUserViewManager"/> interface.</param>    /// <param name="dtoService">Instance of the <see cref="IDtoService"/> interface.</param>    /// <param name="libraryManager">Instance of the <see cref="ILibraryManager"/> interface.</param>    public UserViewsController(        IUserManager userManager,        IUserViewManager userViewManager,        IDtoService dtoService,        ILibraryManager libraryManager)    {        _userManager = userManager;        _userViewManager = userViewManager;        _dtoService = dtoService;        _libraryManager = libraryManager;    }    /// <summary>    /// Get user views.    /// </summary>    /// <param name="userId">User id.</param>    /// <param name="includeExternalContent">Whether or not to include external views such as channels or live tv.</param>    /// <param name="presetViews">Preset views.</param>    /// <param name="includeHidden">Whether or not to include hidden content.</param>    /// <response code="200">User views returned.</response>    /// <returns>An <see cref="OkResult"/> containing the user views.</returns>    [HttpGet("UserViews")]    [ProducesResponseType(StatusCodes.Status200OK)]    public QueryResult<BaseItemDto> GetUserViews(        [FromQuery] Guid? userId,        [FromQuery] bool? includeExternalContent,        [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] CollectionType?[] presetViews,        [FromQuery] bool includeHidden = false)    {        userId = RequestHelpers.GetUserId(User, userId);        var user = _userManager.GetUserById(userId.Value) ?? throw new ResourceNotFoundException();        var query = new UserViewQuery { User = user, IncludeHidden = includeHidden };        if (includeExternalContent.HasValue)        {            query.IncludeExternalContent = includeExternalContent.Value;        }        if (presetViews.Length != 0)        {            query.PresetViews = presetViews;        }        var folders = _userViewManager.GetUserViews(query);        var dtoOptions = new DtoOptions().AddClientFields(User);        dtoOptions.Fields = [..dtoOptions.Fields, ItemFields.PrimaryImageAspectRatio, ItemFields.DisplayPreferencesId];        var dtos = Array.ConvertAll(folders, i => _dtoService.GetBaseItemDto(i, dtoOptions, user));        return new QueryResult<BaseItemDto>(dtos);    }    /// <summary>    /// Get user views.    /// </summary>    /// <param name="userId">User id.</param>    /// <param name="includeExternalContent">Whether or not to include external views such as channels or live tv.</param>    /// <param name="presetViews">Preset views.</param>    /// <param name="includeHidden">Whether or not to include hidden content.</param>    /// <response code="200">User views returned.</response>    /// <returns>An <see cref="OkResult"/> containing the user views.</returns>    [HttpGet("Users/{userId}/Views")]    [ProducesResponseType(StatusCodes.Status200OK)]    [Obsolete("Kept for backwards compatibility")]    [ApiExplorerSettings(IgnoreApi = true)]    public QueryResult<BaseItemDto> GetUserViewsLegacy(        [FromRoute, Required] Guid userId,        [FromQuery] bool? includeExternalContent,        [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] CollectionType?[] presetViews,        [FromQuery] bool includeHidden = false)        => GetUserViews(userId, includeExternalContent, presetViews, includeHidden);    /// <summary>    /// Get user view grouping options.    /// </summary>    /// <param name="userId">User id.</param>    /// <response code="200">User view grouping options returned.</response>    /// <response code="404">User not found.</response>    /// <returns>    /// An <see cref="OkResult"/> containing the user view grouping options    /// or a <see cref="NotFoundResult"/> if user not found.    /// </returns>    [HttpGet("UserViews/GroupingOptions")]    [ProducesResponseType(StatusCodes.Status200OK)]    [ProducesResponseType(StatusCodes.Status404NotFound)]    public ActionResult<IEnumerable<SpecialViewOptionDto>> GetGroupingOptions([FromQuery] Guid? userId)    {        userId = RequestHelpers.GetUserId(User, userId);        var user = _userManager.GetUserById(userId.Value);        if (user is null)        {            return NotFound();        }        return Ok(_libraryManager.GetUserRootFolder()            .GetChildren(user, true)            .OfType<Folder>()            .Where(UserView.IsEligibleForGrouping)            .Select(i => new SpecialViewOptionDto            {                Name = i.Name,                Id = i.Id.ToString("N", CultureInfo.InvariantCulture)            })            .OrderBy(i => i.Name)            .AsEnumerable());    }    /// <summary>    /// Get user view grouping options.    /// </summary>    /// <param name="userId">User id.</param>    /// <response code="200">User view grouping options returned.</response>    /// <response code="404">User not found.</response>    /// <returns>    /// An <see cref="OkResult"/> containing the user view grouping options    /// or a <see cref="NotFoundResult"/> if user not found.    /// </returns>    [HttpGet("Users/{userId}/GroupingOptions")]    [ProducesResponseType(StatusCodes.Status200OK)]    [ProducesResponseType(StatusCodes.Status404NotFound)]    [Obsolete("Kept for backwards compatibility")]    [ApiExplorerSettings(IgnoreApi = true)]    public ActionResult<IEnumerable<SpecialViewOptionDto>> GetGroupingOptionsLegacy(        [FromRoute, Required] Guid userId)        => GetGroupingOptions(userId);}
 |