commit
14faebc7fe
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,161 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Jellyfin.Api.Constants;
|
||||
using MediaBrowser.Model.Tasks;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
|
||||
namespace Jellyfin.Api.Controllers
|
||||
{
|
||||
/// <summary>
|
||||
/// Scheduled Tasks Controller.
|
||||
/// </summary>
|
||||
[Authorize(Policy = Policies.RequiresElevation)]
|
||||
public class ScheduledTasksController : BaseJellyfinApiController
|
||||
{
|
||||
private readonly ITaskManager _taskManager;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ScheduledTasksController"/> class.
|
||||
/// </summary>
|
||||
/// <param name="taskManager">Instance of the <see cref="ITaskManager"/> interface.</param>
|
||||
public ScheduledTasksController(ITaskManager taskManager)
|
||||
{
|
||||
_taskManager = taskManager;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get tasks.
|
||||
/// </summary>
|
||||
/// <param name="isHidden">Optional filter tasks that are hidden, or not.</param>
|
||||
/// <param name="isEnabled">Optional filter tasks that are enabled, or not.</param>
|
||||
/// <response code="200">Scheduled tasks retrieved.</response>
|
||||
/// <returns>The list of scheduled tasks.</returns>
|
||||
[HttpGet]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
public IEnumerable<IScheduledTaskWorker> GetTasks(
|
||||
[FromQuery] bool? isHidden,
|
||||
[FromQuery] bool? isEnabled)
|
||||
{
|
||||
IEnumerable<IScheduledTaskWorker> tasks = _taskManager.ScheduledTasks.OrderBy(o => o.Name);
|
||||
|
||||
foreach (var task in tasks)
|
||||
{
|
||||
if (task.ScheduledTask is IConfigurableScheduledTask scheduledTask)
|
||||
{
|
||||
if (isHidden.HasValue && isHidden.Value != scheduledTask.IsHidden)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isEnabled.HasValue && isEnabled.Value != scheduledTask.IsEnabled)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
yield return task;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get task by id.
|
||||
/// </summary>
|
||||
/// <param name="taskId">Task Id.</param>
|
||||
/// <response code="200">Task retrieved.</response>
|
||||
/// <response code="404">Task not found.</response>
|
||||
/// <returns>An <see cref="OkResult"/> containing the task on success, or a <see cref="NotFoundResult"/> if the task could not be found.</returns>
|
||||
[HttpGet("{taskId}")]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public ActionResult<TaskInfo> GetTask([FromRoute] string? taskId)
|
||||
{
|
||||
var task = _taskManager.ScheduledTasks.FirstOrDefault(i =>
|
||||
string.Equals(i.Id, taskId, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
if (task == null)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
return ScheduledTaskHelpers.GetTaskInfo(task);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Start specified task.
|
||||
/// </summary>
|
||||
/// <param name="taskId">Task Id.</param>
|
||||
/// <response code="204">Task started.</response>
|
||||
/// <response code="404">Task not found.</response>
|
||||
/// <returns>An <see cref="NoContentResult"/> on success, or a <see cref="NotFoundResult"/> if the file could not be found.</returns>
|
||||
[HttpPost("Running/{taskId}")]
|
||||
[ProducesResponseType(StatusCodes.Status204NoContent)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public ActionResult StartTask([FromRoute] string? taskId)
|
||||
{
|
||||
var task = _taskManager.ScheduledTasks.FirstOrDefault(o =>
|
||||
o.Id.Equals(taskId, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
if (task == null)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
_taskManager.Execute(task, new TaskOptions());
|
||||
return NoContent();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stop specified task.
|
||||
/// </summary>
|
||||
/// <param name="taskId">Task Id.</param>
|
||||
/// <response code="204">Task stopped.</response>
|
||||
/// <response code="404">Task not found.</response>
|
||||
/// <returns>An <see cref="OkResult"/> on success, or a <see cref="NotFoundResult"/> if the file could not be found.</returns>
|
||||
[HttpDelete("Running/{taskId}")]
|
||||
[ProducesResponseType(StatusCodes.Status204NoContent)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public ActionResult StopTask([FromRoute] string? taskId)
|
||||
{
|
||||
var task = _taskManager.ScheduledTasks.FirstOrDefault(o =>
|
||||
o.Id.Equals(taskId, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
if (task == null)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
_taskManager.Cancel(task);
|
||||
return NoContent();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update specified task triggers.
|
||||
/// </summary>
|
||||
/// <param name="taskId">Task Id.</param>
|
||||
/// <param name="triggerInfos">Triggers.</param>
|
||||
/// <response code="204">Task triggers updated.</response>
|
||||
/// <response code="404">Task not found.</response>
|
||||
/// <returns>An <see cref="OkResult"/> on success, or a <see cref="NotFoundResult"/> if the file could not be found.</returns>
|
||||
[HttpPost("{taskId}/Triggers")]
|
||||
[ProducesResponseType(StatusCodes.Status204NoContent)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public ActionResult UpdateTask(
|
||||
[FromRoute] string? taskId,
|
||||
[FromBody, BindRequired] TaskTriggerInfo[] triggerInfos)
|
||||
{
|
||||
var task = _taskManager.ScheduledTasks.FirstOrDefault(o =>
|
||||
o.Id.Equals(taskId, StringComparison.OrdinalIgnoreCase));
|
||||
if (task == null)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
task.Triggers = triggerInfos;
|
||||
return NoContent();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,377 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using Jellyfin.Api.Constants;
|
||||
using Jellyfin.Api.Extensions;
|
||||
using MediaBrowser.Common.Extensions;
|
||||
using MediaBrowser.Controller.Dto;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Entities.TV;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.TV;
|
||||
using MediaBrowser.Model.Dto;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Querying;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Jellyfin.Api.Controllers
|
||||
{
|
||||
/// <summary>
|
||||
/// The tv shows controller.
|
||||
/// </summary>
|
||||
[Route("/Shows")]
|
||||
[Authorize(Policy = Policies.DefaultAuthorization)]
|
||||
public class TvShowsController : BaseJellyfinApiController
|
||||
{
|
||||
private readonly IUserManager _userManager;
|
||||
private readonly ILibraryManager _libraryManager;
|
||||
private readonly IDtoService _dtoService;
|
||||
private readonly ITVSeriesManager _tvSeriesManager;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TvShowsController"/> class.
|
||||
/// </summary>
|
||||
/// <param name="userManager">Instance of the <see cref="IUserManager"/> interface.</param>
|
||||
/// <param name="libraryManager">Instance of the <see cref="ILibraryManager"/> interface.</param>
|
||||
/// <param name="dtoService">Instance of the <see cref="IDtoService"/> interface.</param>
|
||||
/// <param name="tvSeriesManager">Instance of the <see cref="ITVSeriesManager"/> interface.</param>
|
||||
public TvShowsController(
|
||||
IUserManager userManager,
|
||||
ILibraryManager libraryManager,
|
||||
IDtoService dtoService,
|
||||
ITVSeriesManager tvSeriesManager)
|
||||
{
|
||||
_userManager = userManager;
|
||||
_libraryManager = libraryManager;
|
||||
_dtoService = dtoService;
|
||||
_tvSeriesManager = tvSeriesManager;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of next up episodes.
|
||||
/// </summary>
|
||||
/// <param name="userId">The user id of the user to get the next up episodes for.</param>
|
||||
/// <param name="startIndex">Optional. The record index to start at. All items with a lower index will be dropped from the results.</param>
|
||||
/// <param name="limit">Optional. The maximum number of records to return.</param>
|
||||
/// <param name="fields">Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimeted. Options: Budget, Chapters, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines, TrailerUrls.</param>
|
||||
/// <param name="seriesId">Optional. Filter by series id.</param>
|
||||
/// <param name="parentId">Optional. Specify this to localize the search to a specific item or folder. Omit to use the root.</param>
|
||||
/// <param name="enableImges">Optional. Include image information in output.</param>
|
||||
/// <param name="imageTypeLimit">Optional. The max number of images to return, per image type.</param>
|
||||
/// <param name="enableImageTypes">Optional. The image types to include in the output.</param>
|
||||
/// <param name="enableUserData">Optional. Include user data.</param>
|
||||
/// <param name="enableTotalRecordCount">Whether to enable the total records count. Defaults to true.</param>
|
||||
/// <returns>A <see cref="QueryResult{BaseItemDto}"/> with the next up episodes.</returns>
|
||||
[HttpGet("NextUp")]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
public ActionResult<QueryResult<BaseItemDto>> GetNextUp(
|
||||
[FromQuery] Guid userId,
|
||||
[FromQuery] int? startIndex,
|
||||
[FromQuery] int? limit,
|
||||
[FromQuery] string? fields,
|
||||
[FromQuery] string? seriesId,
|
||||
[FromQuery] string? parentId,
|
||||
[FromQuery] bool? enableImges,
|
||||
[FromQuery] int? imageTypeLimit,
|
||||
[FromQuery] string? enableImageTypes,
|
||||
[FromQuery] bool? enableUserData,
|
||||
[FromQuery] bool enableTotalRecordCount = true)
|
||||
{
|
||||
var options = new DtoOptions()
|
||||
.AddItemFields(fields!)
|
||||
.AddClientFields(Request)
|
||||
.AddAdditionalDtoOptions(enableImges, enableUserData, imageTypeLimit, enableImageTypes!);
|
||||
|
||||
var result = _tvSeriesManager.GetNextUp(
|
||||
new NextUpQuery
|
||||
{
|
||||
Limit = limit,
|
||||
ParentId = parentId,
|
||||
SeriesId = seriesId,
|
||||
StartIndex = startIndex,
|
||||
UserId = userId,
|
||||
EnableTotalRecordCount = enableTotalRecordCount
|
||||
},
|
||||
options);
|
||||
|
||||
var user = _userManager.GetUserById(userId);
|
||||
|
||||
var returnItems = _dtoService.GetBaseItemDtos(result.Items, options, user);
|
||||
|
||||
return new QueryResult<BaseItemDto>
|
||||
{
|
||||
TotalRecordCount = result.TotalRecordCount,
|
||||
Items = returnItems
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of upcoming episodes.
|
||||
/// </summary>
|
||||
/// <param name="userId">The user id of the user to get the upcoming episodes for.</param>
|
||||
/// <param name="startIndex">Optional. The record index to start at. All items with a lower index will be dropped from the results.</param>
|
||||
/// <param name="limit">Optional. The maximum number of records to return.</param>
|
||||
/// <param name="fields">Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimeted. Options: Budget, Chapters, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines, TrailerUrls.</param>
|
||||
/// <param name="parentId">Optional. Specify this to localize the search to a specific item or folder. Omit to use the root.</param>
|
||||
/// <param name="enableImges">Optional. Include image information in output.</param>
|
||||
/// <param name="imageTypeLimit">Optional. The max number of images to return, per image type.</param>
|
||||
/// <param name="enableImageTypes">Optional. The image types to include in the output.</param>
|
||||
/// <param name="enableUserData">Optional. Include user data.</param>
|
||||
/// <returns>A <see cref="QueryResult{BaseItemDto}"/> with the next up episodes.</returns>
|
||||
[HttpGet("Upcoming")]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
public ActionResult<QueryResult<BaseItemDto>> GetUpcomingEpisodes(
|
||||
[FromQuery] Guid userId,
|
||||
[FromQuery] int? startIndex,
|
||||
[FromQuery] int? limit,
|
||||
[FromQuery] string? fields,
|
||||
[FromQuery] string? parentId,
|
||||
[FromQuery] bool? enableImges,
|
||||
[FromQuery] int? imageTypeLimit,
|
||||
[FromQuery] string? enableImageTypes,
|
||||
[FromQuery] bool? enableUserData)
|
||||
{
|
||||
var user = _userManager.GetUserById(userId);
|
||||
|
||||
var minPremiereDate = DateTime.Now.Date.ToUniversalTime().AddDays(-1);
|
||||
|
||||
var parentIdGuid = string.IsNullOrWhiteSpace(parentId) ? Guid.Empty : new Guid(parentId);
|
||||
|
||||
var options = new DtoOptions()
|
||||
.AddItemFields(fields!)
|
||||
.AddClientFields(Request)
|
||||
.AddAdditionalDtoOptions(enableImges, enableUserData, imageTypeLimit, enableImageTypes!);
|
||||
|
||||
var itemsResult = _libraryManager.GetItemList(new InternalItemsQuery(user)
|
||||
{
|
||||
IncludeItemTypes = new[] { nameof(Episode) },
|
||||
OrderBy = new[] { ItemSortBy.PremiereDate, ItemSortBy.SortName }.Select(i => new ValueTuple<string, SortOrder>(i, SortOrder.Ascending)).ToArray(),
|
||||
MinPremiereDate = minPremiereDate,
|
||||
StartIndex = startIndex,
|
||||
Limit = limit,
|
||||
ParentId = parentIdGuid,
|
||||
Recursive = true,
|
||||
DtoOptions = options
|
||||
});
|
||||
|
||||
var returnItems = _dtoService.GetBaseItemDtos(itemsResult, options, user);
|
||||
|
||||
return new QueryResult<BaseItemDto>
|
||||
{
|
||||
TotalRecordCount = itemsResult.Count,
|
||||
Items = returnItems
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets episodes for a tv season.
|
||||
/// </summary>
|
||||
/// <param name="seriesId">The series id.</param>
|
||||
/// <param name="userId">The user id.</param>
|
||||
/// <param name="fields">Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimeted. Options: Budget, Chapters, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines, TrailerUrls.</param>
|
||||
/// <param name="season">Optional filter by season number.</param>
|
||||
/// <param name="seasonId">Optional. Filter by season id.</param>
|
||||
/// <param name="isMissing">Optional. Filter by items that are missing episodes or not.</param>
|
||||
/// <param name="adjacentTo">Optional. Return items that are siblings of a supplied item.</param>
|
||||
/// <param name="startItemId">Optional. Skip through the list until a given item is found.</param>
|
||||
/// <param name="startIndex">Optional. The record index to start at. All items with a lower index will be dropped from the results.</param>
|
||||
/// <param name="limit">Optional. The maximum number of records to return.</param>
|
||||
/// <param name="enableImages">Optional, include image information in output.</param>
|
||||
/// <param name="imageTypeLimit">Optional, the max number of images to return, per image type.</param>
|
||||
/// <param name="enableImageTypes">Optional. The image types to include in the output.</param>
|
||||
/// <param name="enableUserData">Optional. Include user data.</param>
|
||||
/// <param name="sortBy">Optional. Specify one or more sort orders, comma delimeted. Options: Album, AlbumArtist, Artist, Budget, CommunityRating, CriticRating, DateCreated, DatePlayed, PlayCount, PremiereDate, ProductionYear, SortName, Random, Revenue, Runtime.</param>
|
||||
/// <returns>A <see cref="QueryResult{BaseItemDto}"/> with the episodes on success or a <see cref="NotFoundResult"/> if the series was not found.</returns>
|
||||
[HttpGet("{seriesId}/Episodes")]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public ActionResult<QueryResult<BaseItemDto>> GetEpisodes(
|
||||
[FromRoute] string? seriesId,
|
||||
[FromQuery] Guid userId,
|
||||
[FromQuery] string? fields,
|
||||
[FromQuery] int? season,
|
||||
[FromQuery] string? seasonId,
|
||||
[FromQuery] bool? isMissing,
|
||||
[FromQuery] string? adjacentTo,
|
||||
[FromQuery] string? startItemId,
|
||||
[FromQuery] int? startIndex,
|
||||
[FromQuery] int? limit,
|
||||
[FromQuery] bool? enableImages,
|
||||
[FromQuery] int? imageTypeLimit,
|
||||
[FromQuery] string? enableImageTypes,
|
||||
[FromQuery] bool? enableUserData,
|
||||
[FromQuery] string? sortBy)
|
||||
{
|
||||
var user = _userManager.GetUserById(userId);
|
||||
|
||||
List<BaseItem> episodes;
|
||||
|
||||
var dtoOptions = new DtoOptions()
|
||||
.AddItemFields(fields!)
|
||||
.AddClientFields(Request)
|
||||
.AddAdditionalDtoOptions(enableImages, enableUserData, imageTypeLimit, enableImageTypes!);
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(seasonId)) // Season id was supplied. Get episodes by season id.
|
||||
{
|
||||
var item = _libraryManager.GetItemById(new Guid(seasonId));
|
||||
if (!(item is Season seasonItem))
|
||||
{
|
||||
return NotFound("No season exists with Id " + seasonId);
|
||||
}
|
||||
|
||||
episodes = seasonItem.GetEpisodes(user, dtoOptions);
|
||||
}
|
||||
else if (season.HasValue) // Season number was supplied. Get episodes by season number
|
||||
{
|
||||
if (!(_libraryManager.GetItemById(seriesId) is Series series))
|
||||
{
|
||||
return NotFound("Series not found");
|
||||
}
|
||||
|
||||
var seasonItem = series
|
||||
.GetSeasons(user, dtoOptions)
|
||||
.FirstOrDefault(i => i.IndexNumber == season.Value);
|
||||
|
||||
episodes = seasonItem == null ?
|
||||
new List<BaseItem>()
|
||||
: ((Season)seasonItem).GetEpisodes(user, dtoOptions);
|
||||
}
|
||||
else // No season number or season id was supplied. Returning all episodes.
|
||||
{
|
||||
if (!(_libraryManager.GetItemById(seriesId) is Series series))
|
||||
{
|
||||
return NotFound("Series not found");
|
||||
}
|
||||
|
||||
episodes = series.GetEpisodes(user, dtoOptions).ToList();
|
||||
}
|
||||
|
||||
// Filter after the fact in case the ui doesn't want them
|
||||
if (isMissing.HasValue)
|
||||
{
|
||||
var val = isMissing.Value;
|
||||
episodes = episodes
|
||||
.Where(i => ((Episode)i).IsMissingEpisode == val)
|
||||
.ToList();
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(startItemId))
|
||||
{
|
||||
episodes = episodes
|
||||
.SkipWhile(i => !string.Equals(i.Id.ToString("N", CultureInfo.InvariantCulture), startItemId, StringComparison.OrdinalIgnoreCase))
|
||||
.ToList();
|
||||
}
|
||||
|
||||
// This must be the last filter
|
||||
if (!string.IsNullOrEmpty(adjacentTo))
|
||||
{
|
||||
episodes = UserViewBuilder.FilterForAdjacency(episodes, adjacentTo).ToList();
|
||||
}
|
||||
|
||||
if (string.Equals(sortBy, ItemSortBy.Random, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
episodes.Shuffle();
|
||||
}
|
||||
|
||||
var returnItems = episodes;
|
||||
|
||||
if (startIndex.HasValue || limit.HasValue)
|
||||
{
|
||||
returnItems = ApplyPaging(episodes, startIndex, limit).ToList();
|
||||
}
|
||||
|
||||
var dtos = _dtoService.GetBaseItemDtos(returnItems, dtoOptions, user);
|
||||
|
||||
return new QueryResult<BaseItemDto>
|
||||
{
|
||||
TotalRecordCount = episodes.Count,
|
||||
Items = dtos
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets seasons for a tv series.
|
||||
/// </summary>
|
||||
/// <param name="seriesId">The series id.</param>
|
||||
/// <param name="userId">The user id.</param>
|
||||
/// <param name="fields">Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimeted. Options: Budget, Chapters, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines, TrailerUrls.</param>
|
||||
/// <param name="isSpecialSeason">Optional. Filter by special season.</param>
|
||||
/// <param name="isMissing">Optional. Filter by items that are missing episodes or not.</param>
|
||||
/// <param name="adjacentTo">Optional. Return items that are siblings of a supplied item.</param>
|
||||
/// <param name="enableImages">Optional. Include image information in output.</param>
|
||||
/// <param name="imageTypeLimit">Optional. The max number of images to return, per image type.</param>
|
||||
/// <param name="enableImageTypes">Optional. The image types to include in the output.</param>
|
||||
/// <param name="enableUserData">Optional. Include user data.</param>
|
||||
/// <returns>A <see cref="QueryResult{BaseItemDto}"/> on success or a <see cref="NotFoundResult"/> if the series was not found.</returns>
|
||||
[HttpGet("{seriesId}/Seasons")]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public ActionResult<QueryResult<BaseItemDto>> GetSeasons(
|
||||
[FromRoute] string? seriesId,
|
||||
[FromQuery] Guid userId,
|
||||
[FromQuery] string? fields,
|
||||
[FromQuery] bool? isSpecialSeason,
|
||||
[FromQuery] bool? isMissing,
|
||||
[FromQuery] string? adjacentTo,
|
||||
[FromQuery] bool? enableImages,
|
||||
[FromQuery] int? imageTypeLimit,
|
||||
[FromQuery] string? enableImageTypes,
|
||||
[FromQuery] bool? enableUserData)
|
||||
{
|
||||
var user = _userManager.GetUserById(userId);
|
||||
|
||||
if (!(_libraryManager.GetItemById(seriesId) is Series series))
|
||||
{
|
||||
return NotFound("Series not found");
|
||||
}
|
||||
|
||||
var seasons = series.GetItemList(new InternalItemsQuery(user)
|
||||
{
|
||||
IsMissing = isMissing,
|
||||
IsSpecialSeason = isSpecialSeason,
|
||||
AdjacentTo = adjacentTo
|
||||
});
|
||||
|
||||
var dtoOptions = new DtoOptions()
|
||||
.AddItemFields(fields)
|
||||
.AddClientFields(Request)
|
||||
.AddAdditionalDtoOptions(enableImages, enableUserData, imageTypeLimit, enableImageTypes!);
|
||||
|
||||
var returnItems = _dtoService.GetBaseItemDtos(seasons, dtoOptions, user);
|
||||
|
||||
return new QueryResult<BaseItemDto>
|
||||
{
|
||||
TotalRecordCount = returnItems.Count,
|
||||
Items = returnItems
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Applies the paging.
|
||||
/// </summary>
|
||||
/// <param name="items">The items.</param>
|
||||
/// <param name="startIndex">The start index.</param>
|
||||
/// <param name="limit">The limit.</param>
|
||||
/// <returns>IEnumerable{BaseItem}.</returns>
|
||||
private IEnumerable<BaseItem> ApplyPaging(IEnumerable<BaseItem> items, int? startIndex, int? limit)
|
||||
{
|
||||
// Start at
|
||||
if (startIndex.HasValue)
|
||||
{
|
||||
items = items.Skip(startIndex.Value);
|
||||
}
|
||||
|
||||
// Return limit
|
||||
if (limit.HasValue)
|
||||
{
|
||||
items = items.Take(limit.Value);
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,105 +0,0 @@
|
||||
using System;
|
||||
using MediaBrowser.Controller.Collections;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Dto;
|
||||
using MediaBrowser.Controller.Net;
|
||||
using MediaBrowser.Model.Collections;
|
||||
using MediaBrowser.Model.Services;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace MediaBrowser.Api.Movies
|
||||
{
|
||||
[Route("/Collections", "POST", Summary = "Creates a new collection")]
|
||||
public class CreateCollection : IReturn<CollectionCreationResult>
|
||||
{
|
||||
[ApiMember(Name = "IsLocked", Description = "Whether or not to lock the new collection.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "POST")]
|
||||
public bool IsLocked { get; set; }
|
||||
|
||||
[ApiMember(Name = "Name", Description = "The name of the new collection.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")]
|
||||
public string Name { get; set; }
|
||||
|
||||
[ApiMember(Name = "ParentId", Description = "Optional - create the collection within a specific folder", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")]
|
||||
public string ParentId { get; set; }
|
||||
|
||||
[ApiMember(Name = "Ids", Description = "Item Ids to add to the collection", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST", AllowMultiple = true)]
|
||||
public string Ids { get; set; }
|
||||
}
|
||||
|
||||
[Route("/Collections/{Id}/Items", "POST", Summary = "Adds items to a collection")]
|
||||
public class AddToCollection : IReturnVoid
|
||||
{
|
||||
[ApiMember(Name = "Ids", Description = "Item id, comma delimited", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST")]
|
||||
public string Ids { get; set; }
|
||||
|
||||
[ApiMember(Name = "Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
|
||||
public string Id { get; set; }
|
||||
}
|
||||
|
||||
[Route("/Collections/{Id}/Items", "DELETE", Summary = "Removes items from a collection")]
|
||||
public class RemoveFromCollection : IReturnVoid
|
||||
{
|
||||
[ApiMember(Name = "Ids", Description = "Item id, comma delimited", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "DELETE")]
|
||||
public string Ids { get; set; }
|
||||
|
||||
[ApiMember(Name = "Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")]
|
||||
public string Id { get; set; }
|
||||
}
|
||||
|
||||
[Authenticated]
|
||||
public class CollectionService : BaseApiService
|
||||
{
|
||||
private readonly ICollectionManager _collectionManager;
|
||||
private readonly IDtoService _dtoService;
|
||||
private readonly IAuthorizationContext _authContext;
|
||||
|
||||
public CollectionService(
|
||||
ILogger<CollectionService> logger,
|
||||
IServerConfigurationManager serverConfigurationManager,
|
||||
IHttpResultFactory httpResultFactory,
|
||||
ICollectionManager collectionManager,
|
||||
IDtoService dtoService,
|
||||
IAuthorizationContext authContext)
|
||||
: base(logger, serverConfigurationManager, httpResultFactory)
|
||||
{
|
||||
_collectionManager = collectionManager;
|
||||
_dtoService = dtoService;
|
||||
_authContext = authContext;
|
||||
}
|
||||
|
||||
public object Post(CreateCollection request)
|
||||
{
|
||||
var userId = _authContext.GetAuthorizationInfo(Request).UserId;
|
||||
|
||||
var parentId = string.IsNullOrWhiteSpace(request.ParentId) ? (Guid?)null : new Guid(request.ParentId);
|
||||
|
||||
var item = _collectionManager.CreateCollection(new CollectionCreationOptions
|
||||
{
|
||||
IsLocked = request.IsLocked,
|
||||
Name = request.Name,
|
||||
ParentId = parentId,
|
||||
ItemIdList = SplitValue(request.Ids, ','),
|
||||
UserIds = new[] { userId }
|
||||
|
||||
});
|
||||
|
||||
var dtoOptions = GetDtoOptions(_authContext, request);
|
||||
|
||||
var dto = _dtoService.GetBaseItemDto(item, dtoOptions);
|
||||
|
||||
return new CollectionCreationResult
|
||||
{
|
||||
Id = dto.Id
|
||||
};
|
||||
}
|
||||
|
||||
public void Post(AddToCollection request)
|
||||
{
|
||||
_collectionManager.AddToCollection(new Guid(request.Id), SplitValue(request.Ids, ','));
|
||||
}
|
||||
|
||||
public void Delete(RemoveFromCollection request)
|
||||
{
|
||||
_collectionManager.RemoveFromCollection(new Guid(request.Id), SplitValue(request.Ids, ','));
|
||||
}
|
||||
}
|
||||
}
|
@ -1,132 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Dto;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Entities.Audio;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Net;
|
||||
using MediaBrowser.Controller.Persistence;
|
||||
using MediaBrowser.Model.Services;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace MediaBrowser.Api.Music
|
||||
{
|
||||
[Route("/Albums/{Id}/Similar", "GET", Summary = "Finds albums similar to a given album.")]
|
||||
public class GetSimilarAlbums : BaseGetSimilarItemsFromItem
|
||||
{
|
||||
}
|
||||
|
||||
[Route("/Artists/{Id}/Similar", "GET", Summary = "Finds albums similar to a given album.")]
|
||||
public class GetSimilarArtists : BaseGetSimilarItemsFromItem
|
||||
{
|
||||
}
|
||||
|
||||
[Authenticated]
|
||||
public class AlbumsService : BaseApiService
|
||||
{
|
||||
/// <summary>
|
||||
/// The _user manager
|
||||
/// </summary>
|
||||
private readonly IUserManager _userManager;
|
||||
|
||||
/// <summary>
|
||||
/// The _user data repository
|
||||
/// </summary>
|
||||
private readonly IUserDataManager _userDataRepository;
|
||||
/// <summary>
|
||||
/// The _library manager
|
||||
/// </summary>
|
||||
private readonly ILibraryManager _libraryManager;
|
||||
private readonly IItemRepository _itemRepo;
|
||||
private readonly IDtoService _dtoService;
|
||||
private readonly IAuthorizationContext _authContext;
|
||||
|
||||
public AlbumsService(
|
||||
ILogger<AlbumsService> logger,
|
||||
IServerConfigurationManager serverConfigurationManager,
|
||||
IHttpResultFactory httpResultFactory,
|
||||
IUserManager userManager,
|
||||
IUserDataManager userDataRepository,
|
||||
ILibraryManager libraryManager,
|
||||
IItemRepository itemRepo,
|
||||
IDtoService dtoService,
|
||||
IAuthorizationContext authContext)
|
||||
: base(logger, serverConfigurationManager, httpResultFactory)
|
||||
{
|
||||
_userManager = userManager;
|
||||
_userDataRepository = userDataRepository;
|
||||
_libraryManager = libraryManager;
|
||||
_itemRepo = itemRepo;
|
||||
_dtoService = dtoService;
|
||||
_authContext = authContext;
|
||||
}
|
||||
|
||||
public object Get(GetSimilarArtists request)
|
||||
{
|
||||
var dtoOptions = GetDtoOptions(_authContext, request);
|
||||
|
||||
var result = SimilarItemsHelper.GetSimilarItemsResult(
|
||||
dtoOptions,
|
||||
_userManager,
|
||||
_itemRepo,
|
||||
_libraryManager,
|
||||
_userDataRepository,
|
||||
_dtoService,
|
||||
request, new[] { typeof(MusicArtist) },
|
||||
SimilarItemsHelper.GetSimiliarityScore);
|
||||
|
||||
return ToOptimizedResult(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the specified request.
|
||||
/// </summary>
|
||||
/// <param name="request">The request.</param>
|
||||
/// <returns>System.Object.</returns>
|
||||
public object Get(GetSimilarAlbums request)
|
||||
{
|
||||
var dtoOptions = GetDtoOptions(_authContext, request);
|
||||
|
||||
var result = SimilarItemsHelper.GetSimilarItemsResult(
|
||||
dtoOptions,
|
||||
_userManager,
|
||||
_itemRepo,
|
||||
_libraryManager,
|
||||
_userDataRepository,
|
||||
_dtoService,
|
||||
request, new[] { typeof(MusicAlbum) },
|
||||
GetAlbumSimilarityScore);
|
||||
|
||||
return ToOptimizedResult(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the album similarity score.
|
||||
/// </summary>
|
||||
/// <param name="item1">The item1.</param>
|
||||
/// <param name="item1People">The item1 people.</param>
|
||||
/// <param name="allPeople">All people.</param>
|
||||
/// <param name="item2">The item2.</param>
|
||||
/// <returns>System.Int32.</returns>
|
||||
private int GetAlbumSimilarityScore(BaseItem item1, List<PersonInfo> item1People, List<PersonInfo> allPeople, BaseItem item2)
|
||||
{
|
||||
var points = SimilarItemsHelper.GetSimiliarityScore(item1, item1People, allPeople, item2);
|
||||
|
||||
var album1 = (MusicAlbum)item1;
|
||||
var album2 = (MusicAlbum)item2;
|
||||
|
||||
var artists1 = album1
|
||||
.GetAllArtists()
|
||||
.DistinctNames()
|
||||
.ToList();
|
||||
|
||||
var artists2 = new HashSet<string>(
|
||||
album2.GetAllArtists().DistinctNames(),
|
||||
StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
return points + artists1.Where(artists2.Contains).Sum(i => 5);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,197 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Jellyfin.Data.Entities;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Dto;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Net;
|
||||
using MediaBrowser.Controller.Playlists;
|
||||
using MediaBrowser.Model.Dto;
|
||||
using MediaBrowser.Model.Querying;
|
||||
using MediaBrowser.Model.Services;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace MediaBrowser.Api.Music
|
||||
{
|
||||
[Route("/Songs/{Id}/InstantMix", "GET", Summary = "Creates an instant playlist based on a given song")]
|
||||
public class GetInstantMixFromSong : BaseGetSimilarItemsFromItem
|
||||
{
|
||||
}
|
||||
|
||||
[Route("/Albums/{Id}/InstantMix", "GET", Summary = "Creates an instant playlist based on a given album")]
|
||||
public class GetInstantMixFromAlbum : BaseGetSimilarItemsFromItem
|
||||
{
|
||||
}
|
||||
|
||||
[Route("/Playlists/{Id}/InstantMix", "GET", Summary = "Creates an instant playlist based on a given playlist")]
|
||||
public class GetInstantMixFromPlaylist : BaseGetSimilarItemsFromItem
|
||||
{
|
||||
}
|
||||
|
||||
[Route("/MusicGenres/{Name}/InstantMix", "GET", Summary = "Creates an instant playlist based on a music genre")]
|
||||
public class GetInstantMixFromMusicGenre : BaseGetSimilarItems
|
||||
{
|
||||
[ApiMember(Name = "Name", Description = "The genre name", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
|
||||
public string Name { get; set; }
|
||||
}
|
||||
|
||||
[Route("/Artists/InstantMix", "GET", Summary = "Creates an instant playlist based on a given artist")]
|
||||
public class GetInstantMixFromArtistId : BaseGetSimilarItems
|
||||
{
|
||||
[ApiMember(Name = "Id", Description = "The artist Id", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string Id { get; set; }
|
||||
}
|
||||
|
||||
[Route("/MusicGenres/InstantMix", "GET", Summary = "Creates an instant playlist based on a music genre")]
|
||||
public class GetInstantMixFromMusicGenreId : BaseGetSimilarItems
|
||||
{
|
||||
[ApiMember(Name = "Id", Description = "The genre Id", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string Id { get; set; }
|
||||
}
|
||||
|
||||
[Route("/Items/{Id}/InstantMix", "GET", Summary = "Creates an instant playlist based on a given item")]
|
||||
public class GetInstantMixFromItem : BaseGetSimilarItemsFromItem
|
||||
{
|
||||
}
|
||||
|
||||
[Authenticated]
|
||||
public class InstantMixService : BaseApiService
|
||||
{
|
||||
private readonly IUserManager _userManager;
|
||||
|
||||
private readonly IDtoService _dtoService;
|
||||
private readonly ILibraryManager _libraryManager;
|
||||
private readonly IMusicManager _musicManager;
|
||||
private readonly IAuthorizationContext _authContext;
|
||||
|
||||
public InstantMixService(
|
||||
ILogger<InstantMixService> logger,
|
||||
IServerConfigurationManager serverConfigurationManager,
|
||||
IHttpResultFactory httpResultFactory,
|
||||
IUserManager userManager,
|
||||
IDtoService dtoService,
|
||||
IMusicManager musicManager,
|
||||
ILibraryManager libraryManager,
|
||||
IAuthorizationContext authContext)
|
||||
: base(logger, serverConfigurationManager, httpResultFactory)
|
||||
{
|
||||
_userManager = userManager;
|
||||
_dtoService = dtoService;
|
||||
_musicManager = musicManager;
|
||||
_libraryManager = libraryManager;
|
||||
_authContext = authContext;
|
||||
}
|
||||
|
||||
public object Get(GetInstantMixFromItem request)
|
||||
{
|
||||
var item = _libraryManager.GetItemById(request.Id);
|
||||
|
||||
var user = _userManager.GetUserById(request.UserId);
|
||||
|
||||
var dtoOptions = GetDtoOptions(_authContext, request);
|
||||
|
||||
var items = _musicManager.GetInstantMixFromItem(item, user, dtoOptions);
|
||||
|
||||
return GetResult(items, user, request, dtoOptions);
|
||||
}
|
||||
|
||||
public object Get(GetInstantMixFromArtistId request)
|
||||
{
|
||||
var item = _libraryManager.GetItemById(request.Id);
|
||||
|
||||
var user = _userManager.GetUserById(request.UserId);
|
||||
|
||||
var dtoOptions = GetDtoOptions(_authContext, request);
|
||||
|
||||
var items = _musicManager.GetInstantMixFromItem(item, user, dtoOptions);
|
||||
|
||||
return GetResult(items, user, request, dtoOptions);
|
||||
}
|
||||
|
||||
public object Get(GetInstantMixFromMusicGenreId request)
|
||||
{
|
||||
var item = _libraryManager.GetItemById(request.Id);
|
||||
|
||||
var user = _userManager.GetUserById(request.UserId);
|
||||
|
||||
var dtoOptions = GetDtoOptions(_authContext, request);
|
||||
|
||||
var items = _musicManager.GetInstantMixFromItem(item, user, dtoOptions);
|
||||
|
||||
return GetResult(items, user, request, dtoOptions);
|
||||
}
|
||||
|
||||
public object Get(GetInstantMixFromSong request)
|
||||
{
|
||||
var item = _libraryManager.GetItemById(request.Id);
|
||||
|
||||
var user = _userManager.GetUserById(request.UserId);
|
||||
|
||||
var dtoOptions = GetDtoOptions(_authContext, request);
|
||||
|
||||
var items = _musicManager.GetInstantMixFromItem(item, user, dtoOptions);
|
||||
|
||||
return GetResult(items, user, request, dtoOptions);
|
||||
}
|
||||
|
||||
public object Get(GetInstantMixFromAlbum request)
|
||||
{
|
||||
var album = _libraryManager.GetItemById(request.Id);
|
||||
|
||||
var user = _userManager.GetUserById(request.UserId);
|
||||
|
||||
var dtoOptions = GetDtoOptions(_authContext, request);
|
||||
|
||||
var items = _musicManager.GetInstantMixFromItem(album, user, dtoOptions);
|
||||
|
||||
return GetResult(items, user, request, dtoOptions);
|
||||
}
|
||||
|
||||
public object Get(GetInstantMixFromPlaylist request)
|
||||
{
|
||||
var playlist = (Playlist)_libraryManager.GetItemById(request.Id);
|
||||
|
||||
var user = _userManager.GetUserById(request.UserId);
|
||||
|
||||
var dtoOptions = GetDtoOptions(_authContext, request);
|
||||
|
||||
var items = _musicManager.GetInstantMixFromItem(playlist, user, dtoOptions);
|
||||
|
||||
return GetResult(items, user, request, dtoOptions);
|
||||
}
|
||||
|
||||
public object Get(GetInstantMixFromMusicGenre request)
|
||||
{
|
||||
var user = _userManager.GetUserById(request.UserId);
|
||||
|
||||
var dtoOptions = GetDtoOptions(_authContext, request);
|
||||
|
||||
var items = _musicManager.GetInstantMixFromGenres(new[] { request.Name }, user, dtoOptions);
|
||||
|
||||
return GetResult(items, user, request, dtoOptions);
|
||||
}
|
||||
|
||||
private object GetResult(List<BaseItem> items, User user, BaseGetSimilarItems request, DtoOptions dtoOptions)
|
||||
{
|
||||
var list = items;
|
||||
|
||||
var result = new QueryResult<BaseItemDto>
|
||||
{
|
||||
TotalRecordCount = list.Count
|
||||
};
|
||||
|
||||
if (request.Limit.HasValue)
|
||||
{
|
||||
list = list.Take(request.Limit.Value).ToList();
|
||||
}
|
||||
|
||||
var returnList = _dtoService.GetBaseItemDtos(list, dtoOptions, user);
|
||||
|
||||
result.Items = returnList;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -1,234 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using MediaBrowser.Common.Extensions;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Net;
|
||||
using MediaBrowser.Model.Services;
|
||||
using MediaBrowser.Model.Tasks;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace MediaBrowser.Api.ScheduledTasks
|
||||
{
|
||||
/// <summary>
|
||||
/// Class GetScheduledTask
|
||||
/// </summary>
|
||||
[Route("/ScheduledTasks/{Id}", "GET", Summary = "Gets a scheduled task, by Id")]
|
||||
public class GetScheduledTask : IReturn<TaskInfo>
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the id.
|
||||
/// </summary>
|
||||
/// <value>The id.</value>
|
||||
[ApiMember(Name = "Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
|
||||
public string Id { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Class GetScheduledTasks
|
||||
/// </summary>
|
||||
[Route("/ScheduledTasks", "GET", Summary = "Gets scheduled tasks")]
|
||||
public class GetScheduledTasks : IReturn<TaskInfo[]>
|
||||
{
|
||||
[ApiMember(Name = "IsHidden", Description = "Optional filter tasks that are hidden, or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
|
||||
public bool? IsHidden { get; set; }
|
||||
|
||||
[ApiMember(Name = "IsEnabled", Description = "Optional filter tasks that are enabled, or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
|
||||
public bool? IsEnabled { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Class StartScheduledTask
|
||||
/// </summary>
|
||||
[Route("/ScheduledTasks/Running/{Id}", "POST", Summary = "Starts a scheduled task")]
|
||||
public class StartScheduledTask : IReturnVoid
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the id.
|
||||
/// </summary>
|
||||
/// <value>The id.</value>
|
||||
[ApiMember(Name = "Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
|
||||
public string Id { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Class StopScheduledTask
|
||||
/// </summary>
|
||||
[Route("/ScheduledTasks/Running/{Id}", "DELETE", Summary = "Stops a scheduled task")]
|
||||
public class StopScheduledTask : IReturnVoid
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the id.
|
||||
/// </summary>
|
||||
/// <value>The id.</value>
|
||||
[ApiMember(Name = "Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")]
|
||||
public string Id { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Class UpdateScheduledTaskTriggers
|
||||
/// </summary>
|
||||
[Route("/ScheduledTasks/{Id}/Triggers", "POST", Summary = "Updates the triggers for a scheduled task")]
|
||||
public class UpdateScheduledTaskTriggers : List<TaskTriggerInfo>, IReturnVoid
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the task id.
|
||||
/// </summary>
|
||||
/// <value>The task id.</value>
|
||||
[ApiMember(Name = "Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
|
||||
public string Id { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Class ScheduledTasksService
|
||||
/// </summary>
|
||||
[Authenticated(Roles = "Admin")]
|
||||
public class ScheduledTaskService : BaseApiService
|
||||
{
|
||||
/// <summary>
|
||||
/// The task manager.
|
||||
/// </summary>
|
||||
private readonly ITaskManager _taskManager;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ScheduledTaskService" /> class.
|
||||
/// </summary>
|
||||
/// <param name="taskManager">The task manager.</param>
|
||||
/// <exception cref="ArgumentNullException">taskManager</exception>
|
||||
public ScheduledTaskService(
|
||||
ILogger<ScheduledTaskService> logger,
|
||||
IServerConfigurationManager serverConfigurationManager,
|
||||
IHttpResultFactory httpResultFactory,
|
||||
ITaskManager taskManager)
|
||||
: base(logger, serverConfigurationManager, httpResultFactory)
|
||||
{
|
||||
_taskManager = taskManager;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the specified request.
|
||||
/// </summary>
|
||||
/// <param name="request">The request.</param>
|
||||
/// <returns>IEnumerable{TaskInfo}.</returns>
|
||||
public object Get(GetScheduledTasks request)
|
||||
{
|
||||
IEnumerable<IScheduledTaskWorker> result = _taskManager.ScheduledTasks
|
||||
.OrderBy(i => i.Name);
|
||||
|
||||
if (request.IsHidden.HasValue)
|
||||
{
|
||||
var val = request.IsHidden.Value;
|
||||
|
||||
result = result.Where(i =>
|
||||
{
|
||||
var isHidden = false;
|
||||
|
||||
if (i.ScheduledTask is IConfigurableScheduledTask configurableTask)
|
||||
{
|
||||
isHidden = configurableTask.IsHidden;
|
||||
}
|
||||
|
||||
return isHidden == val;
|
||||
});
|
||||
}
|
||||
|
||||
if (request.IsEnabled.HasValue)
|
||||
{
|
||||
var val = request.IsEnabled.Value;
|
||||
|
||||
result = result.Where(i =>
|
||||
{
|
||||
var isEnabled = true;
|
||||
|
||||
if (i.ScheduledTask is IConfigurableScheduledTask configurableTask)
|
||||
{
|
||||
isEnabled = configurableTask.IsEnabled;
|
||||
}
|
||||
|
||||
return isEnabled == val;
|
||||
});
|
||||
}
|
||||
|
||||
var infos = result
|
||||
.Select(ScheduledTaskHelpers.GetTaskInfo)
|
||||
.ToArray();
|
||||
|
||||
return ToOptimizedResult(infos);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the specified request.
|
||||
/// </summary>
|
||||
/// <param name="request">The request.</param>
|
||||
/// <returns>IEnumerable{TaskInfo}.</returns>
|
||||
/// <exception cref="ResourceNotFoundException">Task not found</exception>
|
||||
public object Get(GetScheduledTask request)
|
||||
{
|
||||
var task = _taskManager.ScheduledTasks.FirstOrDefault(i => string.Equals(i.Id, request.Id));
|
||||
|
||||
if (task == null)
|
||||
{
|
||||
throw new ResourceNotFoundException("Task not found");
|
||||
}
|
||||
|
||||
var result = ScheduledTaskHelpers.GetTaskInfo(task);
|
||||
|
||||
return ToOptimizedResult(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Posts the specified request.
|
||||
/// </summary>
|
||||
/// <param name="request">The request.</param>
|
||||
/// <exception cref="ResourceNotFoundException">Task not found</exception>
|
||||
public void Post(StartScheduledTask request)
|
||||
{
|
||||
var task = _taskManager.ScheduledTasks.FirstOrDefault(i => string.Equals(i.Id, request.Id));
|
||||
|
||||
if (task == null)
|
||||
{
|
||||
throw new ResourceNotFoundException("Task not found");
|
||||
}
|
||||
|
||||
_taskManager.Execute(task, new TaskOptions());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Posts the specified request.
|
||||
/// </summary>
|
||||
/// <param name="request">The request.</param>
|
||||
/// <exception cref="ResourceNotFoundException">Task not found</exception>
|
||||
public void Delete(StopScheduledTask request)
|
||||
{
|
||||
var task = _taskManager.ScheduledTasks.FirstOrDefault(i => string.Equals(i.Id, request.Id));
|
||||
|
||||
if (task == null)
|
||||
{
|
||||
throw new ResourceNotFoundException("Task not found");
|
||||
}
|
||||
|
||||
_taskManager.Cancel(task);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Posts the specified request.
|
||||
/// </summary>
|
||||
/// <param name="request">The request.</param>
|
||||
/// <exception cref="ResourceNotFoundException">Task not found</exception>
|
||||
public void Post(UpdateScheduledTaskTriggers request)
|
||||
{
|
||||
// We need to parse this manually because we told service stack not to with IRequiresRequestStream
|
||||
// https://code.google.com/p/servicestack/source/browse/trunk/Common/ServiceStack.Text/ServiceStack.Text/Controller/PathInfo.cs
|
||||
var id = GetPathValue(1).ToString();
|
||||
|
||||
var task = _taskManager.ScheduledTasks.FirstOrDefault(i => string.Equals(i.Id, id, StringComparison.Ordinal));
|
||||
|
||||
if (task == null)
|
||||
{
|
||||
throw new ResourceNotFoundException("Task not found");
|
||||
}
|
||||
|
||||
task.Triggers = request.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,226 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Controller;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Net;
|
||||
using MediaBrowser.Model.IO;
|
||||
using MediaBrowser.Model.Net;
|
||||
using MediaBrowser.Model.Services;
|
||||
using MediaBrowser.Model.System;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace MediaBrowser.Api.System
|
||||
{
|
||||
/// <summary>
|
||||
/// Class GetSystemInfo
|
||||
/// </summary>
|
||||
[Route("/System/Info", "GET", Summary = "Gets information about the server")]
|
||||
[Authenticated(EscapeParentalControl = true, AllowBeforeStartupWizard = true)]
|
||||
public class GetSystemInfo : IReturn<SystemInfo>
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
[Route("/System/Info/Public", "GET", Summary = "Gets public information about the server")]
|
||||
public class GetPublicSystemInfo : IReturn<PublicSystemInfo>
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
[Route("/System/Ping", "POST")]
|
||||
[Route("/System/Ping", "GET")]
|
||||
public class PingSystem : IReturnVoid
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Class RestartApplication
|
||||
/// </summary>
|
||||
[Route("/System/Restart", "POST", Summary = "Restarts the application, if needed")]
|
||||
[Authenticated(Roles = "Admin", AllowLocal = true)]
|
||||
public class RestartApplication
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This is currently not authenticated because the uninstaller needs to be able to shutdown the server.
|
||||
/// </summary>
|
||||
[Route("/System/Shutdown", "POST", Summary = "Shuts down the application")]
|
||||
[Authenticated(Roles = "Admin", AllowLocal = true)]
|
||||
public class ShutdownApplication
|
||||
{
|
||||
}
|
||||
|
||||
[Route("/System/Logs", "GET", Summary = "Gets a list of available server log files")]
|
||||
[Authenticated(Roles = "Admin")]
|
||||
public class GetServerLogs : IReturn<LogFile[]>
|
||||
{
|
||||
}
|
||||
|
||||
[Route("/System/Endpoint", "GET", Summary = "Gets information about the request endpoint")]
|
||||
[Authenticated]
|
||||
public class GetEndpointInfo : IReturn<EndPointInfo>
|
||||
{
|
||||
public string Endpoint { get; set; }
|
||||
}
|
||||
|
||||
[Route("/System/Logs/Log", "GET", Summary = "Gets a log file")]
|
||||
[Authenticated(Roles = "Admin")]
|
||||
public class GetLogFile
|
||||
{
|
||||
[ApiMember(Name = "Name", Description = "The log file name.", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
|
||||
public string Name { get; set; }
|
||||
}
|
||||
|
||||
[Route("/System/WakeOnLanInfo", "GET", Summary = "Gets wake on lan information")]
|
||||
[Authenticated]
|
||||
public class GetWakeOnLanInfo : IReturn<WakeOnLanInfo[]>
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Class SystemInfoService
|
||||
/// </summary>
|
||||
public class SystemService : BaseApiService
|
||||
{
|
||||
/// <summary>
|
||||
/// The _app host
|
||||
/// </summary>
|
||||
private readonly IServerApplicationHost _appHost;
|
||||
private readonly IApplicationPaths _appPaths;
|
||||
private readonly IFileSystem _fileSystem;
|
||||
|
||||
private readonly INetworkManager _network;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SystemService" /> class.
|
||||
/// </summary>
|
||||
/// <param name="appHost">The app host.</param>
|
||||
/// <param name="fileSystem">The file system.</param>
|
||||
/// <exception cref="ArgumentNullException">jsonSerializer</exception>
|
||||
public SystemService(
|
||||
ILogger<SystemService> logger,
|
||||
IServerConfigurationManager serverConfigurationManager,
|
||||
IHttpResultFactory httpResultFactory,
|
||||
IServerApplicationHost appHost,
|
||||
IFileSystem fileSystem,
|
||||
INetworkManager network)
|
||||
: base(logger, serverConfigurationManager, httpResultFactory)
|
||||
{
|
||||
_appPaths = serverConfigurationManager.ApplicationPaths;
|
||||
_appHost = appHost;
|
||||
_fileSystem = fileSystem;
|
||||
_network = network;
|
||||
}
|
||||
|
||||
public object Post(PingSystem request)
|
||||
{
|
||||
return _appHost.Name;
|
||||
}
|
||||
|
||||
public object Get(GetWakeOnLanInfo request)
|
||||
{
|
||||
var result = _appHost.GetWakeOnLanInfo();
|
||||
|
||||
return ToOptimizedResult(result);
|
||||
}
|
||||
|
||||
public object Get(GetServerLogs request)
|
||||
{
|
||||
IEnumerable<FileSystemMetadata> files;
|
||||
|
||||
try
|
||||
{
|
||||
files = _fileSystem.GetFiles(_appPaths.LogDirectoryPath, new[] { ".txt", ".log" }, true, false);
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
Logger.LogError(ex, "Error getting logs");
|
||||
files = Enumerable.Empty<FileSystemMetadata>();
|
||||
}
|
||||
|
||||
var result = files.Select(i => new LogFile
|
||||
{
|
||||
DateCreated = _fileSystem.GetCreationTimeUtc(i),
|
||||
DateModified = _fileSystem.GetLastWriteTimeUtc(i),
|
||||
Name = i.Name,
|
||||
Size = i.Length
|
||||
|
||||
}).OrderByDescending(i => i.DateModified)
|
||||
.ThenByDescending(i => i.DateCreated)
|
||||
.ThenBy(i => i.Name)
|
||||
.ToArray();
|
||||
|
||||
return ToOptimizedResult(result);
|
||||
}
|
||||
|
||||
public Task<object> Get(GetLogFile request)
|
||||
{
|
||||
var file = _fileSystem.GetFiles(_appPaths.LogDirectoryPath)
|
||||
.First(i => string.Equals(i.Name, request.Name, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
// For older files, assume fully static
|
||||
var fileShare = file.LastWriteTimeUtc < DateTime.UtcNow.AddHours(-1) ? FileShare.Read : FileShare.ReadWrite;
|
||||
|
||||
return ResultFactory.GetStaticFileResult(Request, file.FullName, fileShare);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the specified request.
|
||||
/// </summary>
|
||||
/// <param name="request">The request.</param>
|
||||
/// <returns>System.Object.</returns>
|
||||
public async Task<object> Get(GetSystemInfo request)
|
||||
{
|
||||
var result = await _appHost.GetSystemInfo(CancellationToken.None).ConfigureAwait(false);
|
||||
|
||||
return ToOptimizedResult(result);
|
||||
}
|
||||
|
||||
public async Task<object> Get(GetPublicSystemInfo request)
|
||||
{
|
||||
var result = await _appHost.GetPublicSystemInfo(CancellationToken.None).ConfigureAwait(false);
|
||||
|
||||
return ToOptimizedResult(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Posts the specified request.
|
||||
/// </summary>
|
||||
/// <param name="request">The request.</param>
|
||||
public void Post(RestartApplication request)
|
||||
{
|
||||
_appHost.Restart();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Posts the specified request.
|
||||
/// </summary>
|
||||
/// <param name="request">The request.</param>
|
||||
public void Post(ShutdownApplication request)
|
||||
{
|
||||
Task.Run(async () =>
|
||||
{
|
||||
await Task.Delay(100).ConfigureAwait(false);
|
||||
await _appHost.Shutdown().ConfigureAwait(false);
|
||||
});
|
||||
}
|
||||
|
||||
public object Get(GetEndpointInfo request)
|
||||
{
|
||||
return ToOptimizedResult(new EndPointInfo
|
||||
{
|
||||
IsLocal = Request.IsLocal,
|
||||
IsInNetwork = _network.IsInLocalNetwork(request.Endpoint ?? Request.RemoteIp)
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -1,498 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using MediaBrowser.Common.Extensions;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Dto;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Entities.TV;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Net;
|
||||
using MediaBrowser.Controller.TV;
|
||||
using MediaBrowser.Model.Dto;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Querying;
|
||||
using MediaBrowser.Model.Services;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace MediaBrowser.Api
|
||||
{
|
||||
/// <summary>
|
||||
/// Class GetNextUpEpisodes
|
||||
/// </summary>
|
||||
[Route("/Shows/NextUp", "GET", Summary = "Gets a list of next up episodes")]
|
||||
public class GetNextUpEpisodes : IReturn<QueryResult<BaseItemDto>>, IHasDtoOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the user id.
|
||||
/// </summary>
|
||||
/// <value>The user id.</value>
|
||||
[ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public Guid UserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Skips over a given number of items within the results. Use for paging.
|
||||
/// </summary>
|
||||
/// <value>The start index.</value>
|
||||
[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; }
|
||||
|
||||
/// <summary>
|
||||
/// The maximum number of items to return
|
||||
/// </summary>
|
||||
/// <value>The limit.</value>
|
||||
[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; }
|
||||
|
||||
/// <summary>
|
||||
/// Fields to return within the items, in addition to basic information
|
||||
/// </summary>
|
||||
/// <value>The fields.</value>
|
||||
[ApiMember(Name = "Fields", Description = "Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimeted. Options: Budget, Chapters, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines, TrailerUrls", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
|
||||
public string Fields { get; set; }
|
||||
|
||||
[ApiMember(Name = "SeriesId", Description = "Optional. Filter by series id", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string SeriesId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Specify this to localize the search to a specific item or folder. Omit to use the root.
|
||||
/// </summary>
|
||||
/// <value>The parent id.</value>
|
||||
[ApiMember(Name = "ParentId", Description = "Specify this to localize the search to a specific item or folder. Omit to use the root", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string ParentId { get; set; }
|
||||
|
||||
[ApiMember(Name = "EnableImages", Description = "Optional, include image information in output", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")]
|
||||
public bool? EnableImages { get; set; }
|
||||
|
||||
[ApiMember(Name = "ImageTypeLimit", Description = "Optional, the max number of images to return, per image type", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
|
||||
public int? ImageTypeLimit { get; set; }
|
||||
|
||||
[ApiMember(Name = "EnableImageTypes", Description = "Optional. The image types to include in the output.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string EnableImageTypes { get; set; }
|
||||
|
||||
[ApiMember(Name = "EnableUserData", Description = "Optional, include user data", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")]
|
||||
public bool? EnableUserData { get; set; }
|
||||
public bool EnableTotalRecordCount { get; set; }
|
||||
|
||||
public GetNextUpEpisodes()
|
||||
{
|
||||
EnableTotalRecordCount = true;
|
||||
}
|
||||
}
|
||||
|
||||
[Route("/Shows/Upcoming", "GET", Summary = "Gets a list of upcoming episodes")]
|
||||
public class GetUpcomingEpisodes : IReturn<QueryResult<BaseItemDto>>, IHasDtoOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the user id.
|
||||
/// </summary>
|
||||
/// <value>The user id.</value>
|
||||
[ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public Guid UserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Skips over a given number of items within the results. Use for paging.
|
||||
/// </summary>
|
||||
/// <value>The start index.</value>
|
||||
[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; }
|
||||
|
||||
/// <summary>
|
||||
/// The maximum number of items to return
|
||||
/// </summary>
|
||||
/// <value>The limit.</value>
|
||||
[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; }
|
||||
|
||||
/// <summary>
|
||||
/// Fields to return within the items, in addition to basic information
|
||||
/// </summary>
|
||||
/// <value>The fields.</value>
|
||||
[ApiMember(Name = "Fields", Description = "Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimeted. Options: Budget, Chapters, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines, TrailerUrls", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
|
||||
public string Fields { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Specify this to localize the search to a specific item or folder. Omit to use the root.
|
||||
/// </summary>
|
||||
/// <value>The parent id.</value>
|
||||
[ApiMember(Name = "ParentId", Description = "Specify this to localize the search to a specific item or folder. Omit to use the root", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string ParentId { get; set; }
|
||||
|
||||
[ApiMember(Name = "EnableImages", Description = "Optional, include image information in output", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")]
|
||||
public bool? EnableImages { get; set; }
|
||||
|
||||
[ApiMember(Name = "ImageTypeLimit", Description = "Optional, the max number of images to return, per image type", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
|
||||
public int? ImageTypeLimit { get; set; }
|
||||
|
||||
[ApiMember(Name = "EnableImageTypes", Description = "Optional. The image types to include in the output.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string EnableImageTypes { get; set; }
|
||||
|
||||
[ApiMember(Name = "EnableUserData", Description = "Optional, include user data", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")]
|
||||
public bool? EnableUserData { get; set; }
|
||||
}
|
||||
|
||||
[Route("/Shows/{Id}/Episodes", "GET", Summary = "Gets episodes for a tv season")]
|
||||
public class GetEpisodes : IReturn<QueryResult<BaseItemDto>>, IHasItemFields, IHasDtoOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the user id.
|
||||
/// </summary>
|
||||
/// <value>The user id.</value>
|
||||
[ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public Guid UserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Fields to return within the items, in addition to basic information
|
||||
/// </summary>
|
||||
/// <value>The fields.</value>
|
||||
[ApiMember(Name = "Fields", Description = "Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimeted. Options: Budget, Chapters, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines, TrailerUrls", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
|
||||
public string Fields { get; set; }
|
||||
|
||||
[ApiMember(Name = "Id", Description = "The series id", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string Id { get; set; }
|
||||
|
||||
[ApiMember(Name = "Season", Description = "Optional filter by season number.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public int? Season { get; set; }
|
||||
|
||||
[ApiMember(Name = "SeasonId", Description = "Optional. Filter by season id", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string SeasonId { get; set; }
|
||||
|
||||
[ApiMember(Name = "IsMissing", Description = "Optional filter by items that are missing episodes or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
|
||||
public bool? IsMissing { get; set; }
|
||||
|
||||
[ApiMember(Name = "AdjacentTo", Description = "Optional. Return items that are siblings of a supplied item.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string AdjacentTo { get; set; }
|
||||
|
||||
[ApiMember(Name = "StartItemId", Description = "Optional. Skip through the list until a given item is found.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string StartItemId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Skips over a given number of items within the results. Use for paging.
|
||||
/// </summary>
|
||||
/// <value>The start index.</value>
|
||||
[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; }
|
||||
|
||||
/// <summary>
|
||||
/// The maximum number of items to return
|
||||
/// </summary>
|
||||
/// <value>The limit.</value>
|
||||
[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; }
|
||||
|
||||
[ApiMember(Name = "EnableImages", Description = "Optional, include image information in output", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")]
|
||||
public bool? EnableImages { get; set; }
|
||||
|
||||
[ApiMember(Name = "ImageTypeLimit", Description = "Optional, the max number of images to return, per image type", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
|
||||
public int? ImageTypeLimit { get; set; }
|
||||
|
||||
[ApiMember(Name = "EnableImageTypes", Description = "Optional. The image types to include in the output.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string EnableImageTypes { get; set; }
|
||||
|
||||
[ApiMember(Name = "EnableUserData", Description = "Optional, include user data", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")]
|
||||
public bool? EnableUserData { get; set; }
|
||||
|
||||
[ApiMember(Name = "SortBy", Description = "Optional. Specify one or more sort orders, comma delimeted. Options: Album, AlbumArtist, Artist, Budget, CommunityRating, CriticRating, DateCreated, DatePlayed, PlayCount, PremiereDate, ProductionYear, SortName, Random, Revenue, Runtime", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
|
||||
public string SortBy { get; set; }
|
||||
|
||||
[ApiMember(Name = "SortOrder", Description = "Sort Order - Ascending,Descending", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public SortOrder? SortOrder { get; set; }
|
||||
}
|
||||
|
||||
[Route("/Shows/{Id}/Seasons", "GET", Summary = "Gets seasons for a tv series")]
|
||||
public class GetSeasons : IReturn<QueryResult<BaseItemDto>>, IHasItemFields, IHasDtoOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the user id.
|
||||
/// </summary>
|
||||
/// <value>The user id.</value>
|
||||
[ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public Guid UserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Fields to return within the items, in addition to basic information
|
||||
/// </summary>
|
||||
/// <value>The fields.</value>
|
||||
[ApiMember(Name = "Fields", Description = "Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimeted. Options: Budget, Chapters, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines, TrailerUrls", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
|
||||
public string Fields { get; set; }
|
||||
|
||||
[ApiMember(Name = "Id", Description = "The series id", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string Id { get; set; }
|
||||
|
||||
[ApiMember(Name = "IsSpecialSeason", Description = "Optional. Filter by special season.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
|
||||
public bool? IsSpecialSeason { get; set; }
|
||||
|
||||
[ApiMember(Name = "IsMissing", Description = "Optional filter by items that are missing episodes or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
|
||||
public bool? IsMissing { get; set; }
|
||||
|
||||
[ApiMember(Name = "AdjacentTo", Description = "Optional. Return items that are siblings of a supplied item.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string AdjacentTo { get; set; }
|
||||
|
||||
[ApiMember(Name = "EnableImages", Description = "Optional, include image information in output", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")]
|
||||
public bool? EnableImages { get; set; }
|
||||
|
||||
[ApiMember(Name = "ImageTypeLimit", Description = "Optional, the max number of images to return, per image type", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
|
||||
public int? ImageTypeLimit { get; set; }
|
||||
|
||||
[ApiMember(Name = "EnableImageTypes", Description = "Optional. The image types to include in the output.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string EnableImageTypes { get; set; }
|
||||
|
||||
[ApiMember(Name = "EnableUserData", Description = "Optional, include user data", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")]
|
||||
public bool? EnableUserData { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Class TvShowsService
|
||||
/// </summary>
|
||||
[Authenticated]
|
||||
public class TvShowsService : BaseApiService
|
||||
{
|
||||
/// <summary>
|
||||
/// The _user manager
|
||||
/// </summary>
|
||||
private readonly IUserManager _userManager;
|
||||
|
||||
/// <summary>
|
||||
/// The _library manager
|
||||
/// </summary>
|
||||
private readonly ILibraryManager _libraryManager;
|
||||
|
||||
private readonly IDtoService _dtoService;
|
||||
private readonly ITVSeriesManager _tvSeriesManager;
|
||||
private readonly IAuthorizationContext _authContext;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TvShowsService" /> class.
|
||||
/// </summary>
|
||||
/// <param name="userManager">The user manager.</param>
|
||||
/// <param name="userDataManager">The user data repository.</param>
|
||||
/// <param name="libraryManager">The library manager.</param>
|
||||
public TvShowsService(
|
||||
ILogger<TvShowsService> logger,
|
||||
IServerConfigurationManager serverConfigurationManager,
|
||||
IHttpResultFactory httpResultFactory,
|
||||
IUserManager userManager,
|
||||
ILibraryManager libraryManager,
|
||||
IDtoService dtoService,
|
||||
ITVSeriesManager tvSeriesManager,
|
||||
IAuthorizationContext authContext)
|
||||
: base(logger, serverConfigurationManager, httpResultFactory)
|
||||
{
|
||||
_userManager = userManager;
|
||||
_libraryManager = libraryManager;
|
||||
_dtoService = dtoService;
|
||||
_tvSeriesManager = tvSeriesManager;
|
||||
_authContext = authContext;
|
||||
}
|
||||
|
||||
public object Get(GetUpcomingEpisodes request)
|
||||
{
|
||||
var user = _userManager.GetUserById(request.UserId);
|
||||
|
||||
var minPremiereDate = DateTime.Now.Date.ToUniversalTime().AddDays(-1);
|
||||
|
||||
var parentIdGuid = string.IsNullOrWhiteSpace(request.ParentId) ? Guid.Empty : new Guid(request.ParentId);
|
||||
|
||||
var options = GetDtoOptions(_authContext, request);
|
||||
|
||||
var itemsResult = _libraryManager.GetItemList(new InternalItemsQuery(user)
|
||||
{
|
||||
IncludeItemTypes = new[] { typeof(Episode).Name },
|
||||
OrderBy = new[] { ItemSortBy.PremiereDate, ItemSortBy.SortName }.Select(i => new ValueTuple<string, SortOrder>(i, SortOrder.Ascending)).ToArray(),
|
||||
MinPremiereDate = minPremiereDate,
|
||||
StartIndex = request.StartIndex,
|
||||
Limit = request.Limit,
|
||||
ParentId = parentIdGuid,
|
||||
Recursive = true,
|
||||
DtoOptions = options
|
||||
|
||||
});
|
||||
|
||||
var returnItems = _dtoService.GetBaseItemDtos(itemsResult, options, user);
|
||||
|
||||
var result = new QueryResult<BaseItemDto>
|
||||
{
|
||||
TotalRecordCount = itemsResult.Count,
|
||||
Items = returnItems
|
||||
};
|
||||
|
||||
return ToOptimizedResult(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the specified request.
|
||||
/// </summary>
|
||||
/// <param name="request">The request.</param>
|
||||
/// <returns>System.Object.</returns>
|
||||
public object Get(GetNextUpEpisodes request)
|
||||
{
|
||||
var options = GetDtoOptions(_authContext, request);
|
||||
|
||||
var result = _tvSeriesManager.GetNextUp(new NextUpQuery
|
||||
{
|
||||
Limit = request.Limit,
|
||||
ParentId = request.ParentId,
|
||||
SeriesId = request.SeriesId,
|
||||
StartIndex = request.StartIndex,
|
||||
UserId = request.UserId,
|
||||
EnableTotalRecordCount = request.EnableTotalRecordCount
|
||||
}, options);
|
||||
|
||||
var user = _userManager.GetUserById(request.UserId);
|
||||
|
||||
var returnItems = _dtoService.GetBaseItemDtos(result.Items, options, user);
|
||||
|
||||
return ToOptimizedResult(new QueryResult<BaseItemDto>
|
||||
{
|
||||
TotalRecordCount = result.TotalRecordCount,
|
||||
Items = returnItems
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Applies the paging.
|
||||
/// </summary>
|
||||
/// <param name="items">The items.</param>
|
||||
/// <param name="startIndex">The start index.</param>
|
||||
/// <param name="limit">The limit.</param>
|
||||
/// <returns>IEnumerable{BaseItem}.</returns>
|
||||
private IEnumerable<BaseItem> ApplyPaging(IEnumerable<BaseItem> items, int? startIndex, int? limit)
|
||||
{
|
||||
// Start at
|
||||
if (startIndex.HasValue)
|
||||
{
|
||||
items = items.Skip(startIndex.Value);
|
||||
}
|
||||
|
||||
// Return limit
|
||||
if (limit.HasValue)
|
||||
{
|
||||
items = items.Take(limit.Value);
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
public object Get(GetSeasons request)
|
||||
{
|
||||
var user = _userManager.GetUserById(request.UserId);
|
||||
|
||||
var series = GetSeries(request.Id);
|
||||
|
||||
if (series == null)
|
||||
{
|
||||
throw new ResourceNotFoundException("Series not found");
|
||||
}
|
||||
|
||||
var seasons = series.GetItemList(new InternalItemsQuery(user)
|
||||
{
|
||||
IsMissing = request.IsMissing,
|
||||
IsSpecialSeason = request.IsSpecialSeason,
|
||||
AdjacentTo = request.AdjacentTo
|
||||
|
||||
});
|
||||
|
||||
var dtoOptions = GetDtoOptions(_authContext, request);
|
||||
|
||||
var returnItems = _dtoService.GetBaseItemDtos(seasons, dtoOptions, user);
|
||||
|
||||
return new QueryResult<BaseItemDto>
|
||||
{
|
||||
TotalRecordCount = returnItems.Count,
|
||||
Items = returnItems
|
||||
};
|
||||
}
|
||||
|
||||
private Series GetSeries(string seriesId)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(seriesId))
|
||||
{
|
||||
return _libraryManager.GetItemById(seriesId) as Series;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public object Get(GetEpisodes request)
|
||||
{
|
||||
var user = _userManager.GetUserById(request.UserId);
|
||||
|
||||
List<BaseItem> episodes;
|
||||
|
||||
var dtoOptions = GetDtoOptions(_authContext, request);
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(request.SeasonId))
|
||||
{
|
||||
if (!(_libraryManager.GetItemById(new Guid(request.SeasonId)) is Season season))
|
||||
{
|
||||
throw new ResourceNotFoundException("No season exists with Id " + request.SeasonId);
|
||||
}
|
||||
|
||||
episodes = season.GetEpisodes(user, dtoOptions);
|
||||
}
|
||||
else if (request.Season.HasValue)
|
||||
{
|
||||
var series = GetSeries(request.Id);
|
||||
|
||||
if (series == null)
|
||||
{
|
||||
throw new ResourceNotFoundException("Series not found");
|
||||
}
|
||||
|
||||
var season = series.GetSeasons(user, dtoOptions).FirstOrDefault(i => i.IndexNumber == request.Season.Value);
|
||||
|
||||
episodes = season == null ? new List<BaseItem>() : ((Season)season).GetEpisodes(user, dtoOptions);
|
||||
}
|
||||
else
|
||||
{
|
||||
var series = GetSeries(request.Id);
|
||||
|
||||
if (series == null)
|
||||
{
|
||||
throw new ResourceNotFoundException("Series not found");
|
||||
}
|
||||
|
||||
episodes = series.GetEpisodes(user, dtoOptions).ToList();
|
||||
}
|
||||
|
||||
// Filter after the fact in case the ui doesn't want them
|
||||
if (request.IsMissing.HasValue)
|
||||
{
|
||||
var val = request.IsMissing.Value;
|
||||
episodes = episodes.Where(i => ((Episode)i).IsMissingEpisode == val).ToList();
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(request.StartItemId))
|
||||
{
|
||||
episodes = episodes.SkipWhile(i => !string.Equals(i.Id.ToString("N", CultureInfo.InvariantCulture), request.StartItemId, StringComparison.OrdinalIgnoreCase)).ToList();
|
||||
}
|
||||
|
||||
// This must be the last filter
|
||||
if (!string.IsNullOrEmpty(request.AdjacentTo))
|
||||
{
|
||||
episodes = UserViewBuilder.FilterForAdjacency(episodes, request.AdjacentTo).ToList();
|
||||
}
|
||||
|
||||
if (string.Equals(request.SortBy, ItemSortBy.Random, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
episodes.Shuffle();
|
||||
}
|
||||
|
||||
var returnItems = episodes;
|
||||
|
||||
if (request.StartIndex.HasValue || request.Limit.HasValue)
|
||||
{
|
||||
returnItems = ApplyPaging(episodes, request.StartIndex, request.Limit).ToList();
|
||||
}
|
||||
|
||||
var dtos = _dtoService.GetBaseItemDtos(returnItems, dtoOptions, user);
|
||||
|
||||
return new QueryResult<BaseItemDto>
|
||||
{
|
||||
TotalRecordCount = episodes.Count,
|
||||
Items = dtos
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
@ -1,143 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
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.Querying;
|
||||
using MediaBrowser.Model.Services;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace MediaBrowser.Api.UserLibrary
|
||||
{
|
||||
/// <summary>
|
||||
/// Class GetArtists
|
||||
/// </summary>
|
||||
[Route("/Artists", "GET", Summary = "Gets all artists from a given item, folder, or the entire library")]
|
||||
public class GetArtists : GetItemsByName
|
||||
{
|
||||
}
|
||||
|
||||
[Route("/Artists/AlbumArtists", "GET", Summary = "Gets all album artists from a given item, folder, or the entire library")]
|
||||
public class GetAlbumArtists : GetItemsByName
|
||||
{
|
||||
}
|
||||
|
||||
[Route("/Artists/{Name}", "GET", Summary = "Gets an artist, by name")]
|
||||
public class GetArtist : IReturn<BaseItemDto>
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the name.
|
||||
/// </summary>
|
||||
/// <value>The name.</value>
|
||||
[ApiMember(Name = "Name", Description = "The artist name", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the user id.
|
||||
/// </summary>
|
||||
/// <value>The user id.</value>
|
||||
[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; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Class ArtistsService
|
||||
/// </summary>
|
||||
[Authenticated]
|
||||
public class ArtistsService : BaseItemsByNameService<MusicArtist>
|
||||
{
|
||||
public ArtistsService(
|
||||
ILogger<ArtistsService> logger,
|
||||
IServerConfigurationManager serverConfigurationManager,
|
||||
IHttpResultFactory httpResultFactory,
|
||||
IUserManager userManager,
|
||||
ILibraryManager libraryManager,
|
||||
IUserDataManager userDataRepository,
|
||||
IDtoService dtoService,
|
||||
IAuthorizationContext authorizationContext)
|
||||
: base(
|
||||
logger,
|
||||
serverConfigurationManager,
|
||||
httpResultFactory,
|
||||
userManager,
|
||||
libraryManager,
|
||||
userDataRepository,
|
||||
dtoService,
|
||||
authorizationContext)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the specified request.
|
||||
/// </summary>
|
||||
/// <param name="request">The request.</param>
|
||||
/// <returns>System.Object.</returns>
|
||||
public object Get(GetArtist request)
|
||||
{
|
||||
return GetItem(request);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the item.
|
||||
/// </summary>
|
||||
/// <param name="request">The request.</param>
|
||||
/// <returns>Task{BaseItemDto}.</returns>
|
||||
private BaseItemDto GetItem(GetArtist request)
|
||||
{
|
||||
var dtoOptions = GetDtoOptions(AuthorizationContext, request);
|
||||
|
||||
var item = GetArtist(request.Name, LibraryManager, dtoOptions);
|
||||
|
||||
if (!request.UserId.Equals(Guid.Empty))
|
||||
{
|
||||
var user = UserManager.GetUserById(request.UserId);
|
||||
|
||||
return DtoService.GetBaseItemDto(item, dtoOptions, user);
|
||||
}
|
||||
|
||||
return DtoService.GetBaseItemDto(item, dtoOptions);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the specified request.
|
||||
/// </summary>
|
||||
/// <param name="request">The request.</param>
|
||||
/// <returns>System.Object.</returns>
|
||||
public object Get(GetArtists request)
|
||||
{
|
||||
return GetResultSlim(request);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the specified request.
|
||||
/// </summary>
|
||||
/// <param name="request">The request.</param>
|
||||
/// <returns>System.Object.</returns>
|
||||
public object Get(GetAlbumArtists request)
|
||||
{
|
||||
var result = GetResultSlim(request);
|
||||
|
||||
return ToOptimizedResult(result);
|
||||
}
|
||||
|
||||
protected override QueryResult<(BaseItem, ItemCounts)> GetItems(GetItemsByName request, InternalItemsQuery query)
|
||||
{
|
||||
return request is GetAlbumArtists ? LibraryManager.GetAlbumArtists(query) : LibraryManager.GetArtists(query);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets all items.
|
||||
/// </summary>
|
||||
/// <param name="request">The request.</param>
|
||||
/// <param name="items">The items.</param>
|
||||
/// <returns>IEnumerable{Tuple{System.StringFunc{System.Int32}}}.</returns>
|
||||
protected override IEnumerable<BaseItem> GetAllItems(GetItemsByName request, IList<BaseItem> items)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,456 +0,0 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Threading.Tasks;
|
||||
using Jellyfin.Data.Entities;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Net;
|
||||
using MediaBrowser.Controller.Session;
|
||||
using MediaBrowser.Model.Dto;
|
||||
using MediaBrowser.Model.Services;
|
||||
using MediaBrowser.Model.Session;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace MediaBrowser.Api.UserLibrary
|
||||
{
|
||||
/// <summary>
|
||||
/// Class MarkPlayedItem
|
||||
/// </summary>
|
||||
[Route("/Users/{UserId}/PlayedItems/{Id}", "POST", Summary = "Marks an item as played")]
|
||||
public class MarkPlayedItem : IReturn<UserItemDataDto>
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the user id.
|
||||
/// </summary>
|
||||
/// <value>The user id.</value>
|
||||
[ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
|
||||
public string UserId { get; set; }
|
||||
|
||||
[ApiMember(Name = "DatePlayed", Description = "The date the item was played (if any). Format = yyyyMMddHHmmss", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")]
|
||||
public string DatePlayed { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the id.
|
||||
/// </summary>
|
||||
/// <value>The id.</value>
|
||||
[ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
|
||||
public string Id { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Class MarkUnplayedItem
|
||||
/// </summary>
|
||||
[Route("/Users/{UserId}/PlayedItems/{Id}", "DELETE", Summary = "Marks an item as unplayed")]
|
||||
public class MarkUnplayedItem : IReturn<UserItemDataDto>
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the user id.
|
||||
/// </summary>
|
||||
/// <value>The user id.</value>
|
||||
[ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")]
|
||||
public string UserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the id.
|
||||
/// </summary>
|
||||
/// <value>The id.</value>
|
||||
[ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")]
|
||||
public string Id { get; set; }
|
||||
}
|
||||
|
||||
[Route("/Sessions/Playing", "POST", Summary = "Reports playback has started within a session")]
|
||||
public class ReportPlaybackStart : PlaybackStartInfo, IReturnVoid
|
||||
{
|
||||
}
|
||||
|
||||
[Route("/Sessions/Playing/Progress", "POST", Summary = "Reports playback progress within a session")]
|
||||
public class ReportPlaybackProgress : PlaybackProgressInfo, IReturnVoid
|
||||
{
|
||||
}
|
||||
|
||||
[Route("/Sessions/Playing/Ping", "POST", Summary = "Pings a playback session")]
|
||||
public class PingPlaybackSession : IReturnVoid
|
||||
{
|
||||
[ApiMember(Name = "PlaySessionId", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")]
|
||||
public string PlaySessionId { get; set; }
|
||||
}
|
||||
|
||||
[Route("/Sessions/Playing/Stopped", "POST", Summary = "Reports playback has stopped within a session")]
|
||||
public class ReportPlaybackStopped : PlaybackStopInfo, IReturnVoid
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Class OnPlaybackStart
|
||||
/// </summary>
|
||||
[Route("/Users/{UserId}/PlayingItems/{Id}", "POST", Summary = "Reports that a user has begun playing an item")]
|
||||
public class OnPlaybackStart : IReturnVoid
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the user id.
|
||||
/// </summary>
|
||||
/// <value>The user id.</value>
|
||||
[ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
|
||||
public string UserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the id.
|
||||
/// </summary>
|
||||
/// <value>The id.</value>
|
||||
[ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
|
||||
public string Id { get; set; }
|
||||
|
||||
[ApiMember(Name = "MediaSourceId", Description = "The id of the MediaSource", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST")]
|
||||
public string MediaSourceId { get; set; }
|
||||
|
||||
[ApiMember(Name = "CanSeek", Description = "Indicates if the client can seek", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "POST")]
|
||||
public bool CanSeek { get; set; }
|
||||
|
||||
[ApiMember(Name = "AudioStreamIndex", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "POST")]
|
||||
public int? AudioStreamIndex { get; set; }
|
||||
|
||||
[ApiMember(Name = "SubtitleStreamIndex", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "POST")]
|
||||
public int? SubtitleStreamIndex { get; set; }
|
||||
|
||||
[ApiMember(Name = "PlayMethod", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")]
|
||||
public PlayMethod PlayMethod { get; set; }
|
||||
|
||||
[ApiMember(Name = "LiveStreamId", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")]
|
||||
public string LiveStreamId { get; set; }
|
||||
|
||||
[ApiMember(Name = "PlaySessionId", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")]
|
||||
public string PlaySessionId { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Class OnPlaybackProgress
|
||||
/// </summary>
|
||||
[Route("/Users/{UserId}/PlayingItems/{Id}/Progress", "POST", Summary = "Reports a user's playback progress")]
|
||||
public class OnPlaybackProgress : IReturnVoid
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the user id.
|
||||
/// </summary>
|
||||
/// <value>The user id.</value>
|
||||
[ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
|
||||
public string UserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the id.
|
||||
/// </summary>
|
||||
/// <value>The id.</value>
|
||||
[ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
|
||||
public string Id { get; set; }
|
||||
|
||||
[ApiMember(Name = "MediaSourceId", Description = "The id of the MediaSource", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST")]
|
||||
public string MediaSourceId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the position ticks.
|
||||
/// </summary>
|
||||
/// <value>The position ticks.</value>
|
||||
[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; }
|
||||
|
||||
[ApiMember(Name = "IsPaused", Description = "Indicates if the player is paused.", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "POST")]
|
||||
public bool IsPaused { get; set; }
|
||||
|
||||
[ApiMember(Name = "IsMuted", Description = "Indicates if the player is muted.", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "POST")]
|
||||
public bool IsMuted { get; set; }
|
||||
|
||||
[ApiMember(Name = "AudioStreamIndex", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "POST")]
|
||||
public int? AudioStreamIndex { get; set; }
|
||||
|
||||
[ApiMember(Name = "SubtitleStreamIndex", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "POST")]
|
||||
public int? SubtitleStreamIndex { get; set; }
|
||||
|
||||
[ApiMember(Name = "VolumeLevel", Description = "Scale of 0-100", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "POST")]
|
||||
public int? VolumeLevel { get; set; }
|
||||
|
||||
[ApiMember(Name = "PlayMethod", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")]
|
||||
public PlayMethod PlayMethod { get; set; }
|
||||
|
||||
[ApiMember(Name = "LiveStreamId", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")]
|
||||
public string LiveStreamId { get; set; }
|
||||
|
||||
[ApiMember(Name = "PlaySessionId", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")]
|
||||
public string PlaySessionId { get; set; }
|
||||
|
||||
[ApiMember(Name = "RepeatMode", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")]
|
||||
public RepeatMode RepeatMode { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Class OnPlaybackStopped
|
||||
/// </summary>
|
||||
[Route("/Users/{UserId}/PlayingItems/{Id}", "DELETE", Summary = "Reports that a user has stopped playing an item")]
|
||||
public class OnPlaybackStopped : IReturnVoid
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the user id.
|
||||
/// </summary>
|
||||
/// <value>The user id.</value>
|
||||
[ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")]
|
||||
public string UserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the id.
|
||||
/// </summary>
|
||||
/// <value>The id.</value>
|
||||
[ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")]
|
||||
public string Id { get; set; }
|
||||
|
||||
[ApiMember(Name = "MediaSourceId", Description = "The id of the MediaSource", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "DELETE")]
|
||||
public string MediaSourceId { get; set; }
|
||||
|
||||
[ApiMember(Name = "NextMediaType", Description = "The next media type that will play", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "DELETE")]
|
||||
public string NextMediaType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the position ticks.
|
||||
/// </summary>
|
||||
/// <value>The position ticks.</value>
|
||||
[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; }
|
||||
|
||||
[ApiMember(Name = "LiveStreamId", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")]
|
||||
public string LiveStreamId { get; set; }
|
||||
|
||||
[ApiMember(Name = "PlaySessionId", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")]
|
||||
public string PlaySessionId { get; set; }
|
||||
}
|
||||
|
||||
[Authenticated]
|
||||
public class PlaystateService : BaseApiService
|
||||
{
|
||||
private readonly IUserManager _userManager;
|
||||
private readonly IUserDataManager _userDataRepository;
|
||||
private readonly ILibraryManager _libraryManager;
|
||||
private readonly ISessionManager _sessionManager;
|
||||
private readonly ISessionContext _sessionContext;
|
||||
private readonly IAuthorizationContext _authContext;
|
||||
|
||||
public PlaystateService(
|
||||
ILogger<PlaystateService> logger,
|
||||
IServerConfigurationManager serverConfigurationManager,
|
||||
IHttpResultFactory httpResultFactory,
|
||||
IUserManager userManager,
|
||||
IUserDataManager userDataRepository,
|
||||
ILibraryManager libraryManager,
|
||||
ISessionManager sessionManager,
|
||||
ISessionContext sessionContext,
|
||||
IAuthorizationContext authContext)
|
||||
: base(logger, serverConfigurationManager, httpResultFactory)
|
||||
{
|
||||
_userManager = userManager;
|
||||
_userDataRepository = userDataRepository;
|
||||
_libraryManager = libraryManager;
|
||||
_sessionManager = sessionManager;
|
||||
_sessionContext = sessionContext;
|
||||
_authContext = authContext;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Posts the specified request.
|
||||
/// </summary>
|
||||
/// <param name="request">The request.</param>
|
||||
public object Post(MarkPlayedItem request)
|
||||
{
|
||||
var result = MarkPlayed(request);
|
||||
|
||||
return ToOptimizedResult(result);
|
||||
}
|
||||
|
||||
private UserItemDataDto MarkPlayed(MarkPlayedItem request)
|
||||
{
|
||||
var user = _userManager.GetUserById(Guid.Parse(request.UserId));
|
||||
|
||||
DateTime? datePlayed = null;
|
||||
|
||||
if (!string.IsNullOrEmpty(request.DatePlayed))
|
||||
{
|
||||
datePlayed = DateTime.ParseExact(request.DatePlayed, "yyyyMMddHHmmss", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal);
|
||||
}
|
||||
|
||||
var session = GetSession(_sessionContext);
|
||||
|
||||
var dto = UpdatePlayedStatus(user, request.Id, true, datePlayed);
|
||||
|
||||
foreach (var additionalUserInfo in session.AdditionalUsers)
|
||||
{
|
||||
var additionalUser = _userManager.GetUserById(additionalUserInfo.UserId);
|
||||
|
||||
UpdatePlayedStatus(additionalUser, request.Id, true, datePlayed);
|
||||
}
|
||||
|
||||
return dto;
|
||||
}
|
||||
|
||||
private PlayMethod ValidatePlayMethod(PlayMethod method, string playSessionId)
|
||||
{
|
||||
if (method == PlayMethod.Transcode)
|
||||
{
|
||||
var job = string.IsNullOrWhiteSpace(playSessionId) ? null : ApiEntryPoint.Instance.GetTranscodingJob(playSessionId);
|
||||
if (job == null)
|
||||
{
|
||||
return PlayMethod.DirectPlay;
|
||||
}
|
||||
}
|
||||
|
||||
return method;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Posts the specified request.
|
||||
/// </summary>
|
||||
/// <param name="request">The request.</param>
|
||||
public void Post(OnPlaybackStart request)
|
||||
{
|
||||
Post(new ReportPlaybackStart
|
||||
{
|
||||
CanSeek = request.CanSeek,
|
||||
ItemId = new Guid(request.Id),
|
||||
MediaSourceId = request.MediaSourceId,
|
||||
AudioStreamIndex = request.AudioStreamIndex,
|
||||
SubtitleStreamIndex = request.SubtitleStreamIndex,
|
||||
PlayMethod = request.PlayMethod,
|
||||
PlaySessionId = request.PlaySessionId,
|
||||
LiveStreamId = request.LiveStreamId
|
||||
});
|
||||
}
|
||||
|
||||
public void Post(ReportPlaybackStart request)
|
||||
{
|
||||
request.PlayMethod = ValidatePlayMethod(request.PlayMethod, request.PlaySessionId);
|
||||
|
||||
request.SessionId = GetSession(_sessionContext).Id;
|
||||
|
||||
var task = _sessionManager.OnPlaybackStart(request);
|
||||
|
||||
Task.WaitAll(task);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Posts the specified request.
|
||||
/// </summary>
|
||||
/// <param name="request">The request.</param>
|
||||
public void Post(OnPlaybackProgress request)
|
||||
{
|
||||
Post(new ReportPlaybackProgress
|
||||
{
|
||||
ItemId = new Guid(request.Id),
|
||||
PositionTicks = request.PositionTicks,
|
||||
IsMuted = request.IsMuted,
|
||||
IsPaused = request.IsPaused,
|
||||
MediaSourceId = request.MediaSourceId,
|
||||
AudioStreamIndex = request.AudioStreamIndex,
|
||||
SubtitleStreamIndex = request.SubtitleStreamIndex,
|
||||
VolumeLevel = request.VolumeLevel,
|
||||
PlayMethod = request.PlayMethod,
|
||||
PlaySessionId = request.PlaySessionId,
|
||||
LiveStreamId = request.LiveStreamId,
|
||||
RepeatMode = request.RepeatMode
|
||||
});
|
||||
}
|
||||
|
||||
public void Post(ReportPlaybackProgress request)
|
||||
{
|
||||
request.PlayMethod = ValidatePlayMethod(request.PlayMethod, request.PlaySessionId);
|
||||
|
||||
request.SessionId = GetSession(_sessionContext).Id;
|
||||
|
||||
var task = _sessionManager.OnPlaybackProgress(request);
|
||||
|
||||
Task.WaitAll(task);
|
||||
}
|
||||
|
||||
public void Post(PingPlaybackSession request)
|
||||
{
|
||||
ApiEntryPoint.Instance.PingTranscodingJob(request.PlaySessionId, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Posts the specified request.
|
||||
/// </summary>
|
||||
/// <param name="request">The request.</param>
|
||||
public Task Delete(OnPlaybackStopped request)
|
||||
{
|
||||
return Post(new ReportPlaybackStopped
|
||||
{
|
||||
ItemId = new Guid(request.Id),
|
||||
PositionTicks = request.PositionTicks,
|
||||
MediaSourceId = request.MediaSourceId,
|
||||
PlaySessionId = request.PlaySessionId,
|
||||
LiveStreamId = request.LiveStreamId,
|
||||
NextMediaType = request.NextMediaType
|
||||
});
|
||||
}
|
||||
|
||||
public async Task Post(ReportPlaybackStopped request)
|
||||
{
|
||||
Logger.LogDebug("ReportPlaybackStopped PlaySessionId: {0}", request.PlaySessionId ?? string.Empty);
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(request.PlaySessionId))
|
||||
{
|
||||
await ApiEntryPoint.Instance.KillTranscodingJobs(_authContext.GetAuthorizationInfo(Request).DeviceId, request.PlaySessionId, s => true);
|
||||
}
|
||||
|
||||
request.SessionId = GetSession(_sessionContext).Id;
|
||||
|
||||
await _sessionManager.OnPlaybackStopped(request);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes the specified request.
|
||||
/// </summary>
|
||||
/// <param name="request">The request.</param>
|
||||
public object Delete(MarkUnplayedItem request)
|
||||
{
|
||||
var task = MarkUnplayed(request);
|
||||
|
||||
return ToOptimizedResult(task);
|
||||
}
|
||||
|
||||
private UserItemDataDto MarkUnplayed(MarkUnplayedItem request)
|
||||
{
|
||||
var user = _userManager.GetUserById(Guid.Parse(request.UserId));
|
||||
|
||||
var session = GetSession(_sessionContext);
|
||||
|
||||
var dto = UpdatePlayedStatus(user, request.Id, false, null);
|
||||
|
||||
foreach (var additionalUserInfo in session.AdditionalUsers)
|
||||
{
|
||||
var additionalUser = _userManager.GetUserById(additionalUserInfo.UserId);
|
||||
|
||||
UpdatePlayedStatus(additionalUser, request.Id, false, null);
|
||||
}
|
||||
|
||||
return dto;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the played status.
|
||||
/// </summary>
|
||||
/// <param name="user">The user.</param>
|
||||
/// <param name="itemId">The item id.</param>
|
||||
/// <param name="wasPlayed">if set to <c>true</c> [was played].</param>
|
||||
/// <param name="datePlayed">The date played.</param>
|
||||
/// <returns>Task.</returns>
|
||||
private UserItemDataDto UpdatePlayedStatus(User user, string itemId, bool wasPlayed, DateTime? datePlayed)
|
||||
{
|
||||
var item = _libraryManager.GetItemById(itemId);
|
||||
|
||||
if (wasPlayed)
|
||||
{
|
||||
item.MarkPlayed(user, datePlayed, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
item.MarkUnplayed(user);
|
||||
}
|
||||
|
||||
return _userDataRepository.GetUserDataDto(item, user);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,132 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Dto;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Net;
|
||||
using MediaBrowser.Model.Dto;
|
||||
using MediaBrowser.Model.Querying;
|
||||
using MediaBrowser.Model.Services;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace MediaBrowser.Api.UserLibrary
|
||||
{
|
||||
/// <summary>
|
||||
/// Class GetStudios
|
||||
/// </summary>
|
||||
[Route("/Studios", "GET", Summary = "Gets all studios from a given item, folder, or the entire library")]
|
||||
public class GetStudios : GetItemsByName
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Class GetStudio
|
||||
/// </summary>
|
||||
[Route("/Studios/{Name}", "GET", Summary = "Gets a studio, by name")]
|
||||
public class GetStudio : IReturn<BaseItemDto>
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the name.
|
||||
/// </summary>
|
||||
/// <value>The name.</value>
|
||||
[ApiMember(Name = "Name", Description = "The studio name", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the user id.
|
||||
/// </summary>
|
||||
/// <value>The user id.</value>
|
||||
[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; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Class StudiosService
|
||||
/// </summary>
|
||||
[Authenticated]
|
||||
public class StudiosService : BaseItemsByNameService<Studio>
|
||||
{
|
||||
public StudiosService(
|
||||
ILogger<StudiosService> logger,
|
||||
IServerConfigurationManager serverConfigurationManager,
|
||||
IHttpResultFactory httpResultFactory,
|
||||
IUserManager userManager,
|
||||
ILibraryManager libraryManager,
|
||||
IUserDataManager userDataRepository,
|
||||
IDtoService dtoService,
|
||||
IAuthorizationContext authorizationContext)
|
||||
: base(
|
||||
logger,
|
||||
serverConfigurationManager,
|
||||
httpResultFactory,
|
||||
userManager,
|
||||
libraryManager,
|
||||
userDataRepository,
|
||||
dtoService,
|
||||
authorizationContext)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the specified request.
|
||||
/// </summary>
|
||||
/// <param name="request">The request.</param>
|
||||
/// <returns>System.Object.</returns>
|
||||
public object Get(GetStudio request)
|
||||
{
|
||||
var result = GetItem(request);
|
||||
|
||||
return ToOptimizedResult(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the item.
|
||||
/// </summary>
|
||||
/// <param name="request">The request.</param>
|
||||
/// <returns>Task{BaseItemDto}.</returns>
|
||||
private BaseItemDto GetItem(GetStudio request)
|
||||
{
|
||||
var dtoOptions = GetDtoOptions(AuthorizationContext, request);
|
||||
|
||||
var item = GetStudio(request.Name, LibraryManager, dtoOptions);
|
||||
|
||||
if (!request.UserId.Equals(Guid.Empty))
|
||||
{
|
||||
var user = UserManager.GetUserById(request.UserId);
|
||||
|
||||
return DtoService.GetBaseItemDto(item, dtoOptions, user);
|
||||
}
|
||||
|
||||
return DtoService.GetBaseItemDto(item, dtoOptions);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the specified request.
|
||||
/// </summary>
|
||||
/// <param name="request">The request.</param>
|
||||
/// <returns>System.Object.</returns>
|
||||
public object Get(GetStudios request)
|
||||
{
|
||||
var result = GetResultSlim(request);
|
||||
|
||||
return ToOptimizedResult(result);
|
||||
}
|
||||
|
||||
protected override QueryResult<(BaseItem, ItemCounts)> GetItems(GetItemsByName request, InternalItemsQuery query)
|
||||
{
|
||||
return LibraryManager.GetStudios(query);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets all items.
|
||||
/// </summary>
|
||||
/// <param name="request">The request.</param>
|
||||
/// <param name="items">The items.</param>
|
||||
/// <returns>IEnumerable{Tuple{System.StringFunc{System.Int32}}}.</returns>
|
||||
protected override IEnumerable<BaseItem> GetAllItems(GetItemsByName request, IList<BaseItem> items)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,575 +0,0 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Common.Extensions;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Dto;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Entities.Audio;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Net;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Dto;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.IO;
|
||||
using MediaBrowser.Model.Querying;
|
||||
using MediaBrowser.Model.Services;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace MediaBrowser.Api.UserLibrary
|
||||
{
|
||||
/// <summary>
|
||||
/// Class GetItem
|
||||
/// </summary>
|
||||
[Route("/Users/{UserId}/Items/{Id}", "GET", Summary = "Gets an item from a user's library")]
|
||||
public class GetItem : IReturn<BaseItemDto>
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the user id.
|
||||
/// </summary>
|
||||
/// <value>The user id.</value>
|
||||
[ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
|
||||
public Guid UserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the id.
|
||||
/// </summary>
|
||||
/// <value>The id.</value>
|
||||
[ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
|
||||
public string Id { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Class GetItem
|
||||
/// </summary>
|
||||
[Route("/Users/{UserId}/Items/Root", "GET", Summary = "Gets the root folder from a user's library")]
|
||||
public class GetRootFolder : IReturn<BaseItemDto>
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the user id.
|
||||
/// </summary>
|
||||
/// <value>The user id.</value>
|
||||
[ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
|
||||
public Guid UserId { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Class GetIntros
|
||||
/// </summary>
|
||||
[Route("/Users/{UserId}/Items/{Id}/Intros", "GET", Summary = "Gets intros to play before the main media item plays")]
|
||||
public class GetIntros : IReturn<QueryResult<BaseItemDto>>
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the user id.
|
||||
/// </summary>
|
||||
/// <value>The user id.</value>
|
||||
[ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
|
||||
public Guid UserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the item id.
|
||||
/// </summary>
|
||||
/// <value>The item id.</value>
|
||||
[ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
|
||||
public string Id { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Class MarkFavoriteItem
|
||||
/// </summary>
|
||||
[Route("/Users/{UserId}/FavoriteItems/{Id}", "POST", Summary = "Marks an item as a favorite")]
|
||||
public class MarkFavoriteItem : IReturn<UserItemDataDto>
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the user id.
|
||||
/// </summary>
|
||||
/// <value>The user id.</value>
|
||||
[ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
|
||||
public Guid UserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the id.
|
||||
/// </summary>
|
||||
/// <value>The id.</value>
|
||||
[ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
|
||||
public Guid Id { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Class UnmarkFavoriteItem
|
||||
/// </summary>
|
||||
[Route("/Users/{UserId}/FavoriteItems/{Id}", "DELETE", Summary = "Unmarks an item as a favorite")]
|
||||
public class UnmarkFavoriteItem : IReturn<UserItemDataDto>
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the user id.
|
||||
/// </summary>
|
||||
/// <value>The user id.</value>
|
||||
[ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")]
|
||||
public Guid UserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the id.
|
||||
/// </summary>
|
||||
/// <value>The id.</value>
|
||||
[ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")]
|
||||
public Guid Id { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Class ClearUserItemRating
|
||||
/// </summary>
|
||||
[Route("/Users/{UserId}/Items/{Id}/Rating", "DELETE", Summary = "Deletes a user's saved personal rating for an item")]
|
||||
public class DeleteUserItemRating : IReturn<UserItemDataDto>
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the user id.
|
||||
/// </summary>
|
||||
/// <value>The user id.</value>
|
||||
[ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")]
|
||||
public Guid UserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the id.
|
||||
/// </summary>
|
||||
/// <value>The id.</value>
|
||||
[ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")]
|
||||
public Guid Id { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Class UpdateUserItemRating
|
||||
/// </summary>
|
||||
[Route("/Users/{UserId}/Items/{Id}/Rating", "POST", Summary = "Updates a user's rating for an item")]
|
||||
public class UpdateUserItemRating : IReturn<UserItemDataDto>
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the user id.
|
||||
/// </summary>
|
||||
/// <value>The user id.</value>
|
||||
[ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
|
||||
public Guid UserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the id.
|
||||
/// </summary>
|
||||
/// <value>The id.</value>
|
||||
[ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
|
||||
public Guid Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether this <see cref="UpdateUserItemRating" /> is likes.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if likes; otherwise, <c>false</c>.</value>
|
||||
[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; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Class GetLocalTrailers
|
||||
/// </summary>
|
||||
[Route("/Users/{UserId}/Items/{Id}/LocalTrailers", "GET", Summary = "Gets local trailers for an item")]
|
||||
public class GetLocalTrailers : IReturn<BaseItemDto[]>
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the user id.
|
||||
/// </summary>
|
||||
/// <value>The user id.</value>
|
||||
[ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
|
||||
public Guid UserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the id.
|
||||
/// </summary>
|
||||
/// <value>The id.</value>
|
||||
[ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
|
||||
public string Id { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Class GetSpecialFeatures
|
||||
/// </summary>
|
||||
[Route("/Users/{UserId}/Items/{Id}/SpecialFeatures", "GET", Summary = "Gets special features for an item")]
|
||||
public class GetSpecialFeatures : IReturn<BaseItemDto[]>
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the user id.
|
||||
/// </summary>
|
||||
/// <value>The user id.</value>
|
||||
[ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
|
||||
public Guid UserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the id.
|
||||
/// </summary>
|
||||
/// <value>The id.</value>
|
||||
[ApiMember(Name = "Id", Description = "Movie Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
|
||||
public string Id { get; set; }
|
||||
}
|
||||
|
||||
[Route("/Users/{UserId}/Items/Latest", "GET", Summary = "Gets latest media")]
|
||||
public class GetLatestMedia : IReturn<BaseItemDto[]>, IHasDtoOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the user id.
|
||||
/// </summary>
|
||||
/// <value>The user id.</value>
|
||||
[ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
|
||||
public Guid UserId { get; set; }
|
||||
|
||||
[ApiMember(Name = "Limit", Description = "Limit", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
|
||||
public int Limit { get; set; }
|
||||
|
||||
[ApiMember(Name = "ParentId", Description = "Specify this to localize the search to a specific item or folder. Omit to use the root", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public Guid ParentId { get; set; }
|
||||
|
||||
[ApiMember(Name = "Fields", Description = "Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimeted. Options: Chapters, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, SortName, Studios, Taglines", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
|
||||
public string Fields { 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; }
|
||||
|
||||
[ApiMember(Name = "IsFolder", Description = "Filter by items that are folders, or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
|
||||
public bool? IsFolder { get; set; }
|
||||
|
||||
[ApiMember(Name = "IsPlayed", Description = "Filter by items that are played, or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
|
||||
public bool? IsPlayed { get; set; }
|
||||
|
||||
[ApiMember(Name = "GroupItems", Description = "Whether or not to group items into a parent container.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
|
||||
public bool GroupItems { get; set; }
|
||||
|
||||
[ApiMember(Name = "EnableImages", Description = "Optional, include image information in output", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")]
|
||||
public bool? EnableImages { get; set; }
|
||||
|
||||
[ApiMember(Name = "ImageTypeLimit", Description = "Optional, the max number of images to return, per image type", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
|
||||
public int? ImageTypeLimit { get; set; }
|
||||
|
||||
[ApiMember(Name = "EnableImageTypes", Description = "Optional. The image types to include in the output.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string EnableImageTypes { get; set; }
|
||||
|
||||
[ApiMember(Name = "EnableUserData", Description = "Optional, include user data", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")]
|
||||
public bool? EnableUserData { get; set; }
|
||||
|
||||
public GetLatestMedia()
|
||||
{
|
||||
Limit = 20;
|
||||
GroupItems = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Class UserLibraryService
|
||||
/// </summary>
|
||||
[Authenticated]
|
||||
public class UserLibraryService : BaseApiService
|
||||
{
|
||||
private readonly IUserManager _userManager;
|
||||
private readonly IUserDataManager _userDataRepository;
|
||||
private readonly ILibraryManager _libraryManager;
|
||||
private readonly IDtoService _dtoService;
|
||||
private readonly IUserViewManager _userViewManager;
|
||||
private readonly IFileSystem _fileSystem;
|
||||
private readonly IAuthorizationContext _authContext;
|
||||
|
||||
public UserLibraryService(
|
||||
ILogger<UserLibraryService> logger,
|
||||
IServerConfigurationManager serverConfigurationManager,
|
||||
IHttpResultFactory httpResultFactory,
|
||||
IUserManager userManager,
|
||||
ILibraryManager libraryManager,
|
||||
IUserDataManager userDataRepository,
|
||||
IDtoService dtoService,
|
||||
IUserViewManager userViewManager,
|
||||
IFileSystem fileSystem,
|
||||
IAuthorizationContext authContext)
|
||||
: base(logger, serverConfigurationManager, httpResultFactory)
|
||||
{
|
||||
_userManager = userManager;
|
||||
_libraryManager = libraryManager;
|
||||
_userDataRepository = userDataRepository;
|
||||
_dtoService = dtoService;
|
||||
_userViewManager = userViewManager;
|
||||
_fileSystem = fileSystem;
|
||||
_authContext = authContext;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the specified request.
|
||||
/// </summary>
|
||||
/// <param name="request">The request.</param>
|
||||
/// <returns>System.Object.</returns>
|
||||
public object Get(GetSpecialFeatures request)
|
||||
{
|
||||
var result = GetAsync(request);
|
||||
|
||||
return ToOptimizedResult(result);
|
||||
}
|
||||
|
||||
public object Get(GetLatestMedia request)
|
||||
{
|
||||
var user = _userManager.GetUserById(request.UserId);
|
||||
|
||||
if (!request.IsPlayed.HasValue)
|
||||
{
|
||||
if (user.HidePlayedInLatest)
|
||||
{
|
||||
request.IsPlayed = false;
|
||||
}
|
||||
}
|
||||
|
||||
var dtoOptions = GetDtoOptions(_authContext, request);
|
||||
|
||||
var list = _userViewManager.GetLatestItems(new LatestItemsQuery
|
||||
{
|
||||
GroupItems = request.GroupItems,
|
||||
IncludeItemTypes = ApiEntryPoint.Split(request.IncludeItemTypes, ',', true),
|
||||
IsPlayed = request.IsPlayed,
|
||||
Limit = request.Limit,
|
||||
ParentId = request.ParentId,
|
||||
UserId = request.UserId,
|
||||
}, dtoOptions);
|
||||
|
||||
var dtos = list.Select(i =>
|
||||
{
|
||||
var item = i.Item2[0];
|
||||
var childCount = 0;
|
||||
|
||||
if (i.Item1 != null && (i.Item2.Count > 1 || i.Item1 is MusicAlbum))
|
||||
{
|
||||
item = i.Item1;
|
||||
childCount = i.Item2.Count;
|
||||
}
|
||||
|
||||
var dto = _dtoService.GetBaseItemDto(item, dtoOptions, user);
|
||||
|
||||
dto.ChildCount = childCount;
|
||||
|
||||
return dto;
|
||||
});
|
||||
|
||||
return ToOptimizedResult(dtos.ToArray());
|
||||
}
|
||||
|
||||
private BaseItemDto[] GetAsync(GetSpecialFeatures request)
|
||||
{
|
||||
var user = _userManager.GetUserById(request.UserId);
|
||||
|
||||
var item = string.IsNullOrEmpty(request.Id) ?
|
||||
_libraryManager.GetUserRootFolder() :
|
||||
_libraryManager.GetItemById(request.Id);
|
||||
|
||||
var dtoOptions = GetDtoOptions(_authContext, request);
|
||||
|
||||
var dtos = item
|
||||
.GetExtras(BaseItem.DisplayExtraTypes)
|
||||
.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user, item));
|
||||
|
||||
return dtos.ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the specified request.
|
||||
/// </summary>
|
||||
/// <param name="request">The request.</param>
|
||||
/// <returns>System.Object.</returns>
|
||||
public object Get(GetLocalTrailers request)
|
||||
{
|
||||
var user = _userManager.GetUserById(request.UserId);
|
||||
|
||||
var item = string.IsNullOrEmpty(request.Id) ? _libraryManager.GetUserRootFolder() : _libraryManager.GetItemById(request.Id);
|
||||
|
||||
var dtoOptions = GetDtoOptions(_authContext, request);
|
||||
|
||||
var dtosExtras = item.GetExtras(new[] { ExtraType.Trailer })
|
||||
.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user, item))
|
||||
.ToArray();
|
||||
|
||||
if (item is IHasTrailers hasTrailers)
|
||||
{
|
||||
var trailers = hasTrailers.GetTrailers();
|
||||
var dtosTrailers = _dtoService.GetBaseItemDtos(trailers, dtoOptions, user, item);
|
||||
var allTrailers = new BaseItemDto[dtosExtras.Length + dtosTrailers.Count];
|
||||
dtosExtras.CopyTo(allTrailers, 0);
|
||||
dtosTrailers.CopyTo(allTrailers, dtosExtras.Length);
|
||||
return ToOptimizedResult(allTrailers);
|
||||
}
|
||||
|
||||
return ToOptimizedResult(dtosExtras);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the specified request.
|
||||
/// </summary>
|
||||
/// <param name="request">The request.</param>
|
||||
/// <returns>System.Object.</returns>
|
||||
public async Task<object> Get(GetItem request)
|
||||
{
|
||||
var user = _userManager.GetUserById(request.UserId);
|
||||
|
||||
var item = string.IsNullOrEmpty(request.Id) ? _libraryManager.GetUserRootFolder() : _libraryManager.GetItemById(request.Id);
|
||||
|
||||
await RefreshItemOnDemandIfNeeded(item).ConfigureAwait(false);
|
||||
|
||||
var dtoOptions = GetDtoOptions(_authContext, request);
|
||||
|
||||
var result = _dtoService.GetBaseItemDto(item, dtoOptions, user);
|
||||
|
||||
return ToOptimizedResult(result);
|
||||
}
|
||||
|
||||
private async Task RefreshItemOnDemandIfNeeded(BaseItem item)
|
||||
{
|
||||
if (item is Person)
|
||||
{
|
||||
var hasMetdata = !string.IsNullOrWhiteSpace(item.Overview) && item.HasImage(ImageType.Primary);
|
||||
var performFullRefresh = !hasMetdata && (DateTime.UtcNow - item.DateLastRefreshed).TotalDays >= 3;
|
||||
|
||||
if (!hasMetdata)
|
||||
{
|
||||
var options = new MetadataRefreshOptions(new DirectoryService(_fileSystem))
|
||||
{
|
||||
MetadataRefreshMode = MetadataRefreshMode.FullRefresh,
|
||||
ImageRefreshMode = MetadataRefreshMode.FullRefresh,
|
||||
ForceSave = performFullRefresh
|
||||
};
|
||||
|
||||
await item.RefreshMetadata(options, CancellationToken.None).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the specified request.
|
||||
/// </summary>
|
||||
/// <param name="request">The request.</param>
|
||||
/// <returns>System.Object.</returns>
|
||||
public object Get(GetRootFolder request)
|
||||
{
|
||||
var user = _userManager.GetUserById(request.UserId);
|
||||
|
||||
var item = _libraryManager.GetUserRootFolder();
|
||||
|
||||
var dtoOptions = GetDtoOptions(_authContext, request);
|
||||
|
||||
var result = _dtoService.GetBaseItemDto(item, dtoOptions, user);
|
||||
|
||||
return ToOptimizedResult(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the specified request.
|
||||
/// </summary>
|
||||
/// <param name="request">The request.</param>
|
||||
/// <returns>System.Object.</returns>
|
||||
public async Task<object> Get(GetIntros request)
|
||||
{
|
||||
var user = _userManager.GetUserById(request.UserId);
|
||||
|
||||
var item = string.IsNullOrEmpty(request.Id) ? _libraryManager.GetUserRootFolder() : _libraryManager.GetItemById(request.Id);
|
||||
|
||||
var items = await _libraryManager.GetIntros(item, user).ConfigureAwait(false);
|
||||
|
||||
var dtoOptions = GetDtoOptions(_authContext, request);
|
||||
|
||||
var dtos = items.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user)).ToArray();
|
||||
|
||||
var result = new QueryResult<BaseItemDto>
|
||||
{
|
||||
Items = dtos,
|
||||
TotalRecordCount = dtos.Length
|
||||
};
|
||||
|
||||
return ToOptimizedResult(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Posts the specified request.
|
||||
/// </summary>
|
||||
/// <param name="request">The request.</param>
|
||||
public object Post(MarkFavoriteItem request)
|
||||
{
|
||||
var dto = MarkFavorite(request.UserId, request.Id, true);
|
||||
|
||||
return ToOptimizedResult(dto);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes the specified request.
|
||||
/// </summary>
|
||||
/// <param name="request">The request.</param>
|
||||
public object Delete(UnmarkFavoriteItem request)
|
||||
{
|
||||
var dto = MarkFavorite(request.UserId, request.Id, false);
|
||||
|
||||
return ToOptimizedResult(dto);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Marks the favorite.
|
||||
/// </summary>
|
||||
/// <param name="userId">The user id.</param>
|
||||
/// <param name="itemId">The item id.</param>
|
||||
/// <param name="isFavorite">if set to <c>true</c> [is favorite].</param>
|
||||
private UserItemDataDto MarkFavorite(Guid userId, Guid itemId, bool isFavorite)
|
||||
{
|
||||
var user = _userManager.GetUserById(userId);
|
||||
|
||||
var item = itemId.Equals(Guid.Empty) ? _libraryManager.GetUserRootFolder() : _libraryManager.GetItemById(itemId);
|
||||
|
||||
// Get the user data for this item
|
||||
var data = _userDataRepository.GetUserData(user, item);
|
||||
|
||||
// Set favorite status
|
||||
data.IsFavorite = isFavorite;
|
||||
|
||||
_userDataRepository.SaveUserData(user, item, data, UserDataSaveReason.UpdateUserRating, CancellationToken.None);
|
||||
|
||||
return _userDataRepository.GetUserDataDto(item, user);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes the specified request.
|
||||
/// </summary>
|
||||
/// <param name="request">The request.</param>
|
||||
public object Delete(DeleteUserItemRating request)
|
||||
{
|
||||
var dto = UpdateUserItemRating(request.UserId, request.Id, null);
|
||||
|
||||
return ToOptimizedResult(dto);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Posts the specified request.
|
||||
/// </summary>
|
||||
/// <param name="request">The request.</param>
|
||||
public object Post(UpdateUserItemRating request)
|
||||
{
|
||||
var dto = UpdateUserItemRating(request.UserId, request.Id, request.Likes);
|
||||
|
||||
return ToOptimizedResult(dto);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the user item rating.
|
||||
/// </summary>
|
||||
/// <param name="userId">The user id.</param>
|
||||
/// <param name="itemId">The item id.</param>
|
||||
/// <param name="likes">if set to <c>true</c> [likes].</param>
|
||||
private UserItemDataDto UpdateUserItemRating(Guid userId, Guid itemId, bool? likes)
|
||||
{
|
||||
var user = _userManager.GetUserById(userId);
|
||||
|
||||
var item = itemId.Equals(Guid.Empty) ? _libraryManager.GetUserRootFolder() : _libraryManager.GetItemById(itemId);
|
||||
|
||||
// Get the user data for this item
|
||||
var data = _userDataRepository.GetUserData(user, item);
|
||||
|
||||
data.Likes = likes;
|
||||
|
||||
_userDataRepository.SaveUserData(user, item, data, UserDataSaveReason.UpdateUserRating, CancellationToken.None);
|
||||
|
||||
return _userDataRepository.GetUserDataDto(item, user);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,146 +0,0 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Dto;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Net;
|
||||
using MediaBrowser.Model.Dto;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Library;
|
||||
using MediaBrowser.Model.Querying;
|
||||
using MediaBrowser.Model.Services;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace MediaBrowser.Api.UserLibrary
|
||||
{
|
||||
[Route("/Users/{UserId}/Views", "GET")]
|
||||
public class GetUserViews : IReturn<QueryResult<BaseItemDto>>
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the user id.
|
||||
/// </summary>
|
||||
/// <value>The user id.</value>
|
||||
[ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
|
||||
public Guid UserId { get; set; }
|
||||
|
||||
[ApiMember(Name = "IncludeExternalContent", Description = "Whether or not to include external views such as channels or live tv", IsRequired = true, DataType = "boolean", ParameterType = "query", Verb = "GET")]
|
||||
public bool? IncludeExternalContent { get; set; }
|
||||
public bool IncludeHidden { get; set; }
|
||||
|
||||
public string PresetViews { get; set; }
|
||||
}
|
||||
|
||||
[Route("/Users/{UserId}/GroupingOptions", "GET")]
|
||||
public class GetGroupingOptions : IReturn<SpecialViewOption[]>
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the user id.
|
||||
/// </summary>
|
||||
/// <value>The user id.</value>
|
||||
[ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
|
||||
public Guid UserId { get; set; }
|
||||
}
|
||||
|
||||
public class UserViewsService : BaseApiService
|
||||
{
|
||||
private readonly IUserManager _userManager;
|
||||
private readonly IUserViewManager _userViewManager;
|
||||
private readonly IDtoService _dtoService;
|
||||
private readonly IAuthorizationContext _authContext;
|
||||
private readonly ILibraryManager _libraryManager;
|
||||
|
||||
public UserViewsService(
|
||||
ILogger<UserViewsService> logger,
|
||||
IServerConfigurationManager serverConfigurationManager,
|
||||
IHttpResultFactory httpResultFactory,
|
||||
IUserManager userManager,
|
||||
IUserViewManager userViewManager,
|
||||
IDtoService dtoService,
|
||||
IAuthorizationContext authContext,
|
||||
ILibraryManager libraryManager)
|
||||
: base(logger, serverConfigurationManager, httpResultFactory)
|
||||
{
|
||||
_userManager = userManager;
|
||||
_userViewManager = userViewManager;
|
||||
_dtoService = dtoService;
|
||||
_authContext = authContext;
|
||||
_libraryManager = libraryManager;
|
||||
}
|
||||
|
||||
public object Get(GetUserViews request)
|
||||
{
|
||||
var query = new UserViewQuery
|
||||
{
|
||||
UserId = request.UserId
|
||||
};
|
||||
|
||||
if (request.IncludeExternalContent.HasValue)
|
||||
{
|
||||
query.IncludeExternalContent = request.IncludeExternalContent.Value;
|
||||
}
|
||||
query.IncludeHidden = request.IncludeHidden;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(request.PresetViews))
|
||||
{
|
||||
query.PresetViews = request.PresetViews.Split(',');
|
||||
}
|
||||
|
||||
var app = _authContext.GetAuthorizationInfo(Request).Client ?? string.Empty;
|
||||
if (app.IndexOf("emby rt", StringComparison.OrdinalIgnoreCase) != -1)
|
||||
{
|
||||
query.PresetViews = new[] { CollectionType.Movies, CollectionType.TvShows };
|
||||
}
|
||||
|
||||
var folders = _userViewManager.GetUserViews(query);
|
||||
|
||||
var dtoOptions = GetDtoOptions(_authContext, request);
|
||||
var fields = dtoOptions.Fields.ToList();
|
||||
|
||||
fields.Add(ItemFields.PrimaryImageAspectRatio);
|
||||
fields.Add(ItemFields.DisplayPreferencesId);
|
||||
fields.Remove(ItemFields.BasicSyncInfo);
|
||||
dtoOptions.Fields = fields.ToArray();
|
||||
|
||||
var user = _userManager.GetUserById(request.UserId);
|
||||
|
||||
var dtos = folders.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user))
|
||||
.ToArray();
|
||||
|
||||
var result = new QueryResult<BaseItemDto>
|
||||
{
|
||||
Items = dtos,
|
||||
TotalRecordCount = dtos.Length
|
||||
};
|
||||
|
||||
return ToOptimizedResult(result);
|
||||
}
|
||||
|
||||
public object Get(GetGroupingOptions request)
|
||||
{
|
||||
var user = _userManager.GetUserById(request.UserId);
|
||||
|
||||
var list = _libraryManager.GetUserRootFolder()
|
||||
.GetChildren(user, true)
|
||||
.OfType<Folder>()
|
||||
.Where(UserView.IsEligibleForGrouping)
|
||||
.Select(i => new SpecialViewOption
|
||||
{
|
||||
Name = i.Name,
|
||||
Id = i.Id.ToString("N", CultureInfo.InvariantCulture)
|
||||
|
||||
})
|
||||
.OrderBy(i => i.Name)
|
||||
.ToArray();
|
||||
|
||||
return ToOptimizedResult(list);
|
||||
}
|
||||
}
|
||||
|
||||
class SpecialViewOption
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string Id { get; set; }
|
||||
}
|
||||
}
|
@ -1,131 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Dto;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Net;
|
||||
using MediaBrowser.Model.Dto;
|
||||
using MediaBrowser.Model.Services;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace MediaBrowser.Api.UserLibrary
|
||||
{
|
||||
/// <summary>
|
||||
/// Class GetYears
|
||||
/// </summary>
|
||||
[Route("/Years", "GET", Summary = "Gets all years from a given item, folder, or the entire library")]
|
||||
public class GetYears : GetItemsByName
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Class GetYear
|
||||
/// </summary>
|
||||
[Route("/Years/{Year}", "GET", Summary = "Gets a year")]
|
||||
public class GetYear : IReturn<BaseItemDto>
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the year.
|
||||
/// </summary>
|
||||
/// <value>The year.</value>
|
||||
[ApiMember(Name = "Year", Description = "The year", IsRequired = true, DataType = "int", ParameterType = "path", Verb = "GET")]
|
||||
public int Year { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the user id.
|
||||
/// </summary>
|
||||
/// <value>The user id.</value>
|
||||
[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; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Class YearsService
|
||||
/// </summary>
|
||||
[Authenticated]
|
||||
public class YearsService : BaseItemsByNameService<Year>
|
||||
{
|
||||
public YearsService(
|
||||
ILogger<YearsService> logger,
|
||||
IServerConfigurationManager serverConfigurationManager,
|
||||
IHttpResultFactory httpResultFactory,
|
||||
IUserManager userManager,
|
||||
ILibraryManager libraryManager,
|
||||
IUserDataManager userDataRepository,
|
||||
IDtoService dtoService,
|
||||
IAuthorizationContext authorizationContext)
|
||||
: base(
|
||||
logger,
|
||||
serverConfigurationManager,
|
||||
httpResultFactory,
|
||||
userManager,
|
||||
libraryManager,
|
||||
userDataRepository,
|
||||
dtoService,
|
||||
authorizationContext)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the specified request.
|
||||
/// </summary>
|
||||
/// <param name="request">The request.</param>
|
||||
/// <returns>System.Object.</returns>
|
||||
public object Get(GetYear request)
|
||||
{
|
||||
var result = GetItem(request);
|
||||
|
||||
return ToOptimizedResult(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the item.
|
||||
/// </summary>
|
||||
/// <param name="request">The request.</param>
|
||||
/// <returns>Task{BaseItemDto}.</returns>
|
||||
private BaseItemDto GetItem(GetYear request)
|
||||
{
|
||||
var item = LibraryManager.GetYear(request.Year);
|
||||
|
||||
var dtoOptions = GetDtoOptions(AuthorizationContext, request);
|
||||
|
||||
if (!request.UserId.Equals(Guid.Empty))
|
||||
{
|
||||
var user = UserManager.GetUserById(request.UserId);
|
||||
|
||||
return DtoService.GetBaseItemDto(item, dtoOptions, user);
|
||||
}
|
||||
|
||||
return DtoService.GetBaseItemDto(item, dtoOptions);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the specified request.
|
||||
/// </summary>
|
||||
/// <param name="request">The request.</param>
|
||||
/// <returns>System.Object.</returns>
|
||||
public object Get(GetYears request)
|
||||
{
|
||||
var result = GetResult(request);
|
||||
|
||||
return ToOptimizedResult(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets all items.
|
||||
/// </summary>
|
||||
/// <param name="request">The request.</param>
|
||||
/// <param name="items">The items.</param>
|
||||
/// <returns>IEnumerable{Tuple{System.StringFunc{System.Int32}}}.</returns>
|
||||
protected override IEnumerable<BaseItem> GetAllItems(GetItemsByName request, IList<BaseItem> items)
|
||||
{
|
||||
return items
|
||||
.Select(i => i.ProductionYear ?? 0)
|
||||
.Where(i => i > 0)
|
||||
.Distinct()
|
||||
.Select(year => LibraryManager.GetYear(year));
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.Buffers.Text;
|
||||
using System.Globalization;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace MediaBrowser.Common.Json.Converters
|
||||
{
|
||||
/// <summary>
|
||||
/// Long to String JSON converter.
|
||||
/// Javascript does not support 64-bit integers.
|
||||
/// </summary>
|
||||
public class JsonInt64Converter : JsonConverter<long>
|
||||
{
|
||||
/// <summary>
|
||||
/// Read JSON string as int64.
|
||||
/// </summary>
|
||||
/// <param name="reader"><see cref="Utf8JsonReader"/>.</param>
|
||||
/// <param name="type">Type.</param>
|
||||
/// <param name="options">Options.</param>
|
||||
/// <returns>Parsed value.</returns>
|
||||
public override long Read(ref Utf8JsonReader reader, Type type, JsonSerializerOptions options)
|
||||
{
|
||||
if (reader.TokenType == JsonTokenType.String)
|
||||
{
|
||||
// try to parse number directly from bytes
|
||||
var span = reader.HasValueSequence ? reader.ValueSequence.ToArray() : reader.ValueSpan;
|
||||
if (Utf8Parser.TryParse(span, out long number, out var bytesConsumed) && span.Length == bytesConsumed)
|
||||
{
|
||||
return number;
|
||||
}
|
||||
|
||||
// try to parse from a string if the above failed, this covers cases with other escaped/UTF characters
|
||||
if (long.TryParse(reader.GetString(), out number))
|
||||
{
|
||||
return number;
|
||||
}
|
||||
}
|
||||
|
||||
// fallback to default handling
|
||||
return reader.GetInt64();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write long to JSON string.
|
||||
/// </summary>
|
||||
/// <param name="writer"><see cref="Utf8JsonWriter"/>.</param>
|
||||
/// <param name="value">Value to write.</param>
|
||||
/// <param name="options">Options.</param>
|
||||
public override void Write(Utf8JsonWriter writer, long value, JsonSerializerOptions options)
|
||||
{
|
||||
writer.WriteStringValue(value.ToString(NumberFormatInfo.InvariantInfo));
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in new issue