mirror of https://github.com/jellyfin/jellyfin.git
Merge branch 'jellyfin:master' into master
This commit is contained in:
commit
1e41636e30
|
@ -157,6 +157,7 @@
|
||||||
- [jonas-resch](https://github.com/jonas-resch)
|
- [jonas-resch](https://github.com/jonas-resch)
|
||||||
- [vgambier](https://github.com/vgambier)
|
- [vgambier](https://github.com/vgambier)
|
||||||
- [MinecraftPlaye](https://github.com/MinecraftPlaye)
|
- [MinecraftPlaye](https://github.com/MinecraftPlaye)
|
||||||
|
- [RealGreenDragon](https://github.com/RealGreenDragon)
|
||||||
|
|
||||||
# Emby Contributors
|
# Emby Contributors
|
||||||
|
|
||||||
|
@ -225,3 +226,4 @@
|
||||||
- [gnuyent](https://github.com/gnuyent)
|
- [gnuyent](https://github.com/gnuyent)
|
||||||
- [Matthew Jones](https://github.com/matthew-jones-uk)
|
- [Matthew Jones](https://github.com/matthew-jones-uk)
|
||||||
- [Jakob Kukla](https://github.com/jakobkukla)
|
- [Jakob Kukla](https://github.com/jakobkukla)
|
||||||
|
- [Utku Özdemir](https://github.com/utkuozdemir)
|
||||||
|
|
|
@ -464,7 +464,9 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
|
||||||
var result = ResolveVideos<T>(parent, fileSystemEntries, SupportsMultiVersion, collectionType, parseName) ??
|
var result = ResolveVideos<T>(parent, fileSystemEntries, SupportsMultiVersion, collectionType, parseName) ??
|
||||||
new MultiItemResolverResult();
|
new MultiItemResolverResult();
|
||||||
|
|
||||||
if (result.Items.Count == 1)
|
var isPhotosCollection = string.Equals(collectionType, CollectionType.HomeVideos, StringComparison.OrdinalIgnoreCase)
|
||||||
|
|| string.Equals(collectionType, CollectionType.Photos, StringComparison.OrdinalIgnoreCase);
|
||||||
|
if (!isPhotosCollection && result.Items.Count == 1)
|
||||||
{
|
{
|
||||||
var videoPath = result.Items[0].Path;
|
var videoPath = result.Items[0].Path;
|
||||||
var hasPhotos = photos.Any(i => !PhotoResolver.IsOwnedByResolvedMedia(videoPath, i.Name));
|
var hasPhotos = photos.Any(i => !PhotoResolver.IsOwnedByResolvedMedia(videoPath, i.Name));
|
||||||
|
|
|
@ -120,5 +120,8 @@
|
||||||
"Forced": "강제하기",
|
"Forced": "강제하기",
|
||||||
"Default": "기본 설정",
|
"Default": "기본 설정",
|
||||||
"TaskOptimizeDatabaseDescription": "데이터베이스를 압축하고 사용 가능한 공간을 늘립니다. 라이브러리를 검색한 후 이 작업을 실행하거나 데이터베이스 수정같은 비슷한 작업을 수행하면 성능이 향상될 수 있습니다.",
|
"TaskOptimizeDatabaseDescription": "데이터베이스를 압축하고 사용 가능한 공간을 늘립니다. 라이브러리를 검색한 후 이 작업을 실행하거나 데이터베이스 수정같은 비슷한 작업을 수행하면 성능이 향상될 수 있습니다.",
|
||||||
"TaskOptimizeDatabase": "데이터베이스 최적화"
|
"TaskOptimizeDatabase": "데이터베이스 최적화",
|
||||||
|
"TaskKeyframeExtractorDescription": "비디오 파일에서 키프레임을 추출하여 더 정확한 HLS 재생 목록을 만듭니다. 이 작업은 오랫동안 진행될 수 있습니다.",
|
||||||
|
"TaskKeyframeExtractor": "키프레임 추출",
|
||||||
|
"External": "외부"
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,9 +43,9 @@ namespace Emby.Server.Implementations.TV
|
||||||
}
|
}
|
||||||
|
|
||||||
string presentationUniqueKey = null;
|
string presentationUniqueKey = null;
|
||||||
if (!string.IsNullOrEmpty(query.SeriesId))
|
if (query.SeriesId.HasValue && !query.SeriesId.Value.Equals(default))
|
||||||
{
|
{
|
||||||
if (_libraryManager.GetItemById(query.SeriesId) is Series series)
|
if (_libraryManager.GetItemById(query.SeriesId.Value) is Series series)
|
||||||
{
|
{
|
||||||
presentationUniqueKey = GetUniqueSeriesKey(series);
|
presentationUniqueKey = GetUniqueSeriesKey(series);
|
||||||
}
|
}
|
||||||
|
@ -93,9 +93,9 @@ namespace Emby.Server.Implementations.TV
|
||||||
|
|
||||||
string presentationUniqueKey = null;
|
string presentationUniqueKey = null;
|
||||||
int? limit = null;
|
int? limit = null;
|
||||||
if (!string.IsNullOrEmpty(request.SeriesId))
|
if (request.SeriesId.HasValue && !request.SeriesId.Value.Equals(default))
|
||||||
{
|
{
|
||||||
if (_libraryManager.GetItemById(request.SeriesId) is Series series)
|
if (_libraryManager.GetItemById(request.SeriesId.Value) is Series series)
|
||||||
{
|
{
|
||||||
presentationUniqueKey = GetUniqueSeriesKey(series);
|
presentationUniqueKey = GetUniqueSeriesKey(series);
|
||||||
limit = 1;
|
limit = 1;
|
||||||
|
@ -153,7 +153,7 @@ namespace Emby.Server.Implementations.TV
|
||||||
|
|
||||||
// If viewing all next up for all series, remove first episodes
|
// If viewing all next up for all series, remove first episodes
|
||||||
// But if that returns empty, keep those first episodes (avoid completely empty view)
|
// But if that returns empty, keep those first episodes (avoid completely empty view)
|
||||||
var alwaysEnableFirstEpisode = !string.IsNullOrEmpty(request.SeriesId);
|
var alwaysEnableFirstEpisode = request.SeriesId.HasValue && !request.SeriesId.Value.Equals(default);
|
||||||
var anyFound = false;
|
var anyFound = false;
|
||||||
|
|
||||||
return allNextUp
|
return allNextUp
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using Jellyfin.Api.Constants;
|
using Jellyfin.Api.Constants;
|
||||||
using Jellyfin.Api.Extensions;
|
using Jellyfin.Api.Extensions;
|
||||||
using Jellyfin.Api.Helpers;
|
using Jellyfin.Api.Helpers;
|
||||||
|
@ -9,6 +10,7 @@ using Jellyfin.Data.Enums;
|
||||||
using MediaBrowser.Controller.Dto;
|
using MediaBrowser.Controller.Dto;
|
||||||
using MediaBrowser.Controller.Entities;
|
using MediaBrowser.Controller.Entities;
|
||||||
using MediaBrowser.Controller.Library;
|
using MediaBrowser.Controller.Library;
|
||||||
|
using MediaBrowser.Controller.Net;
|
||||||
using MediaBrowser.Controller.Session;
|
using MediaBrowser.Controller.Session;
|
||||||
using MediaBrowser.Model.Dto;
|
using MediaBrowser.Model.Dto;
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
|
@ -32,6 +34,7 @@ namespace Jellyfin.Api.Controllers
|
||||||
private readonly ILibraryManager _libraryManager;
|
private readonly ILibraryManager _libraryManager;
|
||||||
private readonly ILocalizationManager _localization;
|
private readonly ILocalizationManager _localization;
|
||||||
private readonly IDtoService _dtoService;
|
private readonly IDtoService _dtoService;
|
||||||
|
private readonly IAuthorizationContext _authContext;
|
||||||
private readonly ILogger<ItemsController> _logger;
|
private readonly ILogger<ItemsController> _logger;
|
||||||
private readonly ISessionManager _sessionManager;
|
private readonly ISessionManager _sessionManager;
|
||||||
|
|
||||||
|
@ -42,6 +45,7 @@ namespace Jellyfin.Api.Controllers
|
||||||
/// <param name="libraryManager">Instance of the <see cref="ILibraryManager"/> interface.</param>
|
/// <param name="libraryManager">Instance of the <see cref="ILibraryManager"/> interface.</param>
|
||||||
/// <param name="localization">Instance of the <see cref="ILocalizationManager"/> interface.</param>
|
/// <param name="localization">Instance of the <see cref="ILocalizationManager"/> interface.</param>
|
||||||
/// <param name="dtoService">Instance of the <see cref="IDtoService"/> interface.</param>
|
/// <param name="dtoService">Instance of the <see cref="IDtoService"/> interface.</param>
|
||||||
|
/// <param name="authContext">Instance of the <see cref="IAuthorizationContext"/> interface.</param>
|
||||||
/// <param name="logger">Instance of the <see cref="ILogger"/> interface.</param>
|
/// <param name="logger">Instance of the <see cref="ILogger"/> interface.</param>
|
||||||
/// <param name="sessionManager">Instance of the <see cref="ISessionManager"/> interface.</param>
|
/// <param name="sessionManager">Instance of the <see cref="ISessionManager"/> interface.</param>
|
||||||
public ItemsController(
|
public ItemsController(
|
||||||
|
@ -49,6 +53,7 @@ namespace Jellyfin.Api.Controllers
|
||||||
ILibraryManager libraryManager,
|
ILibraryManager libraryManager,
|
||||||
ILocalizationManager localization,
|
ILocalizationManager localization,
|
||||||
IDtoService dtoService,
|
IDtoService dtoService,
|
||||||
|
IAuthorizationContext authContext,
|
||||||
ILogger<ItemsController> logger,
|
ILogger<ItemsController> logger,
|
||||||
ISessionManager sessionManager)
|
ISessionManager sessionManager)
|
||||||
{
|
{
|
||||||
|
@ -56,6 +61,7 @@ namespace Jellyfin.Api.Controllers
|
||||||
_libraryManager = libraryManager;
|
_libraryManager = libraryManager;
|
||||||
_localization = localization;
|
_localization = localization;
|
||||||
_dtoService = dtoService;
|
_dtoService = dtoService;
|
||||||
|
_authContext = authContext;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_sessionManager = sessionManager;
|
_sessionManager = sessionManager;
|
||||||
}
|
}
|
||||||
|
@ -63,7 +69,7 @@ namespace Jellyfin.Api.Controllers
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets items based on a query.
|
/// Gets items based on a query.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="userId">The user id supplied as query parameter.</param>
|
/// <param name="userId">The user id supplied as query parameter; this is required when not using an API key.</param>
|
||||||
/// <param name="maxOfficialRating">Optional filter by maximum official rating (PG, PG-13, TV-MA, etc).</param>
|
/// <param name="maxOfficialRating">Optional filter by maximum official rating (PG, PG-13, TV-MA, etc).</param>
|
||||||
/// <param name="hasThemeSong">Optional filter by items with theme songs.</param>
|
/// <param name="hasThemeSong">Optional filter by items with theme songs.</param>
|
||||||
/// <param name="hasThemeVideo">Optional filter by items with theme videos.</param>
|
/// <param name="hasThemeVideo">Optional filter by items with theme videos.</param>
|
||||||
|
@ -151,15 +157,15 @@ namespace Jellyfin.Api.Controllers
|
||||||
/// <returns>A <see cref="QueryResult{BaseItemDto}"/> with the items.</returns>
|
/// <returns>A <see cref="QueryResult{BaseItemDto}"/> with the items.</returns>
|
||||||
[HttpGet("Items")]
|
[HttpGet("Items")]
|
||||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||||
public ActionResult<QueryResult<BaseItemDto>> GetItems(
|
public async Task<ActionResult<QueryResult<BaseItemDto>>> GetItems(
|
||||||
[FromQuery] Guid userId,
|
[FromQuery] Guid? userId,
|
||||||
[FromQuery] string? maxOfficialRating,
|
[FromQuery] string? maxOfficialRating,
|
||||||
[FromQuery] bool? hasThemeSong,
|
[FromQuery] bool? hasThemeSong,
|
||||||
[FromQuery] bool? hasThemeVideo,
|
[FromQuery] bool? hasThemeVideo,
|
||||||
[FromQuery] bool? hasSubtitles,
|
[FromQuery] bool? hasSubtitles,
|
||||||
[FromQuery] bool? hasSpecialFeature,
|
[FromQuery] bool? hasSpecialFeature,
|
||||||
[FromQuery] bool? hasTrailer,
|
[FromQuery] bool? hasTrailer,
|
||||||
[FromQuery] string? adjacentTo,
|
[FromQuery] Guid? adjacentTo,
|
||||||
[FromQuery] int? parentIndexNumber,
|
[FromQuery] int? parentIndexNumber,
|
||||||
[FromQuery] bool? hasParentalRating,
|
[FromQuery] bool? hasParentalRating,
|
||||||
[FromQuery] bool? isHd,
|
[FromQuery] bool? isHd,
|
||||||
|
@ -238,7 +244,19 @@ namespace Jellyfin.Api.Controllers
|
||||||
[FromQuery] bool enableTotalRecordCount = true,
|
[FromQuery] bool enableTotalRecordCount = true,
|
||||||
[FromQuery] bool? enableImages = true)
|
[FromQuery] bool? enableImages = true)
|
||||||
{
|
{
|
||||||
var user = userId.Equals(default) ? null : _userManager.GetUserById(userId);
|
var auth = await _authContext.GetAuthorizationInfo(Request).ConfigureAwait(false);
|
||||||
|
|
||||||
|
// if api key is used (auth.IsApiKey == true), then `user` will be null throughout this method
|
||||||
|
var user = !auth.IsApiKey && userId.HasValue && !userId.Value.Equals(default)
|
||||||
|
? _userManager.GetUserById(userId.Value)
|
||||||
|
: null;
|
||||||
|
|
||||||
|
// beyond this point, we're either using an api key or we have a valid user
|
||||||
|
if (!auth.IsApiKey && user is null)
|
||||||
|
{
|
||||||
|
return BadRequest("userId is required");
|
||||||
|
}
|
||||||
|
|
||||||
var dtoOptions = new DtoOptions { Fields = fields }
|
var dtoOptions = new DtoOptions { Fields = fields }
|
||||||
.AddClientFields(Request)
|
.AddClientFields(Request)
|
||||||
.AddAdditionalDtoOptions(enableImages, enableUserData, imageTypeLimit, enableImageTypes);
|
.AddAdditionalDtoOptions(enableImages, enableUserData, imageTypeLimit, enableImageTypes);
|
||||||
|
@ -270,30 +288,39 @@ namespace Jellyfin.Api.Controllers
|
||||||
includeItemTypes = new[] { BaseItemKind.Playlist };
|
includeItemTypes = new[] { BaseItemKind.Playlist };
|
||||||
}
|
}
|
||||||
|
|
||||||
var enabledChannels = user!.GetPreferenceValues<Guid>(PreferenceKind.EnabledChannels);
|
var enabledChannels = auth.IsApiKey
|
||||||
|
? Array.Empty<Guid>()
|
||||||
|
: user!.GetPreferenceValues<Guid>(PreferenceKind.EnabledChannels);
|
||||||
|
|
||||||
bool isInEnabledFolder = Array.IndexOf(user.GetPreferenceValues<Guid>(PreferenceKind.EnabledFolders), item.Id) != -1
|
// api keys are always enabled for all folders
|
||||||
|
bool isInEnabledFolder = auth.IsApiKey
|
||||||
|
|| Array.IndexOf(user!.GetPreferenceValues<Guid>(PreferenceKind.EnabledFolders), item.Id) != -1
|
||||||
// Assume all folders inside an EnabledChannel are enabled
|
// Assume all folders inside an EnabledChannel are enabled
|
||||||
|| Array.IndexOf(enabledChannels, item.Id) != -1
|
|| Array.IndexOf(enabledChannels, item.Id) != -1
|
||||||
// Assume all items inside an EnabledChannel are enabled
|
// Assume all items inside an EnabledChannel are enabled
|
||||||
|| Array.IndexOf(enabledChannels, item.ChannelId) != -1;
|
|| Array.IndexOf(enabledChannels, item.ChannelId) != -1;
|
||||||
|
|
||||||
var collectionFolders = _libraryManager.GetCollectionFolders(item);
|
if (!isInEnabledFolder)
|
||||||
foreach (var collectionFolder in collectionFolders)
|
|
||||||
{
|
{
|
||||||
if (user.GetPreferenceValues<Guid>(PreferenceKind.EnabledFolders).Contains(collectionFolder.Id))
|
var collectionFolders = _libraryManager.GetCollectionFolders(item);
|
||||||
|
foreach (var collectionFolder in collectionFolders)
|
||||||
{
|
{
|
||||||
isInEnabledFolder = true;
|
// api keys never enter this block, so user is never null
|
||||||
|
if (user!.GetPreferenceValues<Guid>(PreferenceKind.EnabledFolders).Contains(collectionFolder.Id))
|
||||||
|
{
|
||||||
|
isInEnabledFolder = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// api keys are always enabled for all folders, so user is never null
|
||||||
if (item is not UserRootFolder
|
if (item is not UserRootFolder
|
||||||
&& !isInEnabledFolder
|
&& !isInEnabledFolder
|
||||||
&& !user.HasPermission(PermissionKind.EnableAllFolders)
|
&& !user!.HasPermission(PermissionKind.EnableAllFolders)
|
||||||
&& !user.HasPermission(PermissionKind.EnableAllChannels)
|
&& !user.HasPermission(PermissionKind.EnableAllChannels)
|
||||||
&& !string.Equals(collectionType, CollectionType.Folders, StringComparison.OrdinalIgnoreCase))
|
&& !string.Equals(collectionType, CollectionType.Folders, StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
_logger.LogWarning("{UserName} is not permitted to access Library {ItemName}.", user.Username, item.Name);
|
_logger.LogWarning("{UserName} is not permitted to access Library {ItemName}", user.Username, item.Name);
|
||||||
return Unauthorized($"{user.Username} is not permitted to access Library {item.Name}.");
|
return Unauthorized($"{user.Username} is not permitted to access Library {item.Name}.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -606,7 +633,7 @@ namespace Jellyfin.Api.Controllers
|
||||||
/// <returns>A <see cref="QueryResult{BaseItemDto}"/> with the items.</returns>
|
/// <returns>A <see cref="QueryResult{BaseItemDto}"/> with the items.</returns>
|
||||||
[HttpGet("Users/{userId}/Items")]
|
[HttpGet("Users/{userId}/Items")]
|
||||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||||
public ActionResult<QueryResult<BaseItemDto>> GetItemsByUserId(
|
public Task<ActionResult<QueryResult<BaseItemDto>>> GetItemsByUserId(
|
||||||
[FromRoute] Guid userId,
|
[FromRoute] Guid userId,
|
||||||
[FromQuery] string? maxOfficialRating,
|
[FromQuery] string? maxOfficialRating,
|
||||||
[FromQuery] bool? hasThemeSong,
|
[FromQuery] bool? hasThemeSong,
|
||||||
|
@ -614,7 +641,7 @@ namespace Jellyfin.Api.Controllers
|
||||||
[FromQuery] bool? hasSubtitles,
|
[FromQuery] bool? hasSubtitles,
|
||||||
[FromQuery] bool? hasSpecialFeature,
|
[FromQuery] bool? hasSpecialFeature,
|
||||||
[FromQuery] bool? hasTrailer,
|
[FromQuery] bool? hasTrailer,
|
||||||
[FromQuery] string? adjacentTo,
|
[FromQuery] Guid? adjacentTo,
|
||||||
[FromQuery] int? parentIndexNumber,
|
[FromQuery] int? parentIndexNumber,
|
||||||
[FromQuery] bool? hasParentalRating,
|
[FromQuery] bool? hasParentalRating,
|
||||||
[FromQuery] bool? isHd,
|
[FromQuery] bool? isHd,
|
||||||
|
|
|
@ -79,7 +79,7 @@ namespace Jellyfin.Api.Controllers
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
[Description("Gets search hints based on a search term")]
|
[Description("Gets search hints based on a search term")]
|
||||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||||
public ActionResult<SearchHintResult> Get(
|
public ActionResult<SearchHintResult> GetSearchHints(
|
||||||
[FromQuery] int? startIndex,
|
[FromQuery] int? startIndex,
|
||||||
[FromQuery] int? limit,
|
[FromQuery] int? limit,
|
||||||
[FromQuery] Guid? userId,
|
[FromQuery] Guid? userId,
|
||||||
|
@ -140,7 +140,7 @@ namespace Jellyfin.Api.Controllers
|
||||||
IndexNumber = item.IndexNumber,
|
IndexNumber = item.IndexNumber,
|
||||||
ParentIndexNumber = item.ParentIndexNumber,
|
ParentIndexNumber = item.ParentIndexNumber,
|
||||||
Id = item.Id,
|
Id = item.Id,
|
||||||
Type = item.GetClientTypeName(),
|
Type = item.GetBaseItemKind(),
|
||||||
MediaType = item.MediaType,
|
MediaType = item.MediaType,
|
||||||
MatchedTerm = hintInfo.MatchedTerm,
|
MatchedTerm = hintInfo.MatchedTerm,
|
||||||
RunTimeTicks = item.RunTimeTicks,
|
RunTimeTicks = item.RunTimeTicks,
|
||||||
|
@ -149,8 +149,10 @@ namespace Jellyfin.Api.Controllers
|
||||||
EndDate = item.EndDate
|
EndDate = item.EndDate
|
||||||
};
|
};
|
||||||
|
|
||||||
// legacy
|
#pragma warning disable CS0618
|
||||||
|
// Kept for compatibility with older clients
|
||||||
result.ItemId = result.Id;
|
result.ItemId = result.Id;
|
||||||
|
#pragma warning restore CS0618
|
||||||
|
|
||||||
if (item.IsFolder)
|
if (item.IsFolder)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using Jellyfin.Api.Constants;
|
using Jellyfin.Api.Constants;
|
||||||
using Jellyfin.Api.ModelBinders;
|
using Jellyfin.Api.ModelBinders;
|
||||||
using Jellyfin.Data.Enums;
|
using Jellyfin.Data.Enums;
|
||||||
|
@ -31,7 +32,7 @@ namespace Jellyfin.Api.Controllers
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Finds movies and trailers similar to a given trailer.
|
/// Finds movies and trailers similar to a given trailer.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="userId">The user id.</param>
|
/// <param name="userId">The user id supplied as query parameter; this is required when not using an API key.</param>
|
||||||
/// <param name="maxOfficialRating">Optional filter by maximum official rating (PG, PG-13, TV-MA, etc).</param>
|
/// <param name="maxOfficialRating">Optional filter by maximum official rating (PG, PG-13, TV-MA, etc).</param>
|
||||||
/// <param name="hasThemeSong">Optional filter by items with theme songs.</param>
|
/// <param name="hasThemeSong">Optional filter by items with theme songs.</param>
|
||||||
/// <param name="hasThemeVideo">Optional filter by items with theme videos.</param>
|
/// <param name="hasThemeVideo">Optional filter by items with theme videos.</param>
|
||||||
|
@ -118,15 +119,15 @@ namespace Jellyfin.Api.Controllers
|
||||||
/// <returns>A <see cref="QueryResult{BaseItemDto}"/> with the trailers.</returns>
|
/// <returns>A <see cref="QueryResult{BaseItemDto}"/> with the trailers.</returns>
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||||
public ActionResult<QueryResult<BaseItemDto>> GetTrailers(
|
public Task<ActionResult<QueryResult<BaseItemDto>>> GetTrailers(
|
||||||
[FromQuery] Guid userId,
|
[FromQuery] Guid? userId,
|
||||||
[FromQuery] string? maxOfficialRating,
|
[FromQuery] string? maxOfficialRating,
|
||||||
[FromQuery] bool? hasThemeSong,
|
[FromQuery] bool? hasThemeSong,
|
||||||
[FromQuery] bool? hasThemeVideo,
|
[FromQuery] bool? hasThemeVideo,
|
||||||
[FromQuery] bool? hasSubtitles,
|
[FromQuery] bool? hasSubtitles,
|
||||||
[FromQuery] bool? hasSpecialFeature,
|
[FromQuery] bool? hasSpecialFeature,
|
||||||
[FromQuery] bool? hasTrailer,
|
[FromQuery] bool? hasTrailer,
|
||||||
[FromQuery] string? adjacentTo,
|
[FromQuery] Guid? adjacentTo,
|
||||||
[FromQuery] int? parentIndexNumber,
|
[FromQuery] int? parentIndexNumber,
|
||||||
[FromQuery] bool? hasParentalRating,
|
[FromQuery] bool? hasParentalRating,
|
||||||
[FromQuery] bool? isHd,
|
[FromQuery] bool? isHd,
|
||||||
|
|
|
@ -77,7 +77,7 @@ namespace Jellyfin.Api.Controllers
|
||||||
[FromQuery] int? startIndex,
|
[FromQuery] int? startIndex,
|
||||||
[FromQuery] int? limit,
|
[FromQuery] int? limit,
|
||||||
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields,
|
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields,
|
||||||
[FromQuery] string? seriesId,
|
[FromQuery] Guid? seriesId,
|
||||||
[FromQuery] Guid? parentId,
|
[FromQuery] Guid? parentId,
|
||||||
[FromQuery] bool? enableImages,
|
[FromQuery] bool? enableImages,
|
||||||
[FromQuery] int? imageTypeLimit,
|
[FromQuery] int? imageTypeLimit,
|
||||||
|
@ -206,7 +206,7 @@ namespace Jellyfin.Api.Controllers
|
||||||
[FromQuery] int? season,
|
[FromQuery] int? season,
|
||||||
[FromQuery] Guid? seasonId,
|
[FromQuery] Guid? seasonId,
|
||||||
[FromQuery] bool? isMissing,
|
[FromQuery] bool? isMissing,
|
||||||
[FromQuery] string? adjacentTo,
|
[FromQuery] Guid? adjacentTo,
|
||||||
[FromQuery] Guid? startItemId,
|
[FromQuery] Guid? startItemId,
|
||||||
[FromQuery] int? startIndex,
|
[FromQuery] int? startIndex,
|
||||||
[FromQuery] int? limit,
|
[FromQuery] int? limit,
|
||||||
|
@ -278,9 +278,9 @@ namespace Jellyfin.Api.Controllers
|
||||||
}
|
}
|
||||||
|
|
||||||
// This must be the last filter
|
// This must be the last filter
|
||||||
if (!string.IsNullOrEmpty(adjacentTo))
|
if (adjacentTo.HasValue && !adjacentTo.Value.Equals(default))
|
||||||
{
|
{
|
||||||
episodes = UserViewBuilder.FilterForAdjacency(episodes, adjacentTo).ToList();
|
episodes = UserViewBuilder.FilterForAdjacency(episodes, adjacentTo.Value).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (string.Equals(sortBy, ItemSortBy.Random, StringComparison.OrdinalIgnoreCase))
|
if (string.Equals(sortBy, ItemSortBy.Random, StringComparison.OrdinalIgnoreCase))
|
||||||
|
@ -326,7 +326,7 @@ namespace Jellyfin.Api.Controllers
|
||||||
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields,
|
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields,
|
||||||
[FromQuery] bool? isSpecialSeason,
|
[FromQuery] bool? isSpecialSeason,
|
||||||
[FromQuery] bool? isMissing,
|
[FromQuery] bool? isMissing,
|
||||||
[FromQuery] string? adjacentTo,
|
[FromQuery] Guid? adjacentTo,
|
||||||
[FromQuery] bool? enableImages,
|
[FromQuery] bool? enableImages,
|
||||||
[FromQuery] int? imageTypeLimit,
|
[FromQuery] int? imageTypeLimit,
|
||||||
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes,
|
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes,
|
||||||
|
|
|
@ -860,7 +860,7 @@ namespace MediaBrowser.Controller.Entities
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(query.AdjacentTo))
|
if (query.AdjacentTo.HasValue && !query.AdjacentTo.Value.Equals(default))
|
||||||
{
|
{
|
||||||
Logger.LogDebug("Query requires post-filtering due to AdjacentTo");
|
Logger.LogDebug("Query requires post-filtering due to AdjacentTo");
|
||||||
return true;
|
return true;
|
||||||
|
@ -1029,9 +1029,9 @@ namespace MediaBrowser.Controller.Entities
|
||||||
#pragma warning restore CA1309
|
#pragma warning restore CA1309
|
||||||
|
|
||||||
// This must be the last filter
|
// This must be the last filter
|
||||||
if (!string.IsNullOrEmpty(query.AdjacentTo))
|
if (query.AdjacentTo.HasValue && !query.AdjacentTo.Value.Equals(default))
|
||||||
{
|
{
|
||||||
items = UserViewBuilder.FilterForAdjacency(items.ToList(), query.AdjacentTo);
|
items = UserViewBuilder.FilterForAdjacency(items.ToList(), query.AdjacentTo.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
return UserViewBuilder.SortAndPage(items, null, query, LibraryManager, enableSorting);
|
return UserViewBuilder.SortAndPage(items, null, query, LibraryManager, enableSorting);
|
||||||
|
|
|
@ -129,7 +129,7 @@ namespace MediaBrowser.Controller.Entities
|
||||||
|
|
||||||
public Guid[] ExcludeItemIds { get; set; }
|
public Guid[] ExcludeItemIds { get; set; }
|
||||||
|
|
||||||
public string? AdjacentTo { get; set; }
|
public Guid? AdjacentTo { get; set; }
|
||||||
|
|
||||||
public string[] PersonTypes { get; set; }
|
public string[] PersonTypes { get; set; }
|
||||||
|
|
||||||
|
|
|
@ -433,9 +433,9 @@ namespace MediaBrowser.Controller.Entities
|
||||||
var user = query.User;
|
var user = query.User;
|
||||||
|
|
||||||
// This must be the last filter
|
// This must be the last filter
|
||||||
if (!string.IsNullOrEmpty(query.AdjacentTo))
|
if (query.AdjacentTo.HasValue && !query.AdjacentTo.Value.Equals(default))
|
||||||
{
|
{
|
||||||
items = FilterForAdjacency(items.ToList(), query.AdjacentTo);
|
items = FilterForAdjacency(items.ToList(), query.AdjacentTo.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
return SortAndPage(items, totalRecordLimit, query, libraryManager, true);
|
return SortAndPage(items, totalRecordLimit, query, libraryManager, true);
|
||||||
|
@ -985,10 +985,9 @@ namespace MediaBrowser.Controller.Entities
|
||||||
return _userViewManager.GetUserSubView(parent.Id, type, localizationKey, sortName);
|
return _userViewManager.GetUserSubView(parent.Id, type, localizationKey, sortName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IEnumerable<BaseItem> FilterForAdjacency(List<BaseItem> list, string adjacentToId)
|
public static IEnumerable<BaseItem> FilterForAdjacency(List<BaseItem> list, Guid adjacentTo)
|
||||||
{
|
{
|
||||||
var adjacentToIdGuid = new Guid(adjacentToId);
|
var adjacentToItem = list.FirstOrDefault(i => i.Id.Equals(adjacentTo));
|
||||||
var adjacentToItem = list.FirstOrDefault(i => i.Id.Equals(adjacentToIdGuid));
|
|
||||||
|
|
||||||
var index = list.IndexOf(adjacentToItem);
|
var index = list.IndexOf(adjacentToItem);
|
||||||
|
|
||||||
|
@ -1005,7 +1004,7 @@ namespace MediaBrowser.Controller.Entities
|
||||||
nextId = list[index + 1].Id;
|
nextId = list[index + 1].Id;
|
||||||
}
|
}
|
||||||
|
|
||||||
return list.Where(i => i.Id.Equals(previousId) || i.Id.Equals(nextId) || i.Id.Equals(adjacentToIdGuid));
|
return list.Where(i => i.Id.Equals(previousId) || i.Id.Equals(nextId) || i.Id.Equals(adjacentTo));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -574,7 +574,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
|
||||||
var ranToCompletion = await process.WaitForExitAsync(TimeSpan.FromMinutes(5)).ConfigureAwait(false);
|
var ranToCompletion = await process.WaitForExitAsync(TimeSpan.FromMinutes(30)).ConfigureAwait(false);
|
||||||
|
|
||||||
if (!ranToCompletion)
|
if (!ranToCompletion)
|
||||||
{
|
{
|
||||||
|
|
|
@ -33,7 +33,7 @@ namespace MediaBrowser.Model.Querying
|
||||||
/// Gets or sets the series id.
|
/// Gets or sets the series id.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>The series id.</value>
|
/// <value>The series id.</value>
|
||||||
public string SeriesId { get; set; }
|
public Guid? SeriesId { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the start index. Use for paging.
|
/// Gets or sets the start index. Use for paging.
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
#nullable disable
|
|
||||||
#pragma warning disable CS1591
|
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using Jellyfin.Data.Enums;
|
||||||
|
|
||||||
namespace MediaBrowser.Model.Search
|
namespace MediaBrowser.Model.Search
|
||||||
{
|
{
|
||||||
|
@ -11,12 +9,28 @@ namespace MediaBrowser.Model.Search
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class SearchHint
|
public class SearchHint
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="SearchHint" /> class.
|
||||||
|
/// </summary>
|
||||||
|
public SearchHint()
|
||||||
|
{
|
||||||
|
Name = string.Empty;
|
||||||
|
MatchedTerm = string.Empty;
|
||||||
|
MediaType = string.Empty;
|
||||||
|
Artists = Array.Empty<string>();
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the item id.
|
/// Gets or sets the item id.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>The item id.</value>
|
/// <value>The item id.</value>
|
||||||
|
[Obsolete("Use Id instead")]
|
||||||
public Guid ItemId { get; set; }
|
public Guid ItemId { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the item id.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The item id.</value>
|
||||||
public Guid Id { get; set; }
|
public Guid Id { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -53,38 +67,42 @@ namespace MediaBrowser.Model.Search
|
||||||
/// Gets or sets the image tag.
|
/// Gets or sets the image tag.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>The image tag.</value>
|
/// <value>The image tag.</value>
|
||||||
public string PrimaryImageTag { get; set; }
|
public string? PrimaryImageTag { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the thumb image tag.
|
/// Gets or sets the thumb image tag.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>The thumb image tag.</value>
|
/// <value>The thumb image tag.</value>
|
||||||
public string ThumbImageTag { get; set; }
|
public string? ThumbImageTag { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the thumb image item identifier.
|
/// Gets or sets the thumb image item identifier.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>The thumb image item identifier.</value>
|
/// <value>The thumb image item identifier.</value>
|
||||||
public string ThumbImageItemId { get; set; }
|
public string? ThumbImageItemId { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the backdrop image tag.
|
/// Gets or sets the backdrop image tag.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>The backdrop image tag.</value>
|
/// <value>The backdrop image tag.</value>
|
||||||
public string BackdropImageTag { get; set; }
|
public string? BackdropImageTag { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the backdrop image item identifier.
|
/// Gets or sets the backdrop image item identifier.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>The backdrop image item identifier.</value>
|
/// <value>The backdrop image item identifier.</value>
|
||||||
public string BackdropImageItemId { get; set; }
|
public string? BackdropImageItemId { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the type.
|
/// Gets or sets the type.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>The type.</value>
|
/// <value>The type.</value>
|
||||||
public string Type { get; set; }
|
public BaseItemKind Type { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value indicating whether this instance is folder.
|
||||||
|
/// </summary>
|
||||||
|
/// <value><c>true</c> if this instance is folder; otherwise, <c>false</c>.</value>
|
||||||
public bool? IsFolder { get; set; }
|
public bool? IsFolder { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -99,31 +117,47 @@ namespace MediaBrowser.Model.Search
|
||||||
/// <value>The type of the media.</value>
|
/// <value>The type of the media.</value>
|
||||||
public string MediaType { get; set; }
|
public string MediaType { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the start date.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The start date.</value>
|
||||||
public DateTime? StartDate { get; set; }
|
public DateTime? StartDate { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the end date.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The end date.</value>
|
||||||
public DateTime? EndDate { get; set; }
|
public DateTime? EndDate { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the series.
|
/// Gets or sets the series.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>The series.</value>
|
/// <value>The series.</value>
|
||||||
public string Series { get; set; }
|
public string? Series { get; set; }
|
||||||
|
|
||||||
public string Status { get; set; }
|
/// <summary>
|
||||||
|
/// Gets or sets the status.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The status.</value>
|
||||||
|
public string? Status { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the album.
|
/// Gets or sets the album.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>The album.</value>
|
/// <value>The album.</value>
|
||||||
public string Album { get; set; }
|
public string? Album { get; set; }
|
||||||
|
|
||||||
public Guid AlbumId { get; set; }
|
/// <summary>
|
||||||
|
/// Gets or sets the album id.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The album id.</value>
|
||||||
|
public Guid? AlbumId { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the album artist.
|
/// Gets or sets the album artist.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>The album artist.</value>
|
/// <value>The album artist.</value>
|
||||||
public string AlbumArtist { get; set; }
|
public string? AlbumArtist { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the artists.
|
/// Gets or sets the artists.
|
||||||
|
@ -147,13 +181,13 @@ namespace MediaBrowser.Model.Search
|
||||||
/// Gets or sets the channel identifier.
|
/// Gets or sets the channel identifier.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>The channel identifier.</value>
|
/// <value>The channel identifier.</value>
|
||||||
public Guid ChannelId { get; set; }
|
public Guid? ChannelId { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the name of the channel.
|
/// Gets or sets the name of the channel.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>The name of the channel.</value>
|
/// <value>The name of the channel.</value>
|
||||||
public string ChannelName { get; set; }
|
public string? ChannelName { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the primary image aspect ratio.
|
/// Gets or sets the primary image aspect ratio.
|
||||||
|
|
Loading…
Reference in New Issue