aboutsummaryrefslogtreecommitdiff
path: root/Jellyfin.Api/Controllers
diff options
context:
space:
mode:
Diffstat (limited to 'Jellyfin.Api/Controllers')
-rw-r--r--Jellyfin.Api/Controllers/ApiKeyController.cs6
-rw-r--r--Jellyfin.Api/Controllers/ArtistsController.cs24
-rw-r--r--Jellyfin.Api/Controllers/ChannelsController.cs12
-rw-r--r--Jellyfin.Api/Controllers/DisplayPreferencesController.cs6
-rw-r--r--Jellyfin.Api/Controllers/DynamicHlsController.cs190
-rw-r--r--Jellyfin.Api/Controllers/FilterController.cs12
-rw-r--r--Jellyfin.Api/Controllers/GenresController.cs27
-rw-r--r--Jellyfin.Api/Controllers/HlsSegmentController.cs4
-rw-r--r--Jellyfin.Api/Controllers/ImageController.cs281
-rw-r--r--Jellyfin.Api/Controllers/InstantMixController.cs52
-rw-r--r--Jellyfin.Api/Controllers/ItemsController.cs23
-rw-r--r--Jellyfin.Api/Controllers/LibraryController.cs76
-rw-r--r--Jellyfin.Api/Controllers/LiveTvController.cs71
-rw-r--r--Jellyfin.Api/Controllers/MoviesController.cs6
-rw-r--r--Jellyfin.Api/Controllers/MusicGenresController.cs6
-rw-r--r--Jellyfin.Api/Controllers/PersonsController.cs17
-rw-r--r--Jellyfin.Api/Controllers/PlaylistsController.cs13
-rw-r--r--Jellyfin.Api/Controllers/PluginsController.cs71
-rw-r--r--Jellyfin.Api/Controllers/SearchController.cs8
-rw-r--r--Jellyfin.Api/Controllers/SessionController.cs6
-rw-r--r--Jellyfin.Api/Controllers/StudiosController.cs6
-rw-r--r--Jellyfin.Api/Controllers/SuggestionsController.cs13
-rw-r--r--Jellyfin.Api/Controllers/TvShowsController.cs64
-rw-r--r--Jellyfin.Api/Controllers/UserController.cs2
-rw-r--r--Jellyfin.Api/Controllers/UserLibraryController.cs31
-rw-r--r--Jellyfin.Api/Controllers/UserViewsController.cs6
-rw-r--r--Jellyfin.Api/Controllers/VideosController.cs31
-rw-r--r--Jellyfin.Api/Controllers/YearsController.cs28
28 files changed, 498 insertions, 594 deletions
diff --git a/Jellyfin.Api/Controllers/ApiKeyController.cs b/Jellyfin.Api/Controllers/ApiKeyController.cs
index 8e0332d3e..593846adc 100644
--- a/Jellyfin.Api/Controllers/ApiKeyController.cs
+++ b/Jellyfin.Api/Controllers/ApiKeyController.cs
@@ -38,11 +38,7 @@ namespace Jellyfin.Api.Controllers
{
var keys = await _authenticationManager.GetApiKeys();
- return new QueryResult<AuthenticationInfo>
- {
- Items = keys,
- TotalRecordCount = keys.Count
- };
+ return new QueryResult<AuthenticationInfo>(keys);
}
/// <summary>
diff --git a/Jellyfin.Api/Controllers/ArtistsController.cs b/Jellyfin.Api/Controllers/ArtistsController.cs
index 3df975563..44796bcc4 100644
--- a/Jellyfin.Api/Controllers/ArtistsController.cs
+++ b/Jellyfin.Api/Controllers/ArtistsController.cs
@@ -126,7 +126,7 @@ namespace Jellyfin.Api.Controllers
User? user = null;
BaseItem parentItem = _libraryManager.GetParentItem(parentId, userId);
- if (userId.HasValue && !userId.Equals(Guid.Empty))
+ if (userId.HasValue && !userId.Equals(default))
{
user = _userManager.GetUserById(userId.Value);
}
@@ -243,11 +243,10 @@ namespace Jellyfin.Api.Controllers
return dto;
});
- return new QueryResult<BaseItemDto>
- {
- Items = dtos.ToArray(),
- TotalRecordCount = result.TotalRecordCount
- };
+ return new QueryResult<BaseItemDto>(
+ query.StartIndex,
+ result.TotalRecordCount,
+ dtos.ToArray());
}
/// <summary>
@@ -330,7 +329,7 @@ namespace Jellyfin.Api.Controllers
User? user = null;
BaseItem parentItem = _libraryManager.GetParentItem(parentId, userId);
- if (userId.HasValue && !userId.Equals(Guid.Empty))
+ if (userId.HasValue && !userId.Equals(default))
{
user = _userManager.GetUserById(userId.Value);
}
@@ -447,11 +446,10 @@ namespace Jellyfin.Api.Controllers
return dto;
});
- return new QueryResult<BaseItemDto>
- {
- Items = dtos.ToArray(),
- TotalRecordCount = result.TotalRecordCount
- };
+ return new QueryResult<BaseItemDto>(
+ query.StartIndex,
+ result.TotalRecordCount,
+ dtos.ToArray());
}
/// <summary>
@@ -469,7 +467,7 @@ namespace Jellyfin.Api.Controllers
var item = _libraryManager.GetArtist(name, dtoOptions);
- if (userId.HasValue && !userId.Equals(Guid.Empty))
+ if (userId.HasValue && !userId.Value.Equals(default))
{
var user = _userManager.GetUserById(userId.Value);
diff --git a/Jellyfin.Api/Controllers/ChannelsController.cs b/Jellyfin.Api/Controllers/ChannelsController.cs
index 54bd80095..d5b589a3f 100644
--- a/Jellyfin.Api/Controllers/ChannelsController.cs
+++ b/Jellyfin.Api/Controllers/ChannelsController.cs
@@ -125,9 +125,9 @@ namespace Jellyfin.Api.Controllers
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] sortBy,
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields)
{
- var user = userId.HasValue && !userId.Equals(Guid.Empty)
- ? _userManager.GetUserById(userId.Value)
- : null;
+ var user = userId is null || userId.Value.Equals(default)
+ ? null
+ : _userManager.GetUserById(userId.Value);
var query = new InternalItemsQuery(user)
{
@@ -199,9 +199,9 @@ namespace Jellyfin.Api.Controllers
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields,
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] channelIds)
{
- var user = userId.HasValue && !userId.Equals(Guid.Empty)
- ? _userManager.GetUserById(userId.Value)
- : null;
+ var user = userId is null || userId.Value.Equals(default)
+ ? null
+ : _userManager.GetUserById(userId.Value);
var query = new InternalItemsQuery(user)
{
diff --git a/Jellyfin.Api/Controllers/DisplayPreferencesController.cs b/Jellyfin.Api/Controllers/DisplayPreferencesController.cs
index 0b2604640..27eb22339 100644
--- a/Jellyfin.Api/Controllers/DisplayPreferencesController.cs
+++ b/Jellyfin.Api/Controllers/DisplayPreferencesController.cs
@@ -126,9 +126,11 @@ namespace Jellyfin.Api.Controllers
HomeSectionType.SmallLibraryTiles,
HomeSectionType.Resume,
HomeSectionType.ResumeAudio,
+ HomeSectionType.ResumeBook,
HomeSectionType.LiveTv,
HomeSectionType.NextUp,
- HomeSectionType.LatestMedia, HomeSectionType.None,
+ HomeSectionType.LatestMedia,
+ HomeSectionType.None,
};
if (!Guid.TryParse(displayPreferencesId, out var itemId))
@@ -182,7 +184,7 @@ namespace Jellyfin.Api.Controllers
var order = int.Parse(key.AsSpan().Slice("homesection".Length));
if (!Enum.TryParse<HomeSectionType>(displayPreferences.CustomPrefs[key], true, out var type))
{
- type = order < 7 ? defaults[order] : HomeSectionType.None;
+ type = order < 8 ? defaults[order] : HomeSectionType.None;
}
displayPreferences.CustomPrefs.Remove(key);
diff --git a/Jellyfin.Api/Controllers/DynamicHlsController.cs b/Jellyfin.Api/Controllers/DynamicHlsController.cs
index 6ef3a2ff9..f8e8d975c 100644
--- a/Jellyfin.Api/Controllers/DynamicHlsController.cs
+++ b/Jellyfin.Api/Controllers/DynamicHlsController.cs
@@ -13,6 +13,7 @@ using Jellyfin.Api.Constants;
using Jellyfin.Api.Helpers;
using Jellyfin.Api.Models.PlaybackDtos;
using Jellyfin.Api.Models.StreamingDtos;
+using Jellyfin.MediaEncoding.Hls.Playlist;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Devices;
@@ -28,7 +29,6 @@ using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
-using Microsoft.Net.Http.Headers;
namespace Jellyfin.Api.Controllers
{
@@ -55,6 +55,7 @@ namespace Jellyfin.Api.Controllers
private readonly TranscodingJobHelper _transcodingJobHelper;
private readonly ILogger<DynamicHlsController> _logger;
private readonly EncodingHelper _encodingHelper;
+ private readonly IDynamicHlsPlaylistGenerator _dynamicHlsPlaylistGenerator;
private readonly DynamicHlsHelper _dynamicHlsHelper;
private readonly EncodingOptions _encodingOptions;
@@ -74,6 +75,7 @@ namespace Jellyfin.Api.Controllers
/// <param name="logger">Instance of the <see cref="ILogger{DynamicHlsController}"/> interface.</param>
/// <param name="dynamicHlsHelper">Instance of <see cref="DynamicHlsHelper"/>.</param>
/// <param name="encodingHelper">Instance of <see cref="EncodingHelper"/>.</param>
+ /// <param name="dynamicHlsPlaylistGenerator">Instance of <see cref="IDynamicHlsPlaylistGenerator"/>.</param>
public DynamicHlsController(
ILibraryManager libraryManager,
IUserManager userManager,
@@ -87,7 +89,8 @@ namespace Jellyfin.Api.Controllers
TranscodingJobHelper transcodingJobHelper,
ILogger<DynamicHlsController> logger,
DynamicHlsHelper dynamicHlsHelper,
- EncodingHelper encodingHelper)
+ EncodingHelper encodingHelper,
+ IDynamicHlsPlaylistGenerator dynamicHlsPlaylistGenerator)
{
_libraryManager = libraryManager;
_userManager = userManager;
@@ -102,6 +105,7 @@ namespace Jellyfin.Api.Controllers
_logger = logger;
_dynamicHlsHelper = dynamicHlsHelper;
_encodingHelper = encodingHelper;
+ _dynamicHlsPlaylistGenerator = dynamicHlsPlaylistGenerator;
_encodingOptions = serverConfigurationManager.GetEncodingOptions();
}
@@ -385,6 +389,8 @@ namespace Jellyfin.Api.Controllers
/// <param name="startTimeTicks">Optional. Specify a starting offset, in ticks. 1 tick = 10000 ms.</param>
/// <param name="width">Optional. The fixed horizontal resolution of the encoded video.</param>
/// <param name="height">Optional. The fixed vertical resolution of the encoded video.</param>
+ /// <param name="maxWidth">Optional. The maximum horizontal resolution of the encoded video.</param>
+ /// <param name="maxHeight">Optional. The maximum vertical resolution of the encoded video.</param>
/// <param name="videoBitRate">Optional. Specify a video bitrate to encode to, e.g. 500000. If omitted this will be left to encoder defaults.</param>
/// <param name="subtitleStreamIndex">Optional. The index of the subtitle stream to use. If omitted no subtitles will be used.</param>
/// <param name="subtitleMethod">Optional. Specify the subtitle delivery method.</param>
@@ -441,6 +447,8 @@ namespace Jellyfin.Api.Controllers
[FromQuery] long? startTimeTicks,
[FromQuery] int? width,
[FromQuery] int? height,
+ [FromQuery] int? maxWidth,
+ [FromQuery] int? maxHeight,
[FromQuery] int? videoBitRate,
[FromQuery] int? subtitleStreamIndex,
[FromQuery] SubtitleDeliveryMethod? subtitleMethod,
@@ -493,6 +501,8 @@ namespace Jellyfin.Api.Controllers
StartTimeTicks = startTimeTicks,
Width = width,
Height = height,
+ MaxWidth = maxWidth,
+ MaxHeight = maxHeight,
VideoBitRate = videoBitRate,
SubtitleStreamIndex = subtitleStreamIndex,
SubtitleMethod = subtitleMethod ?? SubtitleDeliveryMethod.Encode,
@@ -717,6 +727,8 @@ namespace Jellyfin.Api.Controllers
/// <param name="startTimeTicks">Optional. Specify a starting offset, in ticks. 1 tick = 10000 ms.</param>
/// <param name="width">Optional. The fixed horizontal resolution of the encoded video.</param>
/// <param name="height">Optional. The fixed vertical resolution of the encoded video.</param>
+ /// <param name="maxWidth">Optional. The maximum horizontal resolution of the encoded video.</param>
+ /// <param name="maxHeight">Optional. The maximum vertical resolution of the encoded video.</param>
/// <param name="videoBitRate">Optional. Specify a video bitrate to encode to, e.g. 500000. If omitted this will be left to encoder defaults.</param>
/// <param name="subtitleStreamIndex">Optional. The index of the subtitle stream to use. If omitted no subtitles will be used.</param>
/// <param name="subtitleMethod">Optional. Specify the subtitle delivery method.</param>
@@ -771,6 +783,8 @@ namespace Jellyfin.Api.Controllers
[FromQuery] long? startTimeTicks,
[FromQuery] int? width,
[FromQuery] int? height,
+ [FromQuery] int? maxWidth,
+ [FromQuery] int? maxHeight,
[FromQuery] int? videoBitRate,
[FromQuery] int? subtitleStreamIndex,
[FromQuery] SubtitleDeliveryMethod? subtitleMethod,
@@ -823,6 +837,8 @@ namespace Jellyfin.Api.Controllers
StartTimeTicks = startTimeTicks,
Width = width,
Height = height,
+ MaxWidth = maxWidth,
+ MaxHeight = maxHeight,
VideoBitRate = videoBitRate,
SubtitleStreamIndex = subtitleStreamIndex,
SubtitleMethod = subtitleMethod ?? SubtitleDeliveryMethod.Encode,
@@ -844,7 +860,7 @@ namespace Jellyfin.Api.Controllers
StreamOptions = streamOptions
};
- return await GetVariantPlaylistInternal(streamingRequest, "main", cancellationTokenSource)
+ return await GetVariantPlaylistInternal(streamingRequest, cancellationTokenSource)
.ConfigureAwait(false);
}
@@ -1009,7 +1025,7 @@ namespace Jellyfin.Api.Controllers
StreamOptions = streamOptions
};
- return await GetVariantPlaylistInternal(streamingRequest, "main", cancellationTokenSource)
+ return await GetVariantPlaylistInternal(streamingRequest, cancellationTokenSource)
.ConfigureAwait(false);
}
@@ -1020,13 +1036,15 @@ namespace Jellyfin.Api.Controllers
/// <param name="playlistId">The playlist id.</param>
/// <param name="segmentId">The segment id.</param>
/// <param name="container">The video container. Possible values are: ts, webm, asf, wmv, ogv, mp4, m4v, mkv, mpeg, mpg, avi, 3gp, wmv, wtv, m2ts, mov, iso, flv. </param>
+ /// <param name="runtimeTicks">The position of the requested segment in ticks.</param>
+ /// <param name="actualSegmentLengthTicks">The length of the requested segment in ticks.</param>
/// <param name="static">Optional. If true, the original file will be streamed statically without any encoding. Use either no url extension or the original file extension. true/false.</param>
/// <param name="params">The streaming parameters.</param>
/// <param name="tag">The tag.</param>
/// <param name="deviceProfileId">Optional. The dlna device profile id to utilize.</param>
/// <param name="playSessionId">The play session id.</param>
/// <param name="segmentContainer">The segment container.</param>
- /// <param name="segmentLength">The segment lenght.</param>
+ /// <param name="segmentLength">The desired segment length.</param>
/// <param name="minSegments">The minimum number of segments.</param>
/// <param name="mediaSourceId">The media version id, if playing an alternate version.</param>
/// <param name="deviceId">The device id of the client requesting. Used to stop encoding processes when needed.</param>
@@ -1048,6 +1066,8 @@ namespace Jellyfin.Api.Controllers
/// <param name="startTimeTicks">Optional. Specify a starting offset, in ticks. 1 tick = 10000 ms.</param>
/// <param name="width">Optional. The fixed horizontal resolution of the encoded video.</param>
/// <param name="height">Optional. The fixed vertical resolution of the encoded video.</param>
+ /// <param name="maxWidth">Optional. The maximum horizontal resolution of the encoded video.</param>
+ /// <param name="maxHeight">Optional. The maximum vertical resolution of the encoded video.</param>
/// <param name="videoBitRate">Optional. Specify a video bitrate to encode to, e.g. 500000. If omitted this will be left to encoder defaults.</param>
/// <param name="subtitleStreamIndex">Optional. The index of the subtitle stream to use. If omitted no subtitles will be used.</param>
/// <param name="subtitleMethod">Optional. Specify the subtitle delivery method.</param>
@@ -1078,6 +1098,8 @@ namespace Jellyfin.Api.Controllers
[FromRoute, Required] string playlistId,
[FromRoute, Required] int segmentId,
[FromRoute, Required] string container,
+ [FromQuery, Required] long runtimeTicks,
+ [FromQuery, Required] long actualSegmentLengthTicks,
[FromQuery] bool? @static,
[FromQuery] string? @params,
[FromQuery] string? tag,
@@ -1106,6 +1128,8 @@ namespace Jellyfin.Api.Controllers
[FromQuery] long? startTimeTicks,
[FromQuery] int? width,
[FromQuery] int? height,
+ [FromQuery] int? maxWidth,
+ [FromQuery] int? maxHeight,
[FromQuery] int? videoBitRate,
[FromQuery] int? subtitleStreamIndex,
[FromQuery] SubtitleDeliveryMethod? subtitleMethod,
@@ -1129,6 +1153,8 @@ namespace Jellyfin.Api.Controllers
var streamingRequest = new VideoRequestDto
{
Id = itemId,
+ CurrentRuntimeTicks = runtimeTicks,
+ ActualSegmentLengthTicks = actualSegmentLengthTicks,
Container = container,
Static = @static ?? false,
Params = @params,
@@ -1158,6 +1184,8 @@ namespace Jellyfin.Api.Controllers
StartTimeTicks = startTimeTicks,
Width = width,
Height = height,
+ MaxWidth = maxWidth,
+ MaxHeight = maxHeight,
VideoBitRate = videoBitRate,
SubtitleStreamIndex = subtitleStreamIndex,
SubtitleMethod = subtitleMethod ?? SubtitleDeliveryMethod.Encode,
@@ -1190,6 +1218,8 @@ namespace Jellyfin.Api.Controllers
/// <param name="playlistId">The playlist id.</param>
/// <param name="segmentId">The segment id.</param>
/// <param name="container">The video container. Possible values are: ts, webm, asf, wmv, ogv, mp4, m4v, mkv, mpeg, mpg, avi, 3gp, wmv, wtv, m2ts, mov, iso, flv. </param>
+ /// <param name="runtimeTicks">The position of the requested segment in ticks.</param>
+ /// <param name="actualSegmentLengthTicks">The length of the requested segment in ticks.</param>
/// <param name="static">Optional. If true, the original file will be streamed statically without any encoding. Use either no url extension or the original file extension. true/false.</param>
/// <param name="params">The streaming parameters.</param>
/// <param name="tag">The tag.</param>
@@ -1249,6 +1279,8 @@ namespace Jellyfin.Api.Controllers
[FromRoute, Required] string playlistId,
[FromRoute, Required] int segmentId,
[FromRoute, Required] string container,
+ [FromQuery, Required] long runtimeTicks,
+ [FromQuery, Required] long actualSegmentLengthTicks,
[FromQuery] bool? @static,
[FromQuery] string? @params,
[FromQuery] string? tag,
@@ -1302,6 +1334,8 @@ namespace Jellyfin.Api.Controllers
{
Id = itemId,
Container = container,
+ CurrentRuntimeTicks = runtimeTicks,
+ ActualSegmentLengthTicks = actualSegmentLengthTicks,
Static = @static ?? false,
Params = @params,
Tag = tag,
@@ -1355,7 +1389,7 @@ namespace Jellyfin.Api.Controllers
.ConfigureAwait(false);
}
- private async Task<ActionResult> GetVariantPlaylistInternal(StreamingRequestDto streamingRequest, string name, CancellationTokenSource cancellationTokenSource)
+ private async Task<ActionResult> GetVariantPlaylistInternal(StreamingRequestDto streamingRequest, CancellationTokenSource cancellationTokenSource)
{
using var state = await StreamingHelpers.GetStreamingState(
streamingRequest,
@@ -1374,60 +1408,16 @@ namespace Jellyfin.Api.Controllers
cancellationTokenSource.Token)
.ConfigureAwait(false);
- Response.Headers.Add(HeaderNames.Expires, "0");
-
- var segmentLengths = GetSegmentLengths(state);
-
- var segmentContainer = state.Request.SegmentContainer ?? "ts";
-
- // http://ffmpeg.org/ffmpeg-all.html#toc-hls-2
- var isHlsInFmp4 = string.Equals(segmentContainer, "mp4", StringComparison.OrdinalIgnoreCase);
- var hlsVersion = isHlsInFmp4 ? "7" : "3";
-
- var builder = new StringBuilder(128);
-
- builder.AppendLine("#EXTM3U")
- .AppendLine("#EXT-X-PLAYLIST-TYPE:VOD")
- .Append("#EXT-X-VERSION:")
- .Append(hlsVersion)
- .AppendLine()
- .Append("#EXT-X-TARGETDURATION:")
- .Append(Math.Ceiling(segmentLengths.Length > 0 ? segmentLengths.Max() : state.SegmentLength))
- .AppendLine()
- .AppendLine("#EXT-X-MEDIA-SEQUENCE:0");
-
- var index = 0;
- var segmentExtension = EncodingHelper.GetSegmentFileExtension(streamingRequest.SegmentContainer);
- var queryString = Request.QueryString;
-
- if (isHlsInFmp4)
- {
- builder.Append("#EXT-X-MAP:URI=\"")
- .Append("hls1/")
- .Append(name)
- .Append("/-1")
- .Append(segmentExtension)
- .Append(queryString)
- .Append('"')
- .AppendLine();
- }
-
- foreach (var length in segmentLengths)
- {
- builder.Append("#EXTINF:")
- .Append(length.ToString("0.0000", CultureInfo.InvariantCulture))
- .AppendLine(", nodesc")
- .Append("hls1/")
- .Append(name)
- .Append('/')
- .Append(index++)
- .Append(segmentExtension)
- .Append(queryString)
- .AppendLine();
- }
+ var request = new CreateMainPlaylistRequest(
+ state.MediaPath,
+ state.SegmentLength * 1000,
+ state.RunTimeTicks ?? 0,
+ state.Request.SegmentContainer ?? string.Empty,
+ "hls1/main/",
+ Request.QueryString.ToString());
+ var playlist = _dynamicHlsPlaylistGenerator.CreateMainPlaylist(request);
- builder.AppendLine("#EXT-X-ENDLIST");
- return new FileContentResult(Encoding.UTF8.GetBytes(builder.ToString()), MimeTypes.GetMimeType("playlist.m3u8"));
+ return new FileContentResult(Encoding.UTF8.GetBytes(playlist), MimeTypes.GetMimeType("playlist.m3u8"));
}
private async Task<ActionResult> GetDynamicSegment(StreamingRequestDto streamingRequest, int segmentId)
@@ -1528,7 +1518,7 @@ namespace Jellyfin.Api.Controllers
DeleteLastFile(playlistPath, segmentExtension, 0);
}
- streamingRequest.StartTimeTicks = GetStartPositionTicks(state, segmentId);
+ streamingRequest.StartTimeTicks = streamingRequest.CurrentRuntimeTicks;
state.WaitForPath = segmentPath;
job = await _transcodingJobHelper.StartFfMpeg(
@@ -1609,7 +1599,6 @@ namespace Jellyfin.Api.Controllers
state.BaseRequest.BreakOnNonKeyFrames = false;
}
- var inputModifier = _encodingHelper.GetInputModifier(state, _encodingOptions);
var mapArgs = state.IsOutputVideo ? _encodingHelper.GetMapArgs(state) : string.Empty;
var directory = Path.GetDirectoryName(outputPath) ?? throw new ArgumentException($"Provided path ({outputPath}) is not valid.", nameof(outputPath));
@@ -1618,12 +1607,15 @@ namespace Jellyfin.Api.Controllers
var outputExtension = EncodingHelper.GetSegmentFileExtension(state.Request.SegmentContainer);
var outputTsArg = outputPrefix + "%d" + outputExtension;
- var segmentFormat = outputExtension.TrimStart('.');
- if (string.Equals(segmentFormat, "ts", StringComparison.OrdinalIgnoreCase))
+ var segmentFormat = string.Empty;
+ var segmentContainer = outputExtension.TrimStart('.');
+ var inputModifier = _encodingHelper.GetInputModifier(state, _encodingOptions, segmentContainer);
+
+ if (string.Equals(segmentContainer, "ts", StringComparison.OrdinalIgnoreCase))
{
segmentFormat = "mpegts";
}
- else if (string.Equals(segmentFormat, "mp4", StringComparison.OrdinalIgnoreCase))
+ else if (string.Equals(segmentContainer, "mp4", StringComparison.OrdinalIgnoreCase))
{
var outputFmp4HeaderArg = OperatingSystem.IsWindows() switch
{
@@ -1637,7 +1629,8 @@ namespace Jellyfin.Api.Controllers
}
else
{
- _logger.LogError("Invalid HLS segment container: {SegmentFormat}", segmentFormat);
+ _logger.LogError("Invalid HLS segment container: {SegmentContainer}, default to mpegts", segmentContainer);
+ segmentFormat = "mpegts";
}
var maxMuxingQueueSize = _encodingOptions.MaxMuxingQueueSize > 128
@@ -1657,7 +1650,7 @@ namespace Jellyfin.Api.Controllers
CultureInfo.InvariantCulture,
"{0} {1} -map_metadata -1 -map_chapters -1 -threads {2} {3} {4} {5} -copyts -avoid_negative_ts disabled -max_muxing_queue_size {6} -f hls -max_delay 5000000 -hls_time {7} -hls_segment_type {8} -start_number {9}{10} -hls_segment_filename \"{12}\" -hls_playlist_type {11} -hls_list_size 0 -y \"{13}\"",
inputModifier,
- _encodingHelper.GetInputArgument(state, _encodingOptions),
+ _encodingHelper.GetInputArgument(state, _encodingOptions, segmentContainer),
threads,
mapArgs,
GetVideoArguments(state, startNumber, isEventPlaylist),
@@ -1879,7 +1872,7 @@ namespace Jellyfin.Api.Controllers
{
// Transcoding job is over, so assume all existing files are ready
_logger.LogDebug("serving up {0} as transcode is over", segmentPath);
- return GetSegmentResult(state, segmentPath, segmentIndex, transcodingJob);
+ return GetSegmentResult(state, segmentPath, transcodingJob);
}
var currentTranscodingIndex = GetCurrentTranscodingIndex(playlistPath, segmentExtension);
@@ -1888,7 +1881,7 @@ namespace Jellyfin.Api.Controllers
if (segmentIndex < currentTranscodingIndex)
{
_logger.LogDebug("serving up {0} as transcode index {1} is past requested point {2}", segmentPath, currentTranscodingIndex, segmentIndex);
- return GetSegmentResult(state, segmentPath, segmentIndex, transcodingJob);
+ return GetSegmentResult(state, segmentPath, transcodingJob);
}
}
@@ -1903,8 +1896,8 @@ namespace Jellyfin.Api.Controllers
{
if (transcodingJob.HasExited || System.IO.File.Exists(nextSegmentPath))
{
- _logger.LogDebug("serving up {0} as it deemed ready", segmentPath);
- return GetSegmentResult(state, segmentPath, segmentIndex, transcodingJob);
+ _logger.LogDebug("Serving up {SegmentPath} as it deemed ready", segmentPath);
+ return GetSegmentResult(state, segmentPath, transcodingJob);
}
}
else
@@ -1935,16 +1928,16 @@ namespace Jellyfin.Api.Controllers
_logger.LogWarning("cannot serve {0} as it doesn't exist and no transcode is running", segmentPath);
}
- return GetSegmentResult(state, segmentPath, segmentIndex, transcodingJob);
+ return GetSegmentResult(state, segmentPath, transcodingJob);
}
- private ActionResult GetSegmentResult(StreamState state, string segmentPath, int index, TranscodingJobDto? transcodingJob)
+ private ActionResult GetSegmentResult(StreamState state, string segmentPath, TranscodingJobDto? transcodingJob)
{
- var segmentEndingPositionTicks = GetEndPositionTicks(state, index);
+ var segmentEndingPositionTicks = state.Request.CurrentRuntimeTicks + state.Request.ActualSegmentLengthTicks;
Response.OnCompleted(() =>
{
- _logger.LogDebug("finished serving {0}", segmentPath);
+ _logger.LogDebug("Finished serving {SegmentPath}", segmentPath);
if (transcodingJob != null)
{
transcodingJob.DownloadPositionTicks = Math.Max(transcodingJob.DownloadPositionTicks ?? segmentEndingPositionTicks, segmentEndingPositionTicks);
@@ -1954,30 +1947,7 @@ namespace Jellyfin.Api.Controllers
return Task.CompletedTask;
});
- return FileStreamResponseHelpers.GetStaticFileResult(segmentPath, MimeTypes.GetMimeType(segmentPath), false, HttpContext);
- }
-
- private long GetEndPositionTicks(StreamState state, int requestedIndex)
- {
- double startSeconds = 0;
- var lengths = GetSegmentLengths(state);
-
- if (requestedIndex >= lengths.Length)
- {
- var msg = string.Format(
- CultureInfo.InvariantCulture,
- "Invalid segment index requested: {0} - Segment count: {1}",
- requestedIndex,
- lengths.Length);
- throw new ArgumentException(msg);
- }
-
- for (var i = 0; i <= requestedIndex; i++)
- {
- startSeconds += lengths[i];
- }
-
- return TimeSpan.FromSeconds(startSeconds).Ticks;
+ return FileStreamResponseHelpers.GetStaticFileResult(segmentPath, MimeTypes.GetMimeType(segmentPath));
}
private int? GetCurrentTranscodingIndex(string playlist, string segmentExtension)
@@ -2058,29 +2028,5 @@ namespace Jellyfin.Api.Controllers
_logger.LogError(ex, "Error deleting partial stream file(s) {Path}", path);
}
}
-
- private long GetStartPositionTicks(StreamState state, int requestedIndex)
- {
- double startSeconds = 0;
- var lengths = GetSegmentLengths(state);
-
- if (requestedIndex >= lengths.Length)
- {
- var msg = string.Format(
- CultureInfo.InvariantCulture,
- "Invalid segment index requested: {0} - Segment count: {1}",
- requestedIndex,
- lengths.Length);
- throw new ArgumentException(msg);
- }
-
- for (var i = 0; i < requestedIndex; i++)
- {
- startSeconds += lengths[i];
- }
-
- var position = TimeSpan.FromSeconds(startSeconds).Ticks;
- return position;
- }
}
}
diff --git a/Jellyfin.Api/Controllers/FilterController.cs b/Jellyfin.Api/Controllers/FilterController.cs
index a4f12666d..11808b1b8 100644
--- a/Jellyfin.Api/Controllers/FilterController.cs
+++ b/Jellyfin.Api/Controllers/FilterController.cs
@@ -52,9 +52,9 @@ namespace Jellyfin.Api.Controllers
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] BaseItemKind[] includeItemTypes,
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] mediaTypes)
{
- var user = userId.HasValue && !userId.Equals(Guid.Empty)
- ? _userManager.GetUserById(userId.Value)
- : null;
+ var user = userId is null || userId.Value.Equals(default)
+ ? null
+ : _userManager.GetUserById(userId.Value);
BaseItem? item = null;
if (includeItemTypes.Length != 1
@@ -144,9 +144,9 @@ namespace Jellyfin.Api.Controllers
[FromQuery] bool? isSeries,
[FromQuery] bool? recursive)
{
- var user = userId.HasValue && !userId.Equals(Guid.Empty)
- ? _userManager.GetUserById(userId.Value)
- : null;
+ var user = userId is null || userId.Value.Equals(default)
+ ? null
+ : _userManager.GetUserById(userId.Value);
BaseItem? parentItem = null;
if (includeItemTypes.Length == 1
diff --git a/Jellyfin.Api/Controllers/GenresController.cs b/Jellyfin.Api/Controllers/GenresController.cs
index 37e6ae184..e28a50750 100644
--- a/Jellyfin.Api/Controllers/GenresController.cs
+++ b/Jellyfin.Api/Controllers/GenresController.cs
@@ -95,7 +95,9 @@ namespace Jellyfin.Api.Controllers
.AddClientFields(Request)
.AddAdditionalDtoOptions(enableImages, false, imageTypeLimit, enableImageTypes);
- User? user = userId.HasValue && userId != Guid.Empty ? _userManager.GetUserById(userId.Value) : null;
+ User? user = userId is null || userId.Value.Equals(default)
+ ? null
+ : _userManager.GetUserById(userId.Value);
var parentItem = _libraryManager.GetParentItem(parentId, userId);
@@ -157,29 +159,26 @@ namespace Jellyfin.Api.Controllers
var dtoOptions = new DtoOptions()
.AddClientFields(Request);
- Genre item = new Genre();
- if (genreName.IndexOf(BaseItem.SlugChar, StringComparison.OrdinalIgnoreCase) != -1)
+ Genre? item;
+ if (genreName.Contains(BaseItem.SlugChar, StringComparison.OrdinalIgnoreCase))
{
- var result = GetItemFromSlugName<Genre>(_libraryManager, genreName, dtoOptions, BaseItemKind.Genre);
-
- if (result != null)
- {
- item = result;
- }
+ item = GetItemFromSlugName<Genre>(_libraryManager, genreName, dtoOptions, BaseItemKind.Genre);
}
else
{
item = _libraryManager.GetGenre(genreName);
}
- if (userId.HasValue && !userId.Equals(Guid.Empty))
- {
- var user = _userManager.GetUserById(userId.Value);
+ item ??= new Genre();
- return _dtoService.GetBaseItemDto(item, dtoOptions, user);
+ if (userId is null || userId.Value.Equals(default))
+ {
+ return _dtoService.GetBaseItemDto(item, dtoOptions);
}
- return _dtoService.GetBaseItemDto(item, dtoOptions);
+ var user = _userManager.GetUserById(userId.Value);
+
+ return _dtoService.GetBaseItemDto(item, dtoOptions, user);
}
private T? GetItemFromSlugName<T>(ILibraryManager libraryManager, string name, DtoOptions dtoOptions, BaseItemKind baseItemKind)
diff --git a/Jellyfin.Api/Controllers/HlsSegmentController.cs b/Jellyfin.Api/Controllers/HlsSegmentController.cs
index 7325dca0a..78634f0bf 100644
--- a/Jellyfin.Api/Controllers/HlsSegmentController.cs
+++ b/Jellyfin.Api/Controllers/HlsSegmentController.cs
@@ -69,7 +69,7 @@ namespace Jellyfin.Api.Controllers
return BadRequest("Invalid segment.");
}
- return FileStreamResponseHelpers.GetStaticFileResult(file, MimeTypes.GetMimeType(file), false, HttpContext);
+ return FileStreamResponseHelpers.GetStaticFileResult(file, MimeTypes.GetMimeType(file));
}
/// <summary>
@@ -186,7 +186,7 @@ namespace Jellyfin.Api.Controllers
return Task.CompletedTask;
});
- return FileStreamResponseHelpers.GetStaticFileResult(path, MimeTypes.GetMimeType(path), false, HttpContext);
+ return FileStreamResponseHelpers.GetStaticFileResult(path, MimeTypes.GetMimeType(path));
}
}
}
diff --git a/Jellyfin.Api/Controllers/ImageController.cs b/Jellyfin.Api/Controllers/ImageController.cs
index e72589cfa..05d80ba35 100644
--- a/Jellyfin.Api/Controllers/ImageController.cs
+++ b/Jellyfin.Api/Controllers/ImageController.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Collections.Immutable;
using System.ComponentModel.DataAnnotations;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
@@ -11,12 +12,14 @@ using System.Threading.Tasks;
using Jellyfin.Api.Attributes;
using Jellyfin.Api.Constants;
using Jellyfin.Api.Helpers;
+using MediaBrowser.Common.Configuration;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Drawing;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Net;
using MediaBrowser.Controller.Providers;
+using MediaBrowser.Model.Branding;
using MediaBrowser.Model.Drawing;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
@@ -44,6 +47,8 @@ namespace Jellyfin.Api.Controllers
private readonly IAuthorizationContext _authContext;
private readonly ILogger<ImageController> _logger;
private readonly IServerConfigurationManager _serverConfigurationManager;
+ private readonly IApplicationPaths _appPaths;
+ private readonly IImageEncoder _imageEncoder;
/// <summary>
/// Initializes a new instance of the <see cref="ImageController"/> class.
@@ -56,6 +61,8 @@ namespace Jellyfin.Api.Controllers
/// <param name="authContext">Instance of the <see cref="IAuthorizationContext"/> interface.</param>
/// <param name="logger">Instance of the <see cref="ILogger{ImageController}"/> interface.</param>
/// <param name="serverConfigurationManager">Instance of the <see cref="IServerConfigurationManager"/> interface.</param>
+ /// <param name="appPaths">Instance of the <see cref="IApplicationPaths"/> interface.</param>
+ /// <param name="imageEncoder">Instance of the <see cref="IImageEncoder"/> interface.</param>
public ImageController(
IUserManager userManager,
ILibraryManager libraryManager,
@@ -64,7 +71,9 @@ namespace Jellyfin.Api.Controllers
IFileSystem fileSystem,
IAuthorizationContext authContext,
ILogger<ImageController> logger,
- IServerConfigurationManager serverConfigurationManager)
+ IServerConfigurationManager serverConfigurationManager,
+ IApplicationPaths appPaths,
+ IImageEncoder imageEncoder)
{
_userManager = userManager;
_libraryManager = libraryManager;
@@ -74,6 +83,8 @@ namespace Jellyfin.Api.Controllers
_authContext = authContext;
_logger = logger;
_serverConfigurationManager = serverConfigurationManager;
+ _appPaths = appPaths;
+ _imageEncoder = imageEncoder;
}
/// <summary>
@@ -559,8 +570,7 @@ namespace Jellyfin.Api.Controllers
blur,
backgroundColor,
foregroundLayer,
- item,
- Request.Method.Equals(HttpMethods.Head, StringComparison.OrdinalIgnoreCase))
+ item)
.ConfigureAwait(false);
}
@@ -643,8 +653,7 @@ namespace Jellyfin.Api.Controllers
blur,
backgroundColor,
foregroundLayer,
- item,
- Request.Method.Equals(HttpMethods.Head, StringComparison.OrdinalIgnoreCase))
+ item)
.ConfigureAwait(false);
}
@@ -727,8 +736,7 @@ namespace Jellyfin.Api.Controllers
blur,
backgroundColor,
foregroundLayer,
- item,
- Request.Method.Equals(HttpMethods.Head, StringComparison.OrdinalIgnoreCase))
+ item)
.ConfigureAwait(false);
}
@@ -811,8 +819,7 @@ namespace Jellyfin.Api.Controllers
blur,
backgroundColor,
foregroundLayer,
- item,
- Request.Method.Equals(HttpMethods.Head, StringComparison.OrdinalIgnoreCase))
+ item)
.ConfigureAwait(false);
}
@@ -895,8 +902,7 @@ namespace Jellyfin.Api.Controllers
blur,
backgroundColor,
foregroundLayer,
- item,
- Request.Method.Equals(HttpMethods.Head, StringComparison.OrdinalIgnoreCase))
+ item)
.ConfigureAwait(false);
}
@@ -979,8 +985,7 @@ namespace Jellyfin.Api.Controllers
blur,
backgroundColor,
foregroundLayer,
- item,
- Request.Method.Equals(HttpMethods.Head, StringComparison.OrdinalIgnoreCase))
+ item)
.ConfigureAwait(false);
}
@@ -1063,8 +1068,7 @@ namespace Jellyfin.Api.Controllers
blur,
backgroundColor,
foregroundLayer,
- item,
- Request.Method.Equals(HttpMethods.Head, StringComparison.OrdinalIgnoreCase))
+ item)
.ConfigureAwait(false);
}
@@ -1147,8 +1151,7 @@ namespace Jellyfin.Api.Controllers
blur,
backgroundColor,
foregroundLayer,
- item,
- Request.Method.Equals(HttpMethods.Head, StringComparison.OrdinalIgnoreCase))
+ item)
.ConfigureAwait(false);
}
@@ -1231,8 +1234,7 @@ namespace Jellyfin.Api.Controllers
blur,
backgroundColor,
foregroundLayer,
- item,
- Request.Method.Equals(HttpMethods.Head, StringComparison.OrdinalIgnoreCase))
+ item)
.ConfigureAwait(false);
}
@@ -1315,8 +1317,7 @@ namespace Jellyfin.Api.Controllers
blur,
backgroundColor,
foregroundLayer,
- item,
- Request.Method.Equals(HttpMethods.Head, StringComparison.OrdinalIgnoreCase))
+ item)
.ConfigureAwait(false);
}
@@ -1399,8 +1400,7 @@ namespace Jellyfin.Api.Controllers
blur,
backgroundColor,
foregroundLayer,
- item,
- Request.Method.Equals(HttpMethods.Head, StringComparison.OrdinalIgnoreCase))
+ item)
.ConfigureAwait(false);
}
@@ -1483,8 +1483,7 @@ namespace Jellyfin.Api.Controllers
blur,
backgroundColor,
foregroundLayer,
- item,
- Request.Method.Equals(HttpMethods.Head, StringComparison.OrdinalIgnoreCase))
+ item)
.ConfigureAwait(false);
}
@@ -1585,7 +1584,6 @@ namespace Jellyfin.Api.Controllers
backgroundColor,
foregroundLayer,
null,
- Request.Method.Equals(HttpMethods.Head, StringComparison.OrdinalIgnoreCase),
info)
.ConfigureAwait(false);
}
@@ -1687,11 +1685,133 @@ namespace Jellyfin.Api.Controllers
backgroundColor,
foregroundLayer,
null,
- Request.Method.Equals(HttpMethods.Head, StringComparison.OrdinalIgnoreCase),
info)
.ConfigureAwait(false);
}
+ /// <summary>
+ /// Generates or gets the splashscreen.
+ /// </summary>
+ /// <param name="tag">Supply the cache tag from the item object to receive strong caching headers.</param>
+ /// <param name="format">Determines the output format of the image - original,gif,jpg,png.</param>
+ /// <param name="maxWidth">The maximum image width to return.</param>
+ /// <param name="maxHeight">The maximum image height to return.</param>
+ /// <param name="width">The fixed image width to return.</param>
+ /// <param name="height">The fixed image height to return.</param>
+ /// <param name="fillWidth">Width of box to fill.</param>
+ /// <param name="fillHeight">Height of box to fill.</param>
+ /// <param name="blur">Blur image.</param>
+ /// <param name="backgroundColor">Apply a background color for transparent images.</param>
+ /// <param name="foregroundLayer">Apply a foreground layer on top of the image.</param>
+ /// <param name="quality">Quality setting, from 0-100.</param>
+ /// <response code="200">Splashscreen returned successfully.</response>
+ /// <returns>The splashscreen.</returns>
+ [HttpGet("Branding/Splashscreen")]
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ [ProducesImageFile]
+ public async Task<ActionResult> GetSplashscreen(
+ [FromQuery] string? tag,
+ [FromQuery] ImageFormat? format,
+ [FromQuery] int? maxWidth,
+ [FromQuery] int? maxHeight,
+ [FromQuery] int? width,
+ [FromQuery] int? height,
+ [FromQuery] int? fillWidth,
+ [FromQuery] int? fillHeight,
+ [FromQuery] int? blur,
+ [FromQuery] string? backgroundColor,
+ [FromQuery] string? foregroundLayer,
+ [FromQuery, Range(0, 100)] int quality = 90)
+ {
+ var brandingOptions = _serverConfigurationManager.GetConfiguration<BrandingOptions>("branding");
+ string splashscreenPath;
+
+ if (!string.IsNullOrWhiteSpace(brandingOptions.SplashscreenLocation)
+ && System.IO.File.Exists(brandingOptions.SplashscreenLocation))
+ {
+ splashscreenPath = brandingOptions.SplashscreenLocation;
+ }
+ else
+ {
+ splashscreenPath = Path.Combine(_appPaths.DataPath, "splashscreen.png");
+ if (!System.IO.File.Exists(splashscreenPath))
+ {
+ return NotFound();
+ }
+ }
+
+ var outputFormats = GetOutputFormats(format);
+
+ TimeSpan? cacheDuration = null;
+ if (!string.IsNullOrEmpty(tag))
+ {
+ cacheDuration = TimeSpan.FromDays(365);
+ }
+
+ var options = new ImageProcessingOptions
+ {
+ Image = new ItemImageInfo
+ {
+ Path = splashscreenPath
+ },
+ Height = height,
+ MaxHeight = maxHeight,
+ MaxWidth = maxWidth,
+ FillHeight = fillHeight,
+ FillWidth = fillWidth,
+ Quality = quality,
+ Width = width,
+ Blur = blur,
+ BackgroundColor = backgroundColor,
+ ForegroundLayer = foregroundLayer,
+ SupportedOutputFormats = outputFormats
+ };
+
+ return await GetImageResult(
+ options,
+ cacheDuration,
+ ImmutableDictionary<string, string>.Empty)
+ .ConfigureAwait(false);
+ }
+
+ /// <summary>
+ /// Uploads a custom splashscreen.
+ /// </summary>
+ /// <returns>A <see cref="NoContentResult"/> indicating success.</returns>
+ /// <response code="204">Successfully uploaded new splashscreen.</response>
+ /// <response code="400">Error reading MimeType from uploaded image.</response>
+ /// <response code="403">User does not have permission to upload splashscreen..</response>
+ /// <exception cref="ArgumentException">Error reading the image format.</exception>
+ [HttpPost("Branding/Splashscreen")]
+ [Authorize(Policy = Policies.RequiresElevation)]
+ [ProducesResponseType(StatusCodes.Status204NoContent)]
+ [ProducesResponseType(StatusCodes.Status400BadRequest)]
+ [ProducesResponseType(StatusCodes.Status403Forbidden)]
+ [AcceptsImageFile]
+ public async Task<ActionResult> UploadCustomSplashscreen()
+ {
+ await using var memoryStream = await GetMemoryStream(Request.Body).ConfigureAwait(false);
+
+ var mimeType = MediaTypeHeaderValue.Parse(Request.ContentType).MediaType;
+
+ if (!mimeType.HasValue)
+ {
+ return BadRequest("Error reading mimetype from uploaded image");
+ }
+
+ var filePath = Path.Combine(_appPaths.DataPath, "splashscreen-upload" + MimeTypes.ToExtension(mimeType.Value));
+ var brandingOptions = _serverConfigurationManager.GetConfiguration<BrandingOptions>("branding");
+ brandingOptions.SplashscreenLocation = filePath;
+ _serverConfigurationManager.SaveConfiguration("branding", brandingOptions);
+
+ await using (var fs = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous))
+ {
+ await memoryStream.CopyToAsync(fs, CancellationToken.None).ConfigureAwait(false);
+ }
+
+ return NoContent();
+ }
+
private static async Task<MemoryStream> GetMemoryStream(Stream inputStream)
{
using var reader = new StreamReader(inputStream);
@@ -1772,7 +1892,6 @@ namespace Jellyfin.Api.Controllers
string? backgroundColor,
string? foregroundLayer,
BaseItem? item,
- bool isHeadRequest,
ItemImageInfo? imageInfo = null)
{
if (percentPlayed.HasValue)
@@ -1823,28 +1942,37 @@ namespace Jellyfin.Api.Controllers
{ "realTimeInfo.dlna.org", "DLNA.ORG_TLAG=*" }
};
+ if (!imageInfo.IsLocalFile && item != null)
+ {
+ imageInfo = await _libraryManager.ConvertImageToLocal(item, imageInfo, imageIndex ?? 0).ConfigureAwait(false);
+ }
+
+ var options = new ImageProcessingOptions
+ {
+ Height = height,
+ ImageIndex = imageIndex ?? 0,
+ Image = imageInfo,
+ Item = item,
+ ItemId = itemId,
+ MaxHeight = maxHeight,
+ MaxWidth = maxWidth,
+ FillHeight = fillHeight,
+ FillWidth = fillWidth,
+ Quality = quality ?? 100,
+ Width = width,
+ AddPlayedIndicator = addPlayedIndicator ?? false,
+ PercentPlayed = percentPlayed ?? 0,
+ UnplayedCount = unplayedCount,
+ Blur = blur,
+ BackgroundColor = backgroundColor,
+ ForegroundLayer = foregroundLayer,
+ SupportedOutputFormats = outputFormats
+ };
+
return await GetImageResult(
- item,
- itemId,
- imageIndex,
- width,
- height,
- maxWidth,
- maxHeight,
- fillWidth,
- fillHeight,
- quality,
- addPlayedIndicator,
- percentPlayed,
- unplayedCount,
- blur,
- backgroundColor,
- foregroundLayer,
- imageInfo,
- outputFormats,
+ options,
cacheDuration,
- responseHeaders,
- isHeadRequest).ConfigureAwait(false);
+ responseHeaders).ConfigureAwait(false);
}
private ImageFormat[] GetOutputFormats(ImageFormat? format)
@@ -1921,56 +2049,11 @@ namespace Jellyfin.Api.Controllers
}
private async Task<ActionResult> GetImageResult(
- BaseItem? item,
- Guid itemId,
- int? index,
- int? width,
- int? height,
- int? maxWidth,
- int? maxHeight,
- int? fillWidth,
- int? fillHeight,
- int? quality,
- bool? addPlayedIndicator,
- double? percentPlayed,
- int? unplayedCount,
- int? blur,
- string? backgroundColor,
- string? foregroundLayer,
- ItemImageInfo imageInfo,
- IReadOnlyCollection<ImageFormat> supportedFormats,
+ ImageProcessingOptions imageProcessingOptions,
TimeSpan? cacheDuration,
- IDictionary<string, string> headers,
- bool isHeadRequest)
+ IDictionary<string, string> headers)
{
- if (!imageInfo.IsLocalFile && item != null)
- {
- imageInfo = await _libraryManager.ConvertImageToLocal(item, imageInfo, index ?? 0).ConfigureAwait(false);
- }
-
- var options = new ImageProcessingOptions
- {
- Height = height,
- ImageIndex = index ?? 0,
- Image = imageInfo,
- Item = item,
- ItemId = itemId,
- MaxHeight = maxHeight,
- MaxWidth = maxWidth,
- FillHeight = fillHeight,
- FillWidth = fillWidth,
- Quality = quality ?? 100,
- Width = width,
- AddPlayedIndicator = addPlayedIndicator ?? false,
- PercentPlayed = percentPlayed ?? 0,
- UnplayedCount = unplayedCount,
- Blur = blur,
- BackgroundColor = backgroundColor,
- ForegroundLayer = foregroundLayer,
- SupportedOutputFormats = supportedFormats
- };
-
- var (imagePath, imageContentType, dateImageModified) = await _imageProcessor.ProcessImage(options).ConfigureAwait(false);
+ var (imagePath, imageContentType, dateImageModified) = await _imageProcessor.ProcessImage(imageProcessingOptions).ConfigureAwait(false);
var disableCaching = Request.Headers[HeaderNames.CacheControl].Contains("no-cache");
var parsingSuccessful = DateTime.TryParse(Request.Headers[HeaderNames.IfModifiedSince], out var ifModifiedSinceHeader);
@@ -2019,12 +2102,6 @@ namespace Jellyfin.Api.Controllers
}
}
- // if the request is a head request, return a NoContent result with the same headers as it would with a GET request
- if (isHeadRequest)
- {
- return NoContent();
- }
-
return PhysicalFile(imagePath, imageContentType ?? MediaTypeNames.Text.Plain);
}
}
diff --git a/Jellyfin.Api/Controllers/InstantMixController.cs b/Jellyfin.Api/Controllers/InstantMixController.cs
index a6c2e07c9..9abea5938 100644
--- a/Jellyfin.Api/Controllers/InstantMixController.cs
+++ b/Jellyfin.Api/Controllers/InstantMixController.cs
@@ -75,9 +75,9 @@ namespace Jellyfin.Api.Controllers
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes)
{
var item = _libraryManager.GetItemById(id);
- var user = userId.HasValue && !userId.Equals(Guid.Empty)
- ? _userManager.GetUserById(userId.Value)
- : null;
+ var user = userId is null || userId.Value.Equals(default)
+ ? null
+ : _userManager.GetUserById(userId.Value);
var dtoOptions = new DtoOptions { Fields = fields }
.AddClientFields(Request)
.AddAdditionalDtoOptions(enableImages, enableUserData, imageTypeLimit, enableImageTypes);
@@ -111,9 +111,9 @@ namespace Jellyfin.Api.Controllers
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes)
{
var album = _libraryManager.GetItemById(id);
- var user = userId.HasValue && !userId.Equals(Guid.Empty)
- ? _userManager.GetUserById(userId.Value)
- : null;
+ var user = userId is null || userId.Value.Equals(default)
+ ? null
+ : _userManager.GetUserById(userId.Value);
var dtoOptions = new DtoOptions { Fields = fields }
.AddClientFields(Request)
.AddAdditionalDtoOptions(enableImages, enableUserData, imageTypeLimit, enableImageTypes);
@@ -147,9 +147,9 @@ namespace Jellyfin.Api.Controllers
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes)
{
var playlist = (Playlist)_libraryManager.GetItemById(id);
- var user = userId.HasValue && !userId.Equals(Guid.Empty)
- ? _userManager.GetUserById(userId.Value)
- : null;
+ var user = userId is null || userId.Value.Equals(default)
+ ? null
+ : _userManager.GetUserById(userId.Value);
var dtoOptions = new DtoOptions { Fields = fields }
.AddClientFields(Request)
.AddAdditionalDtoOptions(enableImages, enableUserData, imageTypeLimit, enableImageTypes);
@@ -182,9 +182,9 @@ namespace Jellyfin.Api.Controllers
[FromQuery] int? imageTypeLimit,
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes)
{
- var user = userId.HasValue && !userId.Equals(Guid.Empty)
- ? _userManager.GetUserById(userId.Value)
- : null;
+ var user = userId is null || userId.Value.Equals(default)
+ ? null
+ : _userManager.GetUserById(userId.Value);
var dtoOptions = new DtoOptions { Fields = fields }
.AddClientFields(Request)
.AddAdditionalDtoOptions(enableImages, enableUserData, imageTypeLimit, enableImageTypes);
@@ -218,9 +218,9 @@ namespace Jellyfin.Api.Controllers
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes)
{
var item = _libraryManager.GetItemById(id);
- var user = userId.HasValue && !userId.Equals(Guid.Empty)
- ? _userManager.GetUserById(userId.Value)
- : null;
+ var user = userId is null || userId.Value.Equals(default)
+ ? null
+ : _userManager.GetUserById(userId.Value);
var dtoOptions = new DtoOptions { Fields = fields }
.AddClientFields(Request)
.AddAdditionalDtoOptions(enableImages, enableUserData, imageTypeLimit, enableImageTypes);
@@ -254,9 +254,9 @@ namespace Jellyfin.Api.Controllers
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes)
{
var item = _libraryManager.GetItemById(id);
- var user = userId.HasValue && !userId.Equals(Guid.Empty)
- ? _userManager.GetUserById(userId.Value)
- : null;
+ var user = userId is null || userId.Value.Equals(default)
+ ? null
+ : _userManager.GetUserById(userId.Value);
var dtoOptions = new DtoOptions { Fields = fields }
.AddClientFields(Request)
.AddAdditionalDtoOptions(enableImages, enableUserData, imageTypeLimit, enableImageTypes);
@@ -327,9 +327,9 @@ namespace Jellyfin.Api.Controllers
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes)
{
var item = _libraryManager.GetItemById(id);
- var user = userId.HasValue && !userId.Equals(Guid.Empty)
- ? _userManager.GetUserById(userId.Value)
- : null;
+ var user = userId is null || userId.Value.Equals(default)
+ ? null
+ : _userManager.GetUserById(userId.Value);
var dtoOptions = new DtoOptions { Fields = fields }
.AddClientFields(Request)
.AddAdditionalDtoOptions(enableImages, enableUserData, imageTypeLimit, enableImageTypes);
@@ -341,10 +341,7 @@ namespace Jellyfin.Api.Controllers
{
var list = items;
- var result = new QueryResult<BaseItemDto>
- {
- TotalRecordCount = list.Count
- };
+ var totalCount = list.Count;
if (limit.HasValue && limit < list.Count)
{
@@ -353,7 +350,10 @@ namespace Jellyfin.Api.Controllers
var returnList = _dtoService.GetBaseItemDtos(list, dtoOptions, user);
- result.Items = returnList;
+ var result = new QueryResult<BaseItemDto>(
+ 0,
+ totalCount,
+ returnList);
return result;
}
diff --git a/Jellyfin.Api/Controllers/ItemsController.cs b/Jellyfin.Api/Controllers/ItemsController.cs
index f8192955e..2794a06f3 100644
--- a/Jellyfin.Api/Controllers/ItemsController.cs
+++ b/Jellyfin.Api/Controllers/ItemsController.cs
@@ -228,7 +228,7 @@ namespace Jellyfin.Api.Controllers
[FromQuery] bool enableTotalRecordCount = true,
[FromQuery] bool? enableImages = true)
{
- var user = userId == Guid.Empty ? null : _userManager.GetUserById(userId);
+ var user = userId.Equals(default) ? null : _userManager.GetUserById(userId);
var dtoOptions = new DtoOptions { Fields = fields }
.AddClientFields(Request)
.AddAdditionalDtoOptions(enableImages, enableUserData, imageTypeLimit, enableImageTypes);
@@ -491,10 +491,13 @@ namespace Jellyfin.Api.Controllers
else
{
var itemsArray = folder.GetChildren(user, true);
- result = new QueryResult<BaseItem> { Items = itemsArray, TotalRecordCount = itemsArray.Count, StartIndex = 0 };
+ result = new QueryResult<BaseItem>(itemsArray);
}
- return new QueryResult<BaseItemDto> { StartIndex = startIndex.GetValueOrDefault(), TotalRecordCount = result.TotalRecordCount, Items = _dtoService.GetBaseItemDtos(result.Items, dtoOptions, user) };
+ return new QueryResult<BaseItemDto>(
+ startIndex,
+ result.TotalRecordCount,
+ _dtoService.GetBaseItemDtos(result.Items, dtoOptions, user));
}
/// <summary>
@@ -796,7 +799,7 @@ namespace Jellyfin.Api.Controllers
var ancestorIds = Array.Empty<Guid>();
var excludeFolderIds = user.GetPreferenceValues<Guid>(PreferenceKind.LatestItemExcludes);
- if (parentIdGuid.Equals(Guid.Empty) && excludeFolderIds.Length > 0)
+ if (parentIdGuid.Equals(default) && excludeFolderIds.Length > 0)
{
ancestorIds = _libraryManager.GetUserRootFolder().GetChildren(user, true)
.Where(i => i is Folder)
@@ -809,7 +812,7 @@ namespace Jellyfin.Api.Controllers
if (excludeActiveSessions)
{
excludeItemIds = _sessionManager.Sessions
- .Where(s => s.UserId == userId && s.NowPlayingItem != null)
+ .Where(s => s.UserId.Equals(userId) && s.NowPlayingItem != null)
.Select(s => s.NowPlayingItem.Id)
.ToArray();
}
@@ -836,12 +839,10 @@ namespace Jellyfin.Api.Controllers
var returnItems = _dtoService.GetBaseItemDtos(itemsResult.Items, dtoOptions, user);
- return new QueryResult<BaseItemDto>
- {
- StartIndex = startIndex.GetValueOrDefault(),
- TotalRecordCount = itemsResult.TotalRecordCount,
- Items = returnItems
- };
+ return new QueryResult<BaseItemDto>(
+ startIndex,
+ itemsResult.TotalRecordCount,
+ returnItems);
}
}
}
diff --git a/Jellyfin.Api/Controllers/LibraryController.cs b/Jellyfin.Api/Controllers/LibraryController.cs
index f1b9c2f67..4cc17dd0f 100644
--- a/Jellyfin.Api/Controllers/LibraryController.cs
+++ b/Jellyfin.Api/Controllers/LibraryController.cs
@@ -149,14 +149,14 @@ namespace Jellyfin.Api.Controllers
[FromQuery] Guid? userId,
[FromQuery] bool inheritFromParent = false)
{
- var user = userId.HasValue && !userId.Equals(Guid.Empty)
- ? _userManager.GetUserById(userId.Value)
- : null;
-
- var item = itemId.Equals(Guid.Empty)
- ? (!userId.Equals(Guid.Empty)
- ? _libraryManager.GetUserRootFolder()
- : _libraryManager.RootFolder)
+ var user = userId is null || userId.Value.Equals(default)
+ ? null
+ : _userManager.GetUserById(userId.Value);
+
+ var item = itemId.Equals(default)
+ ? (userId is null || userId.Value.Equals(default)
+ ? _libraryManager.RootFolder
+ : _libraryManager.GetUserRootFolder())
: _libraryManager.GetItemById(itemId);
if (item == null)
@@ -215,14 +215,14 @@ namespace Jellyfin.Api.Controllers
[FromQuery] Guid? userId,
[FromQuery] bool inheritFromParent = false)
{
- var user = userId.HasValue && !userId.Equals(Guid.Empty)
- ? _userManager.GetUserById(userId.Value)
- : null;
-
- var item = itemId.Equals(Guid.Empty)
- ? (!userId.Equals(Guid.Empty)
- ? _libraryManager.GetUserRootFolder()
- : _libraryManager.RootFolder)
+ var user = userId is null || userId.Value.Equals(default)
+ ? null
+ : _userManager.GetUserById(userId.Value);
+
+ var item = itemId.Equals(default)
+ ? (userId is null || userId.Value.Equals(default)
+ ? _libraryManager.RootFolder
+ : _libraryManager.GetUserRootFolder())
: _libraryManager.GetItemById(itemId);
if (item == null)
@@ -407,9 +407,9 @@ namespace Jellyfin.Api.Controllers
[FromQuery] Guid? userId,
[FromQuery] bool? isFavorite)
{
- var user = userId.HasValue && !userId.Equals(Guid.Empty)
- ? _userManager.GetUserById(userId.Value)
- : null;
+ var user = userId is null || userId.Value.Equals(default)
+ ? null
+ : _userManager.GetUserById(userId.Value);
var counts = new ItemCounts
{
@@ -449,9 +449,9 @@ namespace Jellyfin.Api.Controllers
var baseItemDtos = new List<BaseItemDto>();
- var user = userId.HasValue && !userId.Equals(Guid.Empty)
- ? _userManager.GetUserById(userId.Value)
- : null;
+ var user = userId is null || userId.Value.Equals(default)
+ ? null
+ : _userManager.GetUserById(userId.Value);
var dtoOptions = new DtoOptions().AddClientFields(Request);
BaseItem? parent = item.GetParent();
@@ -506,13 +506,8 @@ namespace Jellyfin.Api.Controllers
}
var dtoOptions = new DtoOptions().AddClientFields(Request);
- var result = new QueryResult<BaseItemDto>
- {
- TotalRecordCount = items.Count,
- Items = items.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions)).ToArray()
- };
-
- return result;
+ var resultArray = _dtoService.GetBaseItemDtos(items, dtoOptions);
+ return new QueryResult<BaseItemDto>(resultArray);
}
/// <summary>
@@ -694,10 +689,10 @@ namespace Jellyfin.Api.Controllers
[FromQuery] int? limit,
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields)
{
- var item = itemId.Equals(Guid.Empty)
- ? (!userId.Equals(Guid.Empty)
- ? _libraryManager.GetUserRootFolder()
- : _libraryManager.RootFolder)
+ var item = itemId.Equals(default)
+ ? (userId is null || userId.Value.Equals(default)
+ ? _libraryManager.RootFolder
+ : _libraryManager.GetUserRootFolder())
: _libraryManager.GetItemById(itemId);
if (item is Episode || (item is IItemByName && item is not MusicArtist))
@@ -705,9 +700,9 @@ namespace Jellyfin.Api.Controllers
return new QueryResult<BaseItemDto>();
}
- var user = userId.HasValue && !userId.Equals(Guid.Empty)
- ? _userManager.GetUserById(userId.Value)
- : null;
+ var user = userId is null || userId.Value.Equals(default)
+ ? null
+ : _userManager.GetUserById(userId.Value);
var dtoOptions = new DtoOptions { Fields = fields }
.AddClientFields(Request);
@@ -759,11 +754,10 @@ namespace Jellyfin.Api.Controllers
var returnList = _dtoService.GetBaseItemDtos(itemsResult, dtoOptions, user);
- return new QueryResult<BaseItemDto>
- {
- Items = returnList,
- TotalRecordCount = itemsResult.Count
- };
+ return new QueryResult<BaseItemDto>(
+ query.StartIndex,
+ itemsResult.Count,
+ returnList);
}
/// <summary>
diff --git a/Jellyfin.Api/Controllers/LiveTvController.cs b/Jellyfin.Api/Controllers/LiveTvController.cs
index 9e2ef8c60..05340099b 100644
--- a/Jellyfin.Api/Controllers/LiveTvController.cs
+++ b/Jellyfin.Api/Controllers/LiveTvController.cs
@@ -180,9 +180,9 @@ namespace Jellyfin.Api.Controllers
dtoOptions,
CancellationToken.None);
- var user = userId.HasValue && !userId.Equals(Guid.Empty)
- ? _userManager.GetUserById(userId.Value)
- : null;
+ var user = userId is null || userId.Value.Equals(default)
+ ? null
+ : _userManager.GetUserById(userId.Value);
var fieldsList = dtoOptions.Fields.ToList();
fieldsList.Remove(ItemFields.CanDelete);
@@ -193,11 +193,10 @@ namespace Jellyfin.Api.Controllers
dtoOptions.AddCurrentProgram = addCurrentProgram;
var returnArray = _dtoService.GetBaseItemDtos(channelResult.Items, dtoOptions, user);
- return new QueryResult<BaseItemDto>
- {
- Items = returnArray,
- TotalRecordCount = channelResult.TotalRecordCount
- };
+ return new QueryResult<BaseItemDto>(
+ startIndex,
+ channelResult.TotalRecordCount,
+ returnArray);
}
/// <summary>
@@ -212,10 +211,10 @@ namespace Jellyfin.Api.Controllers
[Authorize(Policy = Policies.DefaultAuthorization)]
public ActionResult<BaseItemDto> GetChannel([FromRoute, Required] Guid channelId, [FromQuery] Guid? userId)
{
- var user = userId.HasValue && !userId.Equals(Guid.Empty)
- ? _userManager.GetUserById(userId.Value)
- : null;
- var item = channelId.Equals(Guid.Empty)
+ var user = userId is null || userId.Value.Equals(default)
+ ? null
+ : _userManager.GetUserById(userId.Value);
+ var item = channelId.Equals(default)
? _libraryManager.GetUserRootFolder()
: _libraryManager.GetItemById(channelId);
@@ -383,18 +382,14 @@ namespace Jellyfin.Api.Controllers
[Authorize(Policy = Policies.DefaultAuthorization)]
public ActionResult<QueryResult<BaseItemDto>> GetRecordingFolders([FromQuery] Guid? userId)
{
- var user = userId.HasValue && !userId.Equals(Guid.Empty)
- ? _userManager.GetUserById(userId.Value)
- : null;
+ var user = userId is null || userId.Value.Equals(default)
+ ? null
+ : _userManager.GetUserById(userId.Value);
var folders = _liveTvManager.GetRecordingFolders(user);
var returnArray = _dtoService.GetBaseItemDtos(folders, new DtoOptions(), user);
- return new QueryResult<BaseItemDto>
- {
- Items = returnArray,
- TotalRecordCount = returnArray.Count
- };
+ return new QueryResult<BaseItemDto>(returnArray);
}
/// <summary>
@@ -409,10 +404,10 @@ namespace Jellyfin.Api.Controllers
[Authorize(Policy = Policies.DefaultAuthorization)]
public ActionResult<BaseItemDto> GetRecording([FromRoute, Required] Guid recordingId, [FromQuery] Guid? userId)
{
- var user = userId.HasValue && !userId.Equals(Guid.Empty)
- ? _userManager.GetUserById(userId.Value)
- : null;
- var item = recordingId.Equals(Guid.Empty) ? _libraryManager.GetUserRootFolder() : _libraryManager.GetItemById(recordingId);
+ var user = userId is null || userId.Value.Equals(default)
+ ? null
+ : _userManager.GetUserById(userId.Value);
+ var item = recordingId.Equals(default) ? _libraryManager.GetUserRootFolder() : _libraryManager.GetItemById(recordingId);
var dtoOptions = new DtoOptions()
.AddClientFields(Request);
@@ -566,9 +561,9 @@ namespace Jellyfin.Api.Controllers
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields,
[FromQuery] bool enableTotalRecordCount = true)
{
- var user = userId.HasValue && !userId.Equals(Guid.Empty)
- ? _userManager.GetUserById(userId.Value)
- : null;
+ var user = userId is null || userId.Value.Equals(default)
+ ? null
+ : _userManager.GetUserById(userId.Value);
var query = new InternalItemsQuery(user)
{
@@ -593,7 +588,7 @@ namespace Jellyfin.Api.Controllers
GenreIds = genreIds
};
- if (librarySeriesId != null && !librarySeriesId.Equals(Guid.Empty))
+ if (librarySeriesId.HasValue && !librarySeriesId.Equals(default))
{
query.IsSeries = true;
@@ -622,7 +617,7 @@ namespace Jellyfin.Api.Controllers
[Authorize(Policy = Policies.DefaultAuthorization)]
public async Task<ActionResult<QueryResult<BaseItemDto>>> GetPrograms([FromBody] GetProgramsDto body)
{
- var user = body.UserId.Equals(Guid.Empty) ? null : _userManager.GetUserById(body.UserId);
+ var user = body.UserId.Equals(default) ? null : _userManager.GetUserById(body.UserId);
var query = new InternalItemsQuery(user)
{
@@ -647,7 +642,7 @@ namespace Jellyfin.Api.Controllers
GenreIds = body.GenreIds
};
- if (!body.LibrarySeriesId.Equals(Guid.Empty))
+ if (!body.LibrarySeriesId.Equals(default))
{
query.IsSeries = true;
@@ -687,7 +682,7 @@ namespace Jellyfin.Api.Controllers
[HttpGet("Programs/Recommended")]
[Authorize(Policy = Policies.DefaultAuthorization)]
[ProducesResponseType(StatusCodes.Status200OK)]
- public ActionResult<QueryResult<BaseItemDto>> GetRecommendedPrograms(
+ public async Task<ActionResult<QueryResult<BaseItemDto>>> GetRecommendedPrograms(
[FromQuery] Guid? userId,
[FromQuery] int? limit,
[FromQuery] bool? isAiring,
@@ -705,9 +700,9 @@ namespace Jellyfin.Api.Controllers
[FromQuery] bool? enableUserData,
[FromQuery] bool enableTotalRecordCount = true)
{
- var user = userId.HasValue && !userId.Equals(Guid.Empty)
- ? _userManager.GetUserById(userId.Value)
- : null;
+ var user = userId is null || userId.Value.Equals(default)
+ ? null
+ : _userManager.GetUserById(userId.Value);
var query = new InternalItemsQuery(user)
{
@@ -726,7 +721,7 @@ namespace Jellyfin.Api.Controllers
var dtoOptions = new DtoOptions { Fields = fields }
.AddClientFields(Request)
.AddAdditionalDtoOptions(enableImages, enableUserData, imageTypeLimit, enableImageTypes);
- return _liveTvManager.GetRecommendedPrograms(query, dtoOptions, CancellationToken.None);
+ return await _liveTvManager.GetRecommendedProgramsAsync(query, dtoOptions, CancellationToken.None).ConfigureAwait(false);
}
/// <summary>
@@ -743,9 +738,9 @@ namespace Jellyfin.Api.Controllers
[FromRoute, Required] string programId,
[FromQuery] Guid? userId)
{
- var user = userId.HasValue && !userId.Equals(Guid.Empty)
- ? _userManager.GetUserById(userId.Value)
- : null;
+ var user = userId is null || userId.Value.Equals(default)
+ ? null
+ : _userManager.GetUserById(userId.Value);
return await _liveTvManager.GetProgram(programId, CancellationToken.None, user).ConfigureAwait(false);
}
diff --git a/Jellyfin.Api/Controllers/MoviesController.cs b/Jellyfin.Api/Controllers/MoviesController.cs
index db72ff2f8..420dd9923 100644
--- a/Jellyfin.Api/Controllers/MoviesController.cs
+++ b/Jellyfin.Api/Controllers/MoviesController.cs
@@ -68,9 +68,9 @@ namespace Jellyfin.Api.Controllers
[FromQuery] int categoryLimit = 5,
[FromQuery] int itemLimit = 8)
{
- var user = userId.HasValue && !userId.Equals(Guid.Empty)
- ? _userManager.GetUserById(userId.Value)
- : null;
+ var user = userId is null || userId.Value.Equals(default)
+ ? null
+ : _userManager.GetUserById(userId.Value);
var dtoOptions = new DtoOptions { Fields = fields }
.AddClientFields(Request);
diff --git a/Jellyfin.Api/Controllers/MusicGenresController.cs b/Jellyfin.Api/Controllers/MusicGenresController.cs
index c4c03aa4f..0499b2985 100644
--- a/Jellyfin.Api/Controllers/MusicGenresController.cs
+++ b/Jellyfin.Api/Controllers/MusicGenresController.cs
@@ -95,7 +95,9 @@ namespace Jellyfin.Api.Controllers
.AddClientFields(Request)
.AddAdditionalDtoOptions(enableImages, false, imageTypeLimit, enableImageTypes);
- User? user = userId.HasValue && userId != Guid.Empty ? _userManager.GetUserById(userId.Value) : null;
+ User? user = userId is null || userId.Value.Equals(default)
+ ? null
+ : _userManager.GetUserById(userId.Value);
var parentItem = _libraryManager.GetParentItem(parentId, userId);
@@ -156,7 +158,7 @@ namespace Jellyfin.Api.Controllers
item = _libraryManager.GetMusicGenre(genreName);
}
- if (userId.HasValue && !userId.Equals(Guid.Empty))
+ if (userId.HasValue && !userId.Value.Equals(default))
{
var user = _userManager.GetUserById(userId.Value);
diff --git a/Jellyfin.Api/Controllers/PersonsController.cs b/Jellyfin.Api/Controllers/PersonsController.cs
index cb4894d77..be4b9eded 100644
--- a/Jellyfin.Api/Controllers/PersonsController.cs
+++ b/Jellyfin.Api/Controllers/PersonsController.cs
@@ -82,12 +82,9 @@ namespace Jellyfin.Api.Controllers
.AddClientFields(Request)
.AddAdditionalDtoOptions(enableImages, enableUserData, imageTypeLimit, enableImageTypes);
- User? user = null;
-
- if (userId.HasValue && !userId.Equals(Guid.Empty))
- {
- user = _userManager.GetUserById(userId.Value);
- }
+ User? user = userId is null || userId.Value.Equals(default)
+ ? null
+ : _userManager.GetUserById(userId.Value);
var isFavoriteInFilters = filters.Any(f => f == ItemFilter.IsFavorite);
var peopleItems = _libraryManager.GetPeopleItems(new InternalPeopleQuery(
@@ -101,11 +98,7 @@ namespace Jellyfin.Api.Controllers
Limit = limit ?? 0
});
- return new QueryResult<BaseItemDto>
- {
- Items = peopleItems.Select(person => _dtoService.GetItemByNameDto(person, dtoOptions, null, user)).ToArray(),
- TotalRecordCount = peopleItems.Count
- };
+ return new QueryResult<BaseItemDto>(peopleItems.Select(person => _dtoService.GetItemByNameDto(person, dtoOptions, null, user)).ToArray());
}
/// <summary>
@@ -131,7 +124,7 @@ namespace Jellyfin.Api.Controllers
return NotFound();
}
- if (userId.HasValue && !userId.Equals(Guid.Empty))
+ if (userId.HasValue && !userId.Value.Equals(default))
{
var user = _userManager.GetUserById(userId.Value);
return _dtoService.GetBaseItemDto(item, dtoOptions, user);
diff --git a/Jellyfin.Api/Controllers/PlaylistsController.cs b/Jellyfin.Api/Controllers/PlaylistsController.cs
index 1667d6ede..ad85f2fb2 100644
--- a/Jellyfin.Api/Controllers/PlaylistsController.cs
+++ b/Jellyfin.Api/Controllers/PlaylistsController.cs
@@ -181,7 +181,9 @@ namespace Jellyfin.Api.Controllers
return NotFound();
}
- var user = !userId.Equals(Guid.Empty) ? _userManager.GetUserById(userId) : null;
+ var user = userId.Equals(default)
+ ? null
+ : _userManager.GetUserById(userId);
var items = playlist.GetManageableItems().ToArray();
@@ -208,11 +210,10 @@ namespace Jellyfin.Api.Controllers
dtos[index].PlaylistItemId = items[index].Item1.Id;
}
- var result = new QueryResult<BaseItemDto>
- {
- Items = dtos,
- TotalRecordCount = count
- };
+ var result = new QueryResult<BaseItemDto>(
+ startIndex,
+ count,
+ dtos);
return result;
}
diff --git a/Jellyfin.Api/Controllers/PluginsController.cs b/Jellyfin.Api/Controllers/PluginsController.cs
index b41df1abb..b227dba2d 100644
--- a/Jellyfin.Api/Controllers/PluginsController.cs
+++ b/Jellyfin.Api/Controllers/PluginsController.cs
@@ -7,7 +7,6 @@ using System.Text.Json;
using System.Threading.Tasks;
using Jellyfin.Api.Attributes;
using Jellyfin.Api.Constants;
-using Jellyfin.Api.Models.PluginDtos;
using Jellyfin.Extensions.Json;
using MediaBrowser.Common.Plugins;
using MediaBrowser.Common.Updates;
@@ -44,61 +43,6 @@ namespace Jellyfin.Api.Controllers
}
/// <summary>
- /// Get plugin security info.
- /// </summary>
- /// <response code="200">Plugin security info returned.</response>
- /// <returns>Plugin security info.</returns>
- [Obsolete("This endpoint should not be used.")]
- [HttpGet("SecurityInfo")]
- [ProducesResponseType(StatusCodes.Status200OK)]
- public static ActionResult<PluginSecurityInfo> GetPluginSecurityInfo()
- {
- return new PluginSecurityInfo
- {
- IsMbSupporter = true,
- SupporterKey = "IAmTotallyLegit"
- };
- }
-
- /// <summary>
- /// Gets registration status for a feature.
- /// </summary>
- /// <param name="name">Feature name.</param>
- /// <response code="200">Registration status returned.</response>
- /// <returns>Mb registration record.</returns>
- [Obsolete("This endpoint should not be used.")]
- [HttpPost("RegistrationRecords/{name}")]
- [ProducesResponseType(StatusCodes.Status200OK)]
- public static ActionResult<MBRegistrationRecord> GetRegistrationStatus([FromRoute, Required] string name)
- {
- return new MBRegistrationRecord
- {
- IsRegistered = true,
- RegChecked = true,
- TrialVersion = false,
- IsValid = true,
- RegError = false
- };
- }
-
- /// <summary>
- /// Gets registration status for a feature.
- /// </summary>
- /// <param name="name">Feature name.</param>
- /// <response code="501">Not implemented.</response>
- /// <returns>Not Implemented.</returns>
- /// <exception cref="NotImplementedException">This endpoint is not implemented.</exception>
- [Obsolete("Paid plugins are not supported")]
- [HttpGet("Registrations/{name}")]
- [ProducesResponseType(StatusCodes.Status501NotImplemented)]
- public static ActionResult GetRegistration([FromRoute, Required] string name)
- {
- // TODO Once we have proper apps and plugins and decide to break compatibility with paid plugins,
- // delete all these registration endpoints. They are only kept for compatibility.
- throw new NotImplementedException();
- }
-
- /// <summary>
/// Gets a list of currently installed plugins.
/// </summary>
/// <response code="200">Installed plugins returned.</response>
@@ -317,20 +261,5 @@ namespace Jellyfin.Api.Controllers
return NotFound();
}
-
- /// <summary>
- /// Updates plugin security info.
- /// </summary>
- /// <param name="pluginSecurityInfo">Plugin security info.</param>
- /// <response code="204">Plugin security info updated.</response>
- /// <returns>An <see cref="NoContentResult"/>.</returns>
- [Obsolete("This endpoint should not be used.")]
- [HttpPost("SecurityInfo")]
- [Authorize(Policy = Policies.RequiresElevation)]
- [ProducesResponseType(StatusCodes.Status204NoContent)]
- public ActionResult UpdatePluginSecurityInfo([FromBody, Required] PluginSecurityInfo pluginSecurityInfo)
- {
- return NoContent();
- }
}
}
diff --git a/Jellyfin.Api/Controllers/SearchController.cs b/Jellyfin.Api/Controllers/SearchController.cs
index 26acb4cdc..6ffedccbd 100644
--- a/Jellyfin.Api/Controllers/SearchController.cs
+++ b/Jellyfin.Api/Controllers/SearchController.cs
@@ -121,11 +121,7 @@ namespace Jellyfin.Api.Controllers
IsSports = isSports
});
- return new SearchHintResult
- {
- TotalRecordCount = result.TotalRecordCount,
- SearchHints = result.Items.Select(GetSearchHintResult).ToArray()
- };
+ return new SearchHintResult(result.Items.Select(GetSearchHintResult).ToArray(), result.TotalRecordCount);
}
/// <summary>
@@ -209,7 +205,7 @@ namespace Jellyfin.Api.Controllers
break;
}
- if (!item.ChannelId.Equals(Guid.Empty))
+ if (!item.ChannelId.Equals(default))
{
var channel = _libraryManager.GetItemById(item.ChannelId);
result.ChannelName = channel?.Name;
diff --git a/Jellyfin.Api/Controllers/SessionController.cs b/Jellyfin.Api/Controllers/SessionController.cs
index a6bbd40cc..860bccb9b 100644
--- a/Jellyfin.Api/Controllers/SessionController.cs
+++ b/Jellyfin.Api/Controllers/SessionController.cs
@@ -74,7 +74,7 @@ namespace Jellyfin.Api.Controllers
result = result.Where(i => string.Equals(i.DeviceId, deviceId, StringComparison.OrdinalIgnoreCase));
}
- if (controllableByUserId.HasValue && !controllableByUserId.Equals(Guid.Empty))
+ if (controllableByUserId.HasValue && !controllableByUserId.Equals(default))
{
result = result.Where(i => i.SupportsRemoteControl);
@@ -82,12 +82,12 @@ namespace Jellyfin.Api.Controllers
if (!user.HasPermission(PermissionKind.EnableRemoteControlOfOtherUsers))
{
- result = result.Where(i => i.UserId.Equals(Guid.Empty) || i.ContainsUser(controllableByUserId.Value));
+ result = result.Where(i => i.UserId.Equals(default) || i.ContainsUser(controllableByUserId.Value));
}
if (!user.HasPermission(PermissionKind.EnableSharedDeviceControl))
{
- result = result.Where(i => !i.UserId.Equals(Guid.Empty));
+ result = result.Where(i => !i.UserId.Equals(default));
}
if (activeWithinSeconds.HasValue && activeWithinSeconds.Value > 0)
diff --git a/Jellyfin.Api/Controllers/StudiosController.cs b/Jellyfin.Api/Controllers/StudiosController.cs
index 4422ef32c..053c7baaa 100644
--- a/Jellyfin.Api/Controllers/StudiosController.cs
+++ b/Jellyfin.Api/Controllers/StudiosController.cs
@@ -91,7 +91,9 @@ namespace Jellyfin.Api.Controllers
.AddClientFields(Request)
.AddAdditionalDtoOptions(enableImages, enableUserData, imageTypeLimit, enableImageTypes);
- User? user = userId.HasValue && userId != Guid.Empty ? _userManager.GetUserById(userId.Value) : null;
+ User? user = userId is null || userId.Value.Equals(default)
+ ? null
+ : _userManager.GetUserById(userId.Value);
var parentItem = _libraryManager.GetParentItem(parentId, userId);
@@ -141,7 +143,7 @@ namespace Jellyfin.Api.Controllers
var dtoOptions = new DtoOptions().AddClientFields(Request);
var item = _libraryManager.GetStudio(name);
- if (userId.HasValue && !userId.Equals(Guid.Empty))
+ if (userId.HasValue && !userId.Equals(default))
{
var user = _userManager.GetUserById(userId.Value);
diff --git a/Jellyfin.Api/Controllers/SuggestionsController.cs b/Jellyfin.Api/Controllers/SuggestionsController.cs
index af77c801f..e9c46dcf3 100644
--- a/Jellyfin.Api/Controllers/SuggestionsController.cs
+++ b/Jellyfin.Api/Controllers/SuggestionsController.cs
@@ -63,7 +63,9 @@ namespace Jellyfin.Api.Controllers
[FromQuery] int? limit,
[FromQuery] bool enableTotalRecordCount = false)
{
- var user = !userId.Equals(Guid.Empty) ? _userManager.GetUserById(userId) : null;
+ var user = userId.Equals(default)
+ ? null
+ : _userManager.GetUserById(userId);
var dtoOptions = new DtoOptions().AddClientFields(Request);
var result = _libraryManager.GetItemsResult(new InternalItemsQuery(user)
@@ -81,11 +83,10 @@ namespace Jellyfin.Api.Controllers
var dtoList = _dtoService.GetBaseItemDtos(result.Items, dtoOptions, user);
- return new QueryResult<BaseItemDto>
- {
- TotalRecordCount = result.TotalRecordCount,
- Items = dtoList
- };
+ return new QueryResult<BaseItemDto>(
+ startIndex,
+ result.TotalRecordCount,
+ dtoList);
}
}
}
diff --git a/Jellyfin.Api/Controllers/TvShowsController.cs b/Jellyfin.Api/Controllers/TvShowsController.cs
index e20bcd7a7..179a53fd5 100644
--- a/Jellyfin.Api/Controllers/TvShowsController.cs
+++ b/Jellyfin.Api/Controllers/TvShowsController.cs
@@ -68,6 +68,7 @@ namespace Jellyfin.Api.Controllers
/// <param name="nextUpDateCutoff">Optional. Starting date of shows to show in Next Up section.</param>
/// <param name="enableTotalRecordCount">Whether to enable the total records count. Defaults to true.</param>
/// <param name="disableFirstEpisode">Whether to disable sending the first episode in a series as next up.</param>
+ /// <param name="enableRewatching">Whether to include watched episode in next up results.</param>
/// <returns>A <see cref="QueryResult{BaseItemDto}"/> with the next up episodes.</returns>
[HttpGet("NextUp")]
[ProducesResponseType(StatusCodes.Status200OK)]
@@ -84,7 +85,8 @@ namespace Jellyfin.Api.Controllers
[FromQuery] bool? enableUserData,
[FromQuery] DateTime? nextUpDateCutoff,
[FromQuery] bool enableTotalRecordCount = true,
- [FromQuery] bool disableFirstEpisode = false)
+ [FromQuery] bool disableFirstEpisode = false,
+ [FromQuery] bool enableRewatching = false)
{
var options = new DtoOptions { Fields = fields }
.AddClientFields(Request)
@@ -100,21 +102,21 @@ namespace Jellyfin.Api.Controllers
UserId = userId ?? Guid.Empty,
EnableTotalRecordCount = enableTotalRecordCount,
DisableFirstEpisode = disableFirstEpisode,
- NextUpDateCutoff = nextUpDateCutoff ?? DateTime.MinValue
+ NextUpDateCutoff = nextUpDateCutoff ?? DateTime.MinValue,
+ EnableRewatching = enableRewatching
},
options);
- var user = userId.HasValue && !userId.Equals(Guid.Empty)
- ? _userManager.GetUserById(userId.Value)
- : null;
+ var user = userId is null || userId.Value.Equals(default)
+ ? null
+ : _userManager.GetUserById(userId.Value);
var returnItems = _dtoService.GetBaseItemDtos(result.Items, options, user);
- return new QueryResult<BaseItemDto>
- {
- TotalRecordCount = result.TotalRecordCount,
- Items = returnItems
- };
+ return new QueryResult<BaseItemDto>(
+ startIndex,
+ result.TotalRecordCount,
+ returnItems);
}
/// <summary>
@@ -143,9 +145,9 @@ namespace Jellyfin.Api.Controllers
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes,
[FromQuery] bool? enableUserData)
{
- var user = userId.HasValue && !userId.Equals(Guid.Empty)
- ? _userManager.GetUserById(userId.Value)
- : null;
+ var user = userId is null || userId.Value.Equals(default)
+ ? null
+ : _userManager.GetUserById(userId.Value);
var minPremiereDate = DateTime.UtcNow.Date.AddDays(-1);
@@ -169,11 +171,10 @@ namespace Jellyfin.Api.Controllers
var returnItems = _dtoService.GetBaseItemDtos(itemsResult, options, user);
- return new QueryResult<BaseItemDto>
- {
- TotalRecordCount = itemsResult.Count,
- Items = returnItems
- };
+ return new QueryResult<BaseItemDto>(
+ startIndex,
+ itemsResult.Count,
+ returnItems);
}
/// <summary>
@@ -215,9 +216,9 @@ namespace Jellyfin.Api.Controllers
[FromQuery] bool? enableUserData,
[FromQuery] string? sortBy)
{
- var user = userId.HasValue && !userId.Equals(Guid.Empty)
- ? _userManager.GetUserById(userId.Value)
- : null;
+ var user = userId is null || userId.Value.Equals(default)
+ ? null
+ : _userManager.GetUserById(userId.Value);
List<BaseItem> episodes;
@@ -296,11 +297,10 @@ namespace Jellyfin.Api.Controllers
var dtos = _dtoService.GetBaseItemDtos(returnItems, dtoOptions, user);
- return new QueryResult<BaseItemDto>
- {
- TotalRecordCount = episodes.Count,
- Items = dtos
- };
+ return new QueryResult<BaseItemDto>(
+ startIndex,
+ episodes.Count,
+ dtos);
}
/// <summary>
@@ -332,9 +332,9 @@ namespace Jellyfin.Api.Controllers
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes,
[FromQuery] bool? enableUserData)
{
- var user = userId.HasValue && !userId.Equals(Guid.Empty)
- ? _userManager.GetUserById(userId.Value)
- : null;
+ var user = userId is null || userId.Value.Equals(default)
+ ? null
+ : _userManager.GetUserById(userId.Value);
if (_libraryManager.GetItemById(seriesId) is not Series series)
{
@@ -354,11 +354,7 @@ namespace Jellyfin.Api.Controllers
var returnItems = _dtoService.GetBaseItemDtos(seasons, dtoOptions, user);
- return new QueryResult<BaseItemDto>
- {
- TotalRecordCount = returnItems.Count,
- Items = returnItems
- };
+ return new QueryResult<BaseItemDto>(returnItems);
}
/// <summary>
diff --git a/Jellyfin.Api/Controllers/UserController.cs b/Jellyfin.Api/Controllers/UserController.cs
index 4263d4fe5..6d15d9185 100644
--- a/Jellyfin.Api/Controllers/UserController.cs
+++ b/Jellyfin.Api/Controllers/UserController.cs
@@ -534,7 +534,7 @@ namespace Jellyfin.Api.Controllers
public ActionResult<UserDto> GetCurrentUser()
{
var userId = ClaimHelpers.GetUserId(Request.HttpContext.User);
- if (userId == null)
+ if (userId is null)
{
return BadRequest();
}
diff --git a/Jellyfin.Api/Controllers/UserLibraryController.cs b/Jellyfin.Api/Controllers/UserLibraryController.cs
index 8b99170d9..e45f9b58c 100644
--- a/Jellyfin.Api/Controllers/UserLibraryController.cs
+++ b/Jellyfin.Api/Controllers/UserLibraryController.cs
@@ -76,7 +76,7 @@ namespace Jellyfin.Api.Controllers
{
var user = _userManager.GetUserById(userId);
- var item = itemId.Equals(Guid.Empty)
+ var item = itemId.Equals(default)
? _libraryManager.GetUserRootFolder()
: _libraryManager.GetItemById(itemId);
@@ -116,7 +116,7 @@ namespace Jellyfin.Api.Controllers
{
var user = _userManager.GetUserById(userId);
- var item = itemId.Equals(Guid.Empty)
+ var item = itemId.Equals(default)
? _libraryManager.GetUserRootFolder()
: _libraryManager.GetItemById(itemId);
@@ -124,11 +124,7 @@ namespace Jellyfin.Api.Controllers
var dtoOptions = new DtoOptions().AddClientFields(Request);
var dtos = items.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user)).ToArray();
- return new QueryResult<BaseItemDto>
- {
- Items = dtos,
- TotalRecordCount = dtos.Length
- };
+ return new QueryResult<BaseItemDto>(dtos);
}
/// <summary>
@@ -201,26 +197,21 @@ namespace Jellyfin.Api.Controllers
{
var user = _userManager.GetUserById(userId);
- var item = itemId.Equals(Guid.Empty)
+ var item = itemId.Equals(default)
? _libraryManager.GetUserRootFolder()
: _libraryManager.GetItemById(itemId);
var dtoOptions = new DtoOptions().AddClientFields(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.LocalTrailers;
- 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 allTrailers;
+ return Ok(_dtoService.GetBaseItemDtos(trailers, dtoOptions, user, item));
}
- return dtosExtras;
+ return Ok(item.GetExtras()
+ .Where(e => e.ExtraType == ExtraType.Trailer)
+ .Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user, item)));
}
/// <summary>
@@ -236,7 +227,7 @@ namespace Jellyfin.Api.Controllers
{
var user = _userManager.GetUserById(userId);
- var item = itemId.Equals(Guid.Empty)
+ var item = itemId.Equals(default)
? _libraryManager.GetUserRootFolder()
: _libraryManager.GetItemById(itemId);
@@ -356,7 +347,7 @@ namespace Jellyfin.Api.Controllers
{
var user = _userManager.GetUserById(userId);
- var item = itemId.Equals(Guid.Empty) ? _libraryManager.GetUserRootFolder() : _libraryManager.GetItemById(itemId);
+ var item = itemId.Equals(default) ? _libraryManager.GetUserRootFolder() : _libraryManager.GetItemById(itemId);
// Get the user data for this item
var data = _userDataRepository.GetUserData(user, item);
@@ -379,7 +370,7 @@ namespace Jellyfin.Api.Controllers
{
var user = _userManager.GetUserById(userId);
- var item = itemId.Equals(Guid.Empty) ? _libraryManager.GetUserRootFolder() : _libraryManager.GetItemById(itemId);
+ var item = itemId.Equals(default) ? _libraryManager.GetUserRootFolder() : _libraryManager.GetItemById(itemId);
// Get the user data for this item
var data = _userDataRepository.GetUserData(user, item);
diff --git a/Jellyfin.Api/Controllers/UserViewsController.cs b/Jellyfin.Api/Controllers/UserViewsController.cs
index 3d27371f6..04171da8a 100644
--- a/Jellyfin.Api/Controllers/UserViewsController.cs
+++ b/Jellyfin.Api/Controllers/UserViewsController.cs
@@ -108,11 +108,7 @@ namespace Jellyfin.Api.Controllers
var dtos = folders.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user))
.ToArray();
- return new QueryResult<BaseItemDto>
- {
- Items = dtos,
- TotalRecordCount = dtos.Length
- };
+ return new QueryResult<BaseItemDto>(dtos);
}
/// <summary>
diff --git a/Jellyfin.Api/Controllers/VideosController.cs b/Jellyfin.Api/Controllers/VideosController.cs
index 3c079a71d..62c05331e 100644
--- a/Jellyfin.Api/Controllers/VideosController.cs
+++ b/Jellyfin.Api/Controllers/VideosController.cs
@@ -109,14 +109,14 @@ namespace Jellyfin.Api.Controllers
[ProducesResponseType(StatusCodes.Status200OK)]
public ActionResult<QueryResult<BaseItemDto>> GetAdditionalPart([FromRoute, Required] Guid itemId, [FromQuery] Guid? userId)
{
- var user = userId.HasValue && !userId.Equals(Guid.Empty)
- ? _userManager.GetUserById(userId.Value)
- : null;
-
- var item = itemId.Equals(Guid.Empty)
- ? (!userId.Equals(Guid.Empty)
- ? _libraryManager.GetUserRootFolder()
- : _libraryManager.RootFolder)
+ var user = userId is null || userId.Value.Equals(default)
+ ? null
+ : _userManager.GetUserById(userId.Value);
+
+ var item = itemId.Equals(default)
+ ? (userId is null || userId.Value.Equals(default)
+ ? _libraryManager.RootFolder
+ : _libraryManager.GetUserRootFolder())
: _libraryManager.GetItemById(itemId);
var dtoOptions = new DtoOptions();
@@ -134,12 +134,7 @@ namespace Jellyfin.Api.Controllers
items = Array.Empty<BaseItemDto>();
}
- var result = new QueryResult<BaseItemDto>
- {
- Items = items,
- TotalRecordCount = items.Length
- };
-
+ var result = new QueryResult<BaseItemDto>(items);
return result;
}
@@ -226,7 +221,7 @@ namespace Jellyfin.Api.Controllers
var alternateVersionsOfPrimary = primaryVersion.LinkedAlternateVersions.ToList();
- foreach (var item in items.Where(i => i.Id != primaryVersion.Id))
+ foreach (var item in items.Where(i => !i.Id.Equals(primaryVersion.Id)))
{
item.SetPrimaryVersionId(primaryVersion.Id.ToString("N", CultureInfo.InvariantCulture));
@@ -470,7 +465,7 @@ namespace Jellyfin.Api.Controllers
StreamingHelpers.AddDlnaHeaders(state, Response.Headers, true, state.Request.StartTimeTicks, Request, _dlnaManager);
var httpClient = _httpClientFactory.CreateClient(NamedClient.Default);
- return await FileStreamResponseHelpers.GetStaticRemoteStreamResult(state, isHeadRequest, httpClient, HttpContext).ConfigureAwait(false);
+ return await FileStreamResponseHelpers.GetStaticRemoteStreamResult(state, httpClient, HttpContext).ConfigureAwait(false);
}
if (@static.HasValue && @static.Value && state.InputProtocol != MediaProtocol.File)
@@ -499,9 +494,7 @@ namespace Jellyfin.Api.Controllers
return FileStreamResponseHelpers.GetStaticFileResult(
state.MediaPath,
- contentType,
- isHeadRequest,
- HttpContext);
+ contentType);
}
// Need to start ffmpeg (because media can't be returned directly)
diff --git a/Jellyfin.Api/Controllers/YearsController.cs b/Jellyfin.Api/Controllers/YearsController.cs
index 8be6fd1b5..7c02e2550 100644
--- a/Jellyfin.Api/Controllers/YearsController.cs
+++ b/Jellyfin.Api/Controllers/YearsController.cs
@@ -90,16 +90,11 @@ namespace Jellyfin.Api.Controllers
.AddClientFields(Request)
.AddAdditionalDtoOptions(enableImages, enableUserData, imageTypeLimit, enableImageTypes);
- User? user = null;
+ User? user = userId is null || userId.Value.Equals(default)
+ ? null
+ : _userManager.GetUserById(userId.Value);
BaseItem parentItem = _libraryManager.GetParentItem(parentId, userId);
- if (userId.HasValue && !userId.Equals(Guid.Empty))
- {
- user = _userManager.GetUserById(userId.Value);
- }
-
- IList<BaseItem> items;
-
var query = new InternalItemsQuery(user)
{
ExcludeItemTypes = excludeItemTypes,
@@ -110,17 +105,18 @@ namespace Jellyfin.Api.Controllers
bool Filter(BaseItem i) => FilterItem(i, excludeItemTypes, includeItemTypes, mediaTypes);
+ IList<BaseItem> items;
if (parentItem.IsFolder)
{
var folder = (Folder)parentItem;
- if (!userId.Equals(Guid.Empty))
+ if (userId.Equals(default))
{
- items = recursive ? folder.GetRecursiveChildren(user, query).ToList() : folder.GetChildren(user, true).Where(Filter).ToList();
+ items = recursive ? folder.GetRecursiveChildren(Filter) : folder.Children.Where(Filter).ToList();
}
else
{
- items = recursive ? folder.GetRecursiveChildren(Filter) : folder.Children.Where(Filter).ToList();
+ items = recursive ? folder.GetRecursiveChildren(user, query).ToList() : folder.GetChildren(user, true).Where(Filter).ToList();
}
}
else
@@ -136,8 +132,6 @@ namespace Jellyfin.Api.Controllers
IEnumerable<BaseItem> ibnItems = ibnItemsArray;
- var result = new QueryResult<BaseItemDto> { TotalRecordCount = ibnItemsArray.Count };
-
if (startIndex.HasValue || limit.HasValue)
{
if (startIndex.HasValue)
@@ -155,8 +149,10 @@ namespace Jellyfin.Api.Controllers
var dtos = tuples.Select(i => _dtoService.GetItemByNameDto(i.Item1, dtoOptions, i.Item2, user));
- result.Items = dtos.Where(i => i != null).ToArray();
-
+ var result = new QueryResult<BaseItemDto>(
+ startIndex,
+ ibnItemsArray.Count,
+ dtos.Where(i => i != null).ToArray());
return result;
}
@@ -185,7 +181,7 @@ namespace Jellyfin.Api.Controllers
var dtoOptions = new DtoOptions()
.AddClientFields(Request);
- if (userId.HasValue && !userId.Equals(Guid.Empty))
+ if (userId.HasValue && !userId.Value.Equals(default))
{
var user = _userManager.GetUserById(userId.Value);
return _dtoService.GetBaseItemDto(item, dtoOptions, user);