aboutsummaryrefslogtreecommitdiff
path: root/Jellyfin.Api
diff options
context:
space:
mode:
Diffstat (limited to 'Jellyfin.Api')
-rw-r--r--Jellyfin.Api/Controllers/AudioController.cs24
-rw-r--r--Jellyfin.Api/Controllers/ConfigurationController.cs2
-rw-r--r--Jellyfin.Api/Controllers/DynamicHlsController.cs72
-rw-r--r--Jellyfin.Api/Controllers/HlsSegmentController.cs23
-rw-r--r--Jellyfin.Api/Controllers/ImageByNameController.cs23
-rw-r--r--Jellyfin.Api/Controllers/ImageController.cs12
-rw-r--r--Jellyfin.Api/Controllers/InstantMixController.cs90
-rw-r--r--Jellyfin.Api/Controllers/LibraryController.cs4
-rw-r--r--Jellyfin.Api/Controllers/PluginsController.cs2
-rw-r--r--Jellyfin.Api/Controllers/SessionController.cs32
-rw-r--r--Jellyfin.Api/Controllers/StartupController.cs5
-rw-r--r--Jellyfin.Api/Controllers/SubtitleController.cs66
-rw-r--r--Jellyfin.Api/Controllers/UniversalAudioController.cs8
-rw-r--r--Jellyfin.Api/Controllers/UserController.cs25
-rw-r--r--Jellyfin.Api/Controllers/VideoHlsController.cs12
-rw-r--r--Jellyfin.Api/Controllers/VideosController.cs12
-rw-r--r--Jellyfin.Api/Helpers/DynamicHlsHelper.cs2
-rw-r--r--Jellyfin.Api/Helpers/FileStreamResponseHelpers.cs7
-rw-r--r--Jellyfin.Api/Helpers/MediaInfoHelper.cs5
-rw-r--r--Jellyfin.Api/Helpers/RequestHelpers.cs2
-rw-r--r--Jellyfin.Api/Jellyfin.Api.csproj2
21 files changed, 299 insertions, 131 deletions
diff --git a/Jellyfin.Api/Controllers/AudioController.cs b/Jellyfin.Api/Controllers/AudioController.cs
index 8b1813b20..a6e70e72d 100644
--- a/Jellyfin.Api/Controllers/AudioController.cs
+++ b/Jellyfin.Api/Controllers/AudioController.cs
@@ -144,7 +144,7 @@ namespace Jellyfin.Api.Controllers
{
Id = itemId,
Container = container,
- Static = @static ?? true,
+ Static = @static ?? false,
Params = @params,
Tag = tag,
DeviceProfileId = deviceProfileId,
@@ -168,7 +168,7 @@ namespace Jellyfin.Api.Controllers
Level = level,
Framerate = framerate,
MaxFramerate = maxFramerate,
- CopyTimestamps = copyTimestamps ?? true,
+ CopyTimestamps = copyTimestamps ?? false,
StartTimeTicks = startTimeTicks,
Width = width,
Height = height,
@@ -177,13 +177,13 @@ namespace Jellyfin.Api.Controllers
SubtitleMethod = subtitleMethod ?? SubtitleDeliveryMethod.Encode,
MaxRefFrames = maxRefFrames,
MaxVideoBitDepth = maxVideoBitDepth,
- RequireAvc = requireAvc ?? true,
- DeInterlace = deInterlace ?? true,
- RequireNonAnamorphic = requireNonAnamorphic ?? true,
+ RequireAvc = requireAvc ?? false,
+ DeInterlace = deInterlace ?? false,
+ RequireNonAnamorphic = requireNonAnamorphic ?? false,
TranscodingMaxAudioChannels = transcodingMaxAudioChannels,
CpuCoreLimit = cpuCoreLimit,
LiveStreamId = liveStreamId,
- EnableMpegtsM2TsMode = enableMpegtsM2TsMode ?? true,
+ EnableMpegtsM2TsMode = enableMpegtsM2TsMode ?? false,
VideoCodec = videoCodec,
SubtitleCodec = subtitleCodec,
TranscodeReasons = transcodeReasons,
@@ -309,7 +309,7 @@ namespace Jellyfin.Api.Controllers
{
Id = itemId,
Container = container,
- Static = @static ?? true,
+ Static = @static ?? false,
Params = @params,
Tag = tag,
DeviceProfileId = deviceProfileId,
@@ -333,7 +333,7 @@ namespace Jellyfin.Api.Controllers
Level = level,
Framerate = framerate,
MaxFramerate = maxFramerate,
- CopyTimestamps = copyTimestamps ?? true,
+ CopyTimestamps = copyTimestamps ?? false,
StartTimeTicks = startTimeTicks,
Width = width,
Height = height,
@@ -342,13 +342,13 @@ namespace Jellyfin.Api.Controllers
SubtitleMethod = subtitleMethod ?? SubtitleDeliveryMethod.Encode,
MaxRefFrames = maxRefFrames,
MaxVideoBitDepth = maxVideoBitDepth,
- RequireAvc = requireAvc ?? true,
- DeInterlace = deInterlace ?? true,
- RequireNonAnamorphic = requireNonAnamorphic ?? true,
+ RequireAvc = requireAvc ?? false,
+ DeInterlace = deInterlace ?? false,
+ RequireNonAnamorphic = requireNonAnamorphic ?? false,
TranscodingMaxAudioChannels = transcodingMaxAudioChannels,
CpuCoreLimit = cpuCoreLimit,
LiveStreamId = liveStreamId,
- EnableMpegtsM2TsMode = enableMpegtsM2TsMode ?? true,
+ EnableMpegtsM2TsMode = enableMpegtsM2TsMode ?? false,
VideoCodec = videoCodec,
SubtitleCodec = subtitleCodec,
TranscodeReasons = transcodeReasons,
diff --git a/Jellyfin.Api/Controllers/ConfigurationController.cs b/Jellyfin.Api/Controllers/ConfigurationController.cs
index e1c9f69f6..049a4bed7 100644
--- a/Jellyfin.Api/Controllers/ConfigurationController.cs
+++ b/Jellyfin.Api/Controllers/ConfigurationController.cs
@@ -25,7 +25,7 @@ namespace Jellyfin.Api.Controllers
private readonly IServerConfigurationManager _configurationManager;
private readonly IMediaEncoder _mediaEncoder;
- private readonly JsonSerializerOptions _serializerOptions = JsonDefaults.GetOptions();
+ private readonly JsonSerializerOptions _serializerOptions = JsonDefaults.Options;
/// <summary>
/// Initializes a new instance of the <see cref="ConfigurationController"/> class.
diff --git a/Jellyfin.Api/Controllers/DynamicHlsController.cs b/Jellyfin.Api/Controllers/DynamicHlsController.cs
index f6c23c5aa..c4e75fe85 100644
--- a/Jellyfin.Api/Controllers/DynamicHlsController.cs
+++ b/Jellyfin.Api/Controllers/DynamicHlsController.cs
@@ -225,7 +225,7 @@ namespace Jellyfin.Api.Controllers
var streamingRequest = new HlsVideoRequestDto
{
Id = itemId,
- Static = @static ?? true,
+ Static = @static ?? false,
Params = @params,
Tag = tag,
DeviceProfileId = deviceProfileId,
@@ -249,7 +249,7 @@ namespace Jellyfin.Api.Controllers
Level = level,
Framerate = framerate,
MaxFramerate = maxFramerate,
- CopyTimestamps = copyTimestamps ?? true,
+ CopyTimestamps = copyTimestamps ?? false,
StartTimeTicks = startTimeTicks,
Width = width,
Height = height,
@@ -258,13 +258,13 @@ namespace Jellyfin.Api.Controllers
SubtitleMethod = subtitleMethod ?? SubtitleDeliveryMethod.Encode,
MaxRefFrames = maxRefFrames,
MaxVideoBitDepth = maxVideoBitDepth,
- RequireAvc = requireAvc ?? true,
- DeInterlace = deInterlace ?? true,
- RequireNonAnamorphic = requireNonAnamorphic ?? true,
+ RequireAvc = requireAvc ?? false,
+ DeInterlace = deInterlace ?? false,
+ RequireNonAnamorphic = requireNonAnamorphic ?? false,
TranscodingMaxAudioChannels = transcodingMaxAudioChannels,
CpuCoreLimit = cpuCoreLimit,
LiveStreamId = liveStreamId,
- EnableMpegtsM2TsMode = enableMpegtsM2TsMode ?? true,
+ EnableMpegtsM2TsMode = enableMpegtsM2TsMode ?? false,
VideoCodec = videoCodec,
SubtitleCodec = subtitleCodec,
TranscodeReasons = transcodeReasons,
@@ -392,7 +392,7 @@ namespace Jellyfin.Api.Controllers
var streamingRequest = new HlsAudioRequestDto
{
Id = itemId,
- Static = @static ?? true,
+ Static = @static ?? false,
Params = @params,
Tag = tag,
DeviceProfileId = deviceProfileId,
@@ -416,7 +416,7 @@ namespace Jellyfin.Api.Controllers
Level = level,
Framerate = framerate,
MaxFramerate = maxFramerate,
- CopyTimestamps = copyTimestamps ?? true,
+ CopyTimestamps = copyTimestamps ?? false,
StartTimeTicks = startTimeTicks,
Width = width,
Height = height,
@@ -425,13 +425,13 @@ namespace Jellyfin.Api.Controllers
SubtitleMethod = subtitleMethod ?? SubtitleDeliveryMethod.Encode,
MaxRefFrames = maxRefFrames,
MaxVideoBitDepth = maxVideoBitDepth,
- RequireAvc = requireAvc ?? true,
- DeInterlace = deInterlace ?? true,
- RequireNonAnamorphic = requireNonAnamorphic ?? true,
+ RequireAvc = requireAvc ?? false,
+ DeInterlace = deInterlace ?? false,
+ RequireNonAnamorphic = requireNonAnamorphic ?? false,
TranscodingMaxAudioChannels = transcodingMaxAudioChannels,
CpuCoreLimit = cpuCoreLimit,
LiveStreamId = liveStreamId,
- EnableMpegtsM2TsMode = enableMpegtsM2TsMode ?? true,
+ EnableMpegtsM2TsMode = enableMpegtsM2TsMode ?? false,
VideoCodec = videoCodec,
SubtitleCodec = subtitleCodec,
TranscodeReasons = transcodeReasons,
@@ -555,7 +555,7 @@ namespace Jellyfin.Api.Controllers
var streamingRequest = new VideoRequestDto
{
Id = itemId,
- Static = @static ?? true,
+ Static = @static ?? false,
Params = @params,
Tag = tag,
DeviceProfileId = deviceProfileId,
@@ -579,7 +579,7 @@ namespace Jellyfin.Api.Controllers
Level = level,
Framerate = framerate,
MaxFramerate = maxFramerate,
- CopyTimestamps = copyTimestamps ?? true,
+ CopyTimestamps = copyTimestamps ?? false,
StartTimeTicks = startTimeTicks,
Width = width,
Height = height,
@@ -588,13 +588,13 @@ namespace Jellyfin.Api.Controllers
SubtitleMethod = subtitleMethod ?? SubtitleDeliveryMethod.Encode,
MaxRefFrames = maxRefFrames,
MaxVideoBitDepth = maxVideoBitDepth,
- RequireAvc = requireAvc ?? true,
- DeInterlace = deInterlace ?? true,
- RequireNonAnamorphic = requireNonAnamorphic ?? true,
+ RequireAvc = requireAvc ?? false,
+ DeInterlace = deInterlace ?? false,
+ RequireNonAnamorphic = requireNonAnamorphic ?? false,
TranscodingMaxAudioChannels = transcodingMaxAudioChannels,
CpuCoreLimit = cpuCoreLimit,
LiveStreamId = liveStreamId,
- EnableMpegtsM2TsMode = enableMpegtsM2TsMode ?? true,
+ EnableMpegtsM2TsMode = enableMpegtsM2TsMode ?? false,
VideoCodec = videoCodec,
SubtitleCodec = subtitleCodec,
TranscodeReasons = transcodeReasons,
@@ -720,7 +720,7 @@ namespace Jellyfin.Api.Controllers
var streamingRequest = new StreamingRequestDto
{
Id = itemId,
- Static = @static ?? true,
+ Static = @static ?? false,
Params = @params,
Tag = tag,
DeviceProfileId = deviceProfileId,
@@ -744,7 +744,7 @@ namespace Jellyfin.Api.Controllers
Level = level,
Framerate = framerate,
MaxFramerate = maxFramerate,
- CopyTimestamps = copyTimestamps ?? true,
+ CopyTimestamps = copyTimestamps ?? false,
StartTimeTicks = startTimeTicks,
Width = width,
Height = height,
@@ -753,13 +753,13 @@ namespace Jellyfin.Api.Controllers
SubtitleMethod = subtitleMethod ?? SubtitleDeliveryMethod.Encode,
MaxRefFrames = maxRefFrames,
MaxVideoBitDepth = maxVideoBitDepth,
- RequireAvc = requireAvc ?? true,
- DeInterlace = deInterlace ?? true,
- RequireNonAnamorphic = requireNonAnamorphic ?? true,
+ RequireAvc = requireAvc ?? false,
+ DeInterlace = deInterlace ?? false,
+ RequireNonAnamorphic = requireNonAnamorphic ?? false,
TranscodingMaxAudioChannels = transcodingMaxAudioChannels,
CpuCoreLimit = cpuCoreLimit,
LiveStreamId = liveStreamId,
- EnableMpegtsM2TsMode = enableMpegtsM2TsMode ?? true,
+ EnableMpegtsM2TsMode = enableMpegtsM2TsMode ?? false,
VideoCodec = videoCodec,
SubtitleCodec = subtitleCodec,
TranscodeReasons = transcodeReasons,
@@ -890,7 +890,7 @@ namespace Jellyfin.Api.Controllers
{
Id = itemId,
Container = container,
- Static = @static ?? true,
+ Static = @static ?? false,
Params = @params,
Tag = tag,
DeviceProfileId = deviceProfileId,
@@ -914,7 +914,7 @@ namespace Jellyfin.Api.Controllers
Level = level,
Framerate = framerate,
MaxFramerate = maxFramerate,
- CopyTimestamps = copyTimestamps ?? true,
+ CopyTimestamps = copyTimestamps ?? false,
StartTimeTicks = startTimeTicks,
Width = width,
Height = height,
@@ -923,13 +923,13 @@ namespace Jellyfin.Api.Controllers
SubtitleMethod = subtitleMethod ?? SubtitleDeliveryMethod.Encode,
MaxRefFrames = maxRefFrames,
MaxVideoBitDepth = maxVideoBitDepth,
- RequireAvc = requireAvc ?? true,
- DeInterlace = deInterlace ?? true,
- RequireNonAnamorphic = requireNonAnamorphic ?? true,
+ RequireAvc = requireAvc ?? false,
+ DeInterlace = deInterlace ?? false,
+ RequireNonAnamorphic = requireNonAnamorphic ?? false,
TranscodingMaxAudioChannels = transcodingMaxAudioChannels,
CpuCoreLimit = cpuCoreLimit,
LiveStreamId = liveStreamId,
- EnableMpegtsM2TsMode = enableMpegtsM2TsMode ?? true,
+ EnableMpegtsM2TsMode = enableMpegtsM2TsMode ?? false,
VideoCodec = videoCodec,
SubtitleCodec = subtitleCodec,
TranscodeReasons = transcodeReasons,
@@ -1062,7 +1062,7 @@ namespace Jellyfin.Api.Controllers
{
Id = itemId,
Container = container,
- Static = @static ?? true,
+ Static = @static ?? false,
Params = @params,
Tag = tag,
DeviceProfileId = deviceProfileId,
@@ -1086,7 +1086,7 @@ namespace Jellyfin.Api.Controllers
Level = level,
Framerate = framerate,
MaxFramerate = maxFramerate,
- CopyTimestamps = copyTimestamps ?? true,
+ CopyTimestamps = copyTimestamps ?? false,
StartTimeTicks = startTimeTicks,
Width = width,
Height = height,
@@ -1095,13 +1095,13 @@ namespace Jellyfin.Api.Controllers
SubtitleMethod = subtitleMethod ?? SubtitleDeliveryMethod.Encode,
MaxRefFrames = maxRefFrames,
MaxVideoBitDepth = maxVideoBitDepth,
- RequireAvc = requireAvc ?? true,
- DeInterlace = deInterlace ?? true,
- RequireNonAnamorphic = requireNonAnamorphic ?? true,
+ RequireAvc = requireAvc ?? false,
+ DeInterlace = deInterlace ?? false,
+ RequireNonAnamorphic = requireNonAnamorphic ?? false,
TranscodingMaxAudioChannels = transcodingMaxAudioChannels,
CpuCoreLimit = cpuCoreLimit,
LiveStreamId = liveStreamId,
- EnableMpegtsM2TsMode = enableMpegtsM2TsMode ?? true,
+ EnableMpegtsM2TsMode = enableMpegtsM2TsMode ?? false,
VideoCodec = videoCodec,
SubtitleCodec = subtitleCodec,
TranscodeReasons = transcodeReasons,
diff --git a/Jellyfin.Api/Controllers/HlsSegmentController.cs b/Jellyfin.Api/Controllers/HlsSegmentController.cs
index d0ed45acb..473bdc523 100644
--- a/Jellyfin.Api/Controllers/HlsSegmentController.cs
+++ b/Jellyfin.Api/Controllers/HlsSegmentController.cs
@@ -61,7 +61,13 @@ namespace Jellyfin.Api.Controllers
{
// TODO: Deprecate with new iOS app
var file = segmentId + Path.GetExtension(Request.Path);
- file = Path.Combine(_serverConfigurationManager.GetTranscodePath(), file);
+ var transcodePath = _serverConfigurationManager.GetTranscodePath();
+ file = Path.GetFullPath(Path.Combine(transcodePath, file));
+ var fileDir = Path.GetDirectoryName(file);
+ if (string.IsNullOrEmpty(fileDir) || !fileDir.StartsWith(transcodePath))
+ {
+ return BadRequest("Invalid segment.");
+ }
return FileStreamResponseHelpers.GetStaticFileResult(file, MimeTypes.GetMimeType(file)!, false, HttpContext);
}
@@ -81,7 +87,13 @@ namespace Jellyfin.Api.Controllers
public ActionResult GetHlsPlaylistLegacy([FromRoute, Required] string itemId, [FromRoute, Required] string playlistId)
{
var file = playlistId + Path.GetExtension(Request.Path);
- file = Path.Combine(_serverConfigurationManager.GetTranscodePath(), file);
+ var transcodePath = _serverConfigurationManager.GetTranscodePath();
+ file = Path.GetFullPath(Path.Combine(transcodePath, file));
+ var fileDir = Path.GetDirectoryName(file);
+ if (string.IsNullOrEmpty(fileDir) || !fileDir.StartsWith(transcodePath) || Path.GetExtension(file) != ".m3u8")
+ {
+ return BadRequest("Invalid segment.");
+ }
return GetFileResult(file, file);
}
@@ -130,7 +142,12 @@ namespace Jellyfin.Api.Controllers
var file = segmentId + Path.GetExtension(Request.Path);
var transcodeFolderPath = _serverConfigurationManager.GetTranscodePath();
- file = Path.Combine(transcodeFolderPath, file);
+ file = Path.GetFullPath(Path.Combine(transcodeFolderPath, file));
+ var fileDir = Path.GetDirectoryName(file);
+ if (string.IsNullOrEmpty(fileDir) || !fileDir.StartsWith(transcodeFolderPath))
+ {
+ return BadRequest("Invalid segment.");
+ }
var normalizedPlaylistId = playlistId;
diff --git a/Jellyfin.Api/Controllers/ImageByNameController.cs b/Jellyfin.Api/Controllers/ImageByNameController.cs
index 198dbc51f..e1b808098 100644
--- a/Jellyfin.Api/Controllers/ImageByNameController.cs
+++ b/Jellyfin.Api/Controllers/ImageByNameController.cs
@@ -74,7 +74,7 @@ namespace Jellyfin.Api.Controllers
: type;
var path = BaseItem.SupportedImageExtensions
- .Select(i => Path.Combine(_applicationPaths.GeneralPath, name, filename + i))
+ .Select(i => Path.GetFullPath(Path.Combine(_applicationPaths.GeneralPath, name, filename + i)))
.FirstOrDefault(System.IO.File.Exists);
if (path == null)
@@ -82,6 +82,11 @@ namespace Jellyfin.Api.Controllers
return NotFound();
}
+ if (!path.StartsWith(_applicationPaths.GeneralPath))
+ {
+ return BadRequest("Invalid image path.");
+ }
+
var contentType = MimeTypes.GetMimeType(path);
return File(System.IO.File.OpenRead(path), contentType);
}
@@ -163,7 +168,8 @@ namespace Jellyfin.Api.Controllers
/// <returns>A <see cref="FileStreamResult"/> containing the image contents on success, or a <see cref="NotFoundResult"/> if the image could not be found.</returns>
private ActionResult GetImageFile(string basePath, string theme, string? name)
{
- var themeFolder = Path.Combine(basePath, theme);
+ var themeFolder = Path.GetFullPath(Path.Combine(basePath, theme));
+
if (Directory.Exists(themeFolder))
{
var path = BaseItem.SupportedImageExtensions.Select(i => Path.Combine(themeFolder, name + i))
@@ -171,12 +177,18 @@ namespace Jellyfin.Api.Controllers
if (!string.IsNullOrEmpty(path) && System.IO.File.Exists(path))
{
+ if (!path.StartsWith(basePath))
+ {
+ return BadRequest("Invalid image path.");
+ }
+
var contentType = MimeTypes.GetMimeType(path);
+
return PhysicalFile(path, contentType);
}
}
- var allFolder = Path.Combine(basePath, "all");
+ var allFolder = Path.GetFullPath(Path.Combine(basePath, "all"));
if (Directory.Exists(allFolder))
{
var path = BaseItem.SupportedImageExtensions.Select(i => Path.Combine(allFolder, name + i))
@@ -184,6 +196,11 @@ namespace Jellyfin.Api.Controllers
if (!string.IsNullOrEmpty(path) && System.IO.File.Exists(path))
{
+ if (!path.StartsWith(basePath))
+ {
+ return BadRequest("Invalid image path.");
+ }
+
var contentType = MimeTypes.GetMimeType(path);
return PhysicalFile(path, contentType);
}
diff --git a/Jellyfin.Api/Controllers/ImageController.cs b/Jellyfin.Api/Controllers/ImageController.cs
index cfc038f23..89037749a 100644
--- a/Jellyfin.Api/Controllers/ImageController.cs
+++ b/Jellyfin.Api/Controllers/ImageController.cs
@@ -196,6 +196,11 @@ namespace Jellyfin.Api.Controllers
}
var user = _userManager.GetUserById(userId);
+ if (user?.ProfileImage == null)
+ {
+ return NoContent();
+ }
+
try
{
System.IO.File.Delete(user.ProfileImage.Path);
@@ -235,6 +240,11 @@ namespace Jellyfin.Api.Controllers
}
var user = _userManager.GetUserById(userId);
+ if (user?.ProfileImage == null)
+ {
+ return NoContent();
+ }
+
try
{
System.IO.File.Delete(user.ProfileImage.Path);
@@ -1469,7 +1479,7 @@ namespace Jellyfin.Api.Controllers
[FromQuery] int? imageIndex)
{
var user = _userManager.GetUserById(userId);
- if (user == null)
+ if (user?.ProfileImage == null)
{
return NotFound();
}
diff --git a/Jellyfin.Api/Controllers/InstantMixController.cs b/Jellyfin.Api/Controllers/InstantMixController.cs
index f061755c3..f232dffaa 100644
--- a/Jellyfin.Api/Controllers/InstantMixController.cs
+++ b/Jellyfin.Api/Controllers/InstantMixController.cs
@@ -86,7 +86,7 @@ namespace Jellyfin.Api.Controllers
}
/// <summary>
- /// Creates an instant playlist based on a given song.
+ /// Creates an instant playlist based on a given album.
/// </summary>
/// <param name="id">The item id.</param>
/// <param name="userId">Optional. Filter by user id, and attach user data.</param>
@@ -122,7 +122,7 @@ namespace Jellyfin.Api.Controllers
}
/// <summary>
- /// Creates an instant playlist based on a given song.
+ /// Creates an instant playlist based on a given playlist.
/// </summary>
/// <param name="id">The item id.</param>
/// <param name="userId">Optional. Filter by user id, and attach user data.</param>
@@ -158,7 +158,7 @@ namespace Jellyfin.Api.Controllers
}
/// <summary>
- /// Creates an instant playlist based on a given song.
+ /// Creates an instant playlist based on a given genre.
/// </summary>
/// <param name="name">The genre name.</param>
/// <param name="userId">Optional. Filter by user id, and attach user data.</param>
@@ -172,7 +172,7 @@ namespace Jellyfin.Api.Controllers
/// <returns>A <see cref="QueryResult{BaseItemDto}"/> with the playlist items.</returns>
[HttpGet("MusicGenres/{name}/InstantMix")]
[ProducesResponseType(StatusCodes.Status200OK)]
- public ActionResult<QueryResult<BaseItemDto>> GetInstantMixFromMusicGenre(
+ public ActionResult<QueryResult<BaseItemDto>> GetInstantMixFromMusicGenreByName(
[FromRoute, Required] string name,
[FromQuery] Guid? userId,
[FromQuery] int? limit,
@@ -193,7 +193,7 @@ namespace Jellyfin.Api.Controllers
}
/// <summary>
- /// Creates an instant playlist based on a given song.
+ /// Creates an instant playlist based on a given artist.
/// </summary>
/// <param name="id">The item id.</param>
/// <param name="userId">Optional. Filter by user id, and attach user data.</param>
@@ -229,7 +229,7 @@ namespace Jellyfin.Api.Controllers
}
/// <summary>
- /// Creates an instant playlist based on a given song.
+ /// Creates an instant playlist based on a given genre.
/// </summary>
/// <param name="id">The item id.</param>
/// <param name="userId">Optional. Filter by user id, and attach user data.</param>
@@ -243,7 +243,7 @@ namespace Jellyfin.Api.Controllers
/// <returns>A <see cref="QueryResult{BaseItemDto}"/> with the playlist items.</returns>
[HttpGet("MusicGenres/{id}/InstantMix")]
[ProducesResponseType(StatusCodes.Status200OK)]
- public ActionResult<QueryResult<BaseItemDto>> GetInstantMixFromMusicGenres(
+ public ActionResult<QueryResult<BaseItemDto>> GetInstantMixFromMusicGenreById(
[FromRoute, Required] Guid id,
[FromQuery] Guid? userId,
[FromQuery] int? limit,
@@ -265,7 +265,7 @@ namespace Jellyfin.Api.Controllers
}
/// <summary>
- /// Creates an instant playlist based on a given song.
+ /// Creates an instant playlist based on a given item.
/// </summary>
/// <param name="id">The item id.</param>
/// <param name="userId">Optional. Filter by user id, and attach user data.</param>
@@ -300,6 +300,80 @@ namespace Jellyfin.Api.Controllers
return GetResult(items, user, limit, dtoOptions);
}
+ /// <summary>
+ /// Creates an instant playlist based on a given artist.
+ /// </summary>
+ /// <param name="id">The item id.</param>
+ /// <param name="userId">Optional. Filter by user id, and attach user data.</param>
+ /// <param name="limit">Optional. The maximum number of records to return.</param>
+ /// <param name="fields">Optional. Specify additional fields of information to return in the output.</param>
+ /// <param name="enableImages">Optional. Include image information in output.</param>
+ /// <param name="enableUserData">Optional. Include user data.</param>
+ /// <param name="imageTypeLimit">Optional. The max number of images to return, per image type.</param>
+ /// <param name="enableImageTypes">Optional. The image types to include in the output.</param>
+ /// <response code="200">Instant playlist returned.</response>
+ /// <returns>A <see cref="QueryResult{BaseItemDto}"/> with the playlist items.</returns>
+ [HttpGet("Artists/InstantMix")]
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ [Obsolete("Use GetInstantMixFromArtists")]
+ public ActionResult<QueryResult<BaseItemDto>> GetInstantMixFromArtists2(
+ [FromQuery, Required] Guid id,
+ [FromQuery] Guid? userId,
+ [FromQuery] int? limit,
+ [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields,
+ [FromQuery] bool? enableImages,
+ [FromQuery] bool? enableUserData,
+ [FromQuery] int? imageTypeLimit,
+ [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes)
+ {
+ return GetInstantMixFromArtists(
+ id,
+ userId,
+ limit,
+ fields,
+ enableImages,
+ enableUserData,
+ imageTypeLimit,
+ enableImageTypes);
+ }
+
+ /// <summary>
+ /// Creates an instant playlist based on a given genre.
+ /// </summary>
+ /// <param name="id">The item id.</param>
+ /// <param name="userId">Optional. Filter by user id, and attach user data.</param>
+ /// <param name="limit">Optional. The maximum number of records to return.</param>
+ /// <param name="fields">Optional. Specify additional fields of information to return in the output.</param>
+ /// <param name="enableImages">Optional. Include image information in output.</param>
+ /// <param name="enableUserData">Optional. Include user data.</param>
+ /// <param name="imageTypeLimit">Optional. The max number of images to return, per image type.</param>
+ /// <param name="enableImageTypes">Optional. The image types to include in the output.</param>
+ /// <response code="200">Instant playlist returned.</response>
+ /// <returns>A <see cref="QueryResult{BaseItemDto}"/> with the playlist items.</returns>
+ [HttpGet("MusicGenres/InstantMix")]
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ [Obsolete("Use GetInstantMixFromMusicGenres instead")]
+ public ActionResult<QueryResult<BaseItemDto>> GetInstantMixFromMusicGenreById2(
+ [FromQuery, Required] Guid id,
+ [FromQuery] Guid? userId,
+ [FromQuery] int? limit,
+ [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields,
+ [FromQuery] bool? enableImages,
+ [FromQuery] bool? enableUserData,
+ [FromQuery] int? imageTypeLimit,
+ [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes)
+ {
+ return GetInstantMixFromMusicGenreById(
+ id,
+ userId,
+ limit,
+ fields,
+ enableImages,
+ enableUserData,
+ imageTypeLimit,
+ enableImageTypes);
+ }
+
private QueryResult<BaseItemDto> GetResult(List<BaseItem> items, User? user, int? limit, DtoOptions dtoOptions)
{
var list = items;
diff --git a/Jellyfin.Api/Controllers/LibraryController.cs b/Jellyfin.Api/Controllers/LibraryController.cs
index f8e8825ef..1d4bbe61e 100644
--- a/Jellyfin.Api/Controllers/LibraryController.cs
+++ b/Jellyfin.Api/Controllers/LibraryController.cs
@@ -114,7 +114,7 @@ namespace Jellyfin.Api.Controllers
return NotFound();
}
- return PhysicalFile(item.Path, MimeTypes.GetMimeType(item.Path));
+ return PhysicalFile(item.Path, MimeTypes.GetMimeType(item.Path), true);
}
/// <summary>
@@ -666,7 +666,7 @@ namespace Jellyfin.Api.Controllers
}
// TODO determine non-ASCII validity.
- return PhysicalFile(path, MimeTypes.GetMimeType(path), filename);
+ return PhysicalFile(path, MimeTypes.GetMimeType(path), filename, true);
}
/// <summary>
diff --git a/Jellyfin.Api/Controllers/PluginsController.cs b/Jellyfin.Api/Controllers/PluginsController.cs
index a5aa9bfca..24285bfb9 100644
--- a/Jellyfin.Api/Controllers/PluginsController.cs
+++ b/Jellyfin.Api/Controllers/PluginsController.cs
@@ -45,7 +45,7 @@ namespace Jellyfin.Api.Controllers
{
_installationManager = installationManager;
_pluginManager = pluginManager;
- _serializerOptions = JsonDefaults.GetOptions();
+ _serializerOptions = JsonDefaults.Options;
_config = config;
}
diff --git a/Jellyfin.Api/Controllers/SessionController.cs b/Jellyfin.Api/Controllers/SessionController.cs
index e2269a2ce..7bd0b6918 100644
--- a/Jellyfin.Api/Controllers/SessionController.cs
+++ b/Jellyfin.Api/Controllers/SessionController.cs
@@ -153,6 +153,10 @@ namespace Jellyfin.Api.Controllers
/// <param name="playCommand">The type of play command to issue (PlayNow, PlayNext, PlayLast). Clients who have not yet implemented play next and play last may play now.</param>
/// <param name="itemIds">The ids of the items to play, comma delimited.</param>
/// <param name="startPositionTicks">The starting position of the first item.</param>
+ /// <param name="mediaSourceId">Optional. The media source id.</param>
+ /// <param name="audioStreamIndex">Optional. The index of the audio stream to play.</param>
+ /// <param name="subtitleStreamIndex">Optional. The index of the subtitle stream to play.</param>
+ /// <param name="startIndex">Optional. The start index.</param>
/// <response code="204">Instruction sent to session.</response>
/// <returns>A <see cref="NoContentResult"/>.</returns>
[HttpPost("Sessions/{sessionId}/Playing")]
@@ -162,13 +166,21 @@ namespace Jellyfin.Api.Controllers
[FromRoute, Required] string sessionId,
[FromQuery, Required] PlayCommand playCommand,
[FromQuery, Required, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] itemIds,
- [FromQuery] long? startPositionTicks)
+ [FromQuery] long? startPositionTicks,
+ [FromQuery] string? mediaSourceId,
+ [FromQuery] int? audioStreamIndex,
+ [FromQuery] int? subtitleStreamIndex,
+ [FromQuery] int? startIndex)
{
var playRequest = new PlayRequest
{
ItemIds = itemIds,
StartPositionTicks = startPositionTicks,
- PlayCommand = playCommand
+ PlayCommand = playCommand,
+ MediaSourceId = mediaSourceId,
+ AudioStreamIndex = audioStreamIndex,
+ SubtitleStreamIndex = subtitleStreamIndex,
+ StartIndex = startIndex
};
_sessionManager.SendPlayCommand(
@@ -301,9 +313,7 @@ namespace Jellyfin.Api.Controllers
/// Issues a command to a client to display a message to the user.
/// </summary>
/// <param name="sessionId">The session id.</param>
- /// <param name="text">The message test.</param>
- /// <param name="header">The message header.</param>
- /// <param name="timeoutMs">The message timeout. If omitted the user will have to confirm viewing the message.</param>
+ /// <param name="command">The <see cref="MessageCommand" /> object containing Header, Message Text, and TimeoutMs.</param>
/// <response code="204">Message sent.</response>
/// <returns>A <see cref="NoContentResult"/>.</returns>
[HttpPost("Sessions/{sessionId}/Message")]
@@ -311,16 +321,12 @@ namespace Jellyfin.Api.Controllers
[ProducesResponseType(StatusCodes.Status204NoContent)]
public ActionResult SendMessageCommand(
[FromRoute, Required] string sessionId,
- [FromQuery, Required] string text,
- [FromQuery] string? header,
- [FromQuery] long? timeoutMs)
+ [FromBody, Required] MessageCommand command)
{
- var command = new MessageCommand
+ if (string.IsNullOrWhiteSpace(command.Header))
{
- Header = string.IsNullOrEmpty(header) ? "Message from Server" : header,
- TimeoutMs = timeoutMs,
- Text = text
- };
+ command.Header = "Message from Server";
+ }
_sessionManager.SendMessageCommand(RequestHelpers.GetSession(_sessionManager, _authContext, Request).Id, sessionId, command, CancellationToken.None);
diff --git a/Jellyfin.Api/Controllers/StartupController.cs b/Jellyfin.Api/Controllers/StartupController.cs
index d9cb34557..a01a617fc 100644
--- a/Jellyfin.Api/Controllers/StartupController.cs
+++ b/Jellyfin.Api/Controllers/StartupController.cs
@@ -132,7 +132,10 @@ namespace Jellyfin.Api.Controllers
{
var user = _userManager.Users.First();
- user.Username = startupUserDto.Name;
+ if (startupUserDto.Name != null)
+ {
+ user.Username = startupUserDto.Name;
+ }
await _userManager.UpdateUserAsync(user).ConfigureAwait(false);
diff --git a/Jellyfin.Api/Controllers/SubtitleController.cs b/Jellyfin.Api/Controllers/SubtitleController.cs
index 16a47f2d8..1669a659d 100644
--- a/Jellyfin.Api/Controllers/SubtitleController.cs
+++ b/Jellyfin.Api/Controllers/SubtitleController.cs
@@ -182,6 +182,10 @@ namespace Jellyfin.Api.Controllers
/// <summary>
/// Gets subtitles in a specified format.
/// </summary>
+ /// <param name="routeItemId">The (route) item id.</param>
+ /// <param name="routeMediaSourceId">The (route) media source id.</param>
+ /// <param name="routeIndex">The (route) subtitle stream index.</param>
+ /// <param name="routeFormat">The (route) format of the returned subtitle.</param>
/// <param name="itemId">The item id.</param>
/// <param name="mediaSourceId">The media source id.</param>
/// <param name="index">The subtitle stream index.</param>
@@ -189,22 +193,32 @@ namespace Jellyfin.Api.Controllers
/// <param name="endPositionTicks">Optional. The end position of the subtitle in ticks.</param>
/// <param name="copyTimestamps">Optional. Whether to copy the timestamps.</param>
/// <param name="addVttTimeMap">Optional. Whether to add a VTT time map.</param>
- /// <param name="startPositionTicks">Optional. The start position of the subtitle in ticks.</param>
+ /// <param name="startPositionTicks">The start position of the subtitle in ticks.</param>
/// <response code="200">File returned.</response>
/// <returns>A <see cref="FileContentResult"/> with the subtitle file.</returns>
- [HttpGet("Videos/{itemId}/{mediaSourceId}/Subtitles/{index}/Stream.{format}")]
+ [HttpGet("Videos/{routeItemId}/routeMediaSourceId/Subtitles/{routeIndex}/Stream.{routeFormat}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesFile("text/*")]
public async Task<ActionResult> GetSubtitle(
- [FromRoute, Required] Guid itemId,
- [FromRoute, Required] string mediaSourceId,
- [FromRoute, Required] int index,
- [FromRoute, Required] string format,
+ [FromRoute, Required] Guid routeItemId,
+ [FromRoute, Required] string routeMediaSourceId,
+ [FromRoute, Required] int routeIndex,
+ [FromRoute, Required] string routeFormat,
+ [FromQuery, ParameterObsolete] Guid? itemId,
+ [FromQuery, ParameterObsolete] string? mediaSourceId,
+ [FromQuery, ParameterObsolete] int? index,
+ [FromQuery, ParameterObsolete] string? format,
[FromQuery] long? endPositionTicks,
[FromQuery] bool copyTimestamps = false,
[FromQuery] bool addVttTimeMap = false,
[FromQuery] long startPositionTicks = 0)
{
+ // Set parameters to route value if not provided via query.
+ itemId ??= routeItemId;
+ mediaSourceId ??= routeMediaSourceId;
+ index ??= routeIndex;
+ format ??= routeFormat;
+
if (string.Equals(format, "js", StringComparison.OrdinalIgnoreCase))
{
format = "json";
@@ -212,9 +226,9 @@ namespace Jellyfin.Api.Controllers
if (string.IsNullOrEmpty(format))
{
- var item = (Video)_libraryManager.GetItemById(itemId);
+ var item = (Video)_libraryManager.GetItemById(itemId.Value);
- var idString = itemId.ToString("N", CultureInfo.InvariantCulture);
+ var idString = itemId.Value.ToString("N", CultureInfo.InvariantCulture);
var mediaSource = _mediaSourceManager.GetStaticMediaSources(item, false)
.First(i => string.Equals(i.Id, mediaSourceId ?? idString, StringComparison.Ordinal));
@@ -226,7 +240,7 @@ namespace Jellyfin.Api.Controllers
if (string.Equals(format, "vtt", StringComparison.OrdinalIgnoreCase) && addVttTimeMap)
{
- await using Stream stream = await EncodeSubtitles(itemId, mediaSourceId, index, format, startPositionTicks, endPositionTicks, copyTimestamps).ConfigureAwait(false);
+ await using Stream stream = await EncodeSubtitles(itemId.Value, mediaSourceId, index.Value, format, startPositionTicks, endPositionTicks, copyTimestamps).ConfigureAwait(false);
using var reader = new StreamReader(stream);
var text = await reader.ReadToEndAsync().ConfigureAwait(false);
@@ -238,9 +252,9 @@ namespace Jellyfin.Api.Controllers
return File(
await EncodeSubtitles(
- itemId,
+ itemId.Value,
mediaSourceId,
- index,
+ index.Value,
format,
startPositionTicks,
endPositionTicks,
@@ -251,30 +265,44 @@ namespace Jellyfin.Api.Controllers
/// <summary>
/// Gets subtitles in a specified format.
/// </summary>
+ /// <param name="routeItemId">The (route) item id.</param>
+ /// <param name="routeMediaSourceId">The (route) media source id.</param>
+ /// <param name="routeIndex">The (route) subtitle stream index.</param>
+ /// <param name="routeStartPositionTicks">The (route) start position of the subtitle in ticks.</param>
+ /// <param name="routeFormat">The (route) format of the returned subtitle.</param>
/// <param name="itemId">The item id.</param>
/// <param name="mediaSourceId">The media source id.</param>
/// <param name="index">The subtitle stream index.</param>
- /// <param name="startPositionTicks">Optional. The start position of the subtitle in ticks.</param>
+ /// <param name="startPositionTicks">The start position of the subtitle in ticks.</param>
/// <param name="format">The format of the returned subtitle.</param>
/// <param name="endPositionTicks">Optional. The end position of the subtitle in ticks.</param>
/// <param name="copyTimestamps">Optional. Whether to copy the timestamps.</param>
/// <param name="addVttTimeMap">Optional. Whether to add a VTT time map.</param>
/// <response code="200">File returned.</response>
/// <returns>A <see cref="FileContentResult"/> with the subtitle file.</returns>
- [HttpGet("Videos/{itemId}/{mediaSourceId}/Subtitles/{index}/{startPositionTicks}/Stream.{format}")]
+ [HttpGet("Videos/{routeItemId}/{routeMediaSourceId}/Subtitles/{routeIndex}/{routeStartPositionTicks}/Stream.{routeFormat}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesFile("text/*")]
public Task<ActionResult> GetSubtitleWithTicks(
- [FromRoute, Required] Guid itemId,
- [FromRoute, Required] string mediaSourceId,
- [FromRoute, Required] int index,
- [FromRoute, Required] long startPositionTicks,
- [FromRoute, Required] string format,
+ [FromRoute, Required] Guid routeItemId,
+ [FromRoute, Required] string routeMediaSourceId,
+ [FromRoute, Required] int routeIndex,
+ [FromRoute, Required] long routeStartPositionTicks,
+ [FromRoute, Required] string routeFormat,
+ [FromQuery, ParameterObsolete] Guid? itemId,
+ [FromQuery, ParameterObsolete] string? mediaSourceId,
+ [FromQuery, ParameterObsolete] int? index,
+ [FromQuery, ParameterObsolete] long? startPositionTicks,
+ [FromQuery, ParameterObsolete] string? format,
[FromQuery] long? endPositionTicks,
[FromQuery] bool copyTimestamps = false,
[FromQuery] bool addVttTimeMap = false)
{
return GetSubtitle(
+ routeItemId,
+ routeMediaSourceId,
+ routeIndex,
+ routeFormat,
itemId,
mediaSourceId,
index,
@@ -282,7 +310,7 @@ namespace Jellyfin.Api.Controllers
endPositionTicks,
copyTimestamps,
addVttTimeMap,
- startPositionTicks);
+ startPositionTicks ?? routeStartPositionTicks);
}
/// <summary>
diff --git a/Jellyfin.Api/Controllers/UniversalAudioController.cs b/Jellyfin.Api/Controllers/UniversalAudioController.cs
index 0c2e6f19f..dcdd8b367 100644
--- a/Jellyfin.Api/Controllers/UniversalAudioController.cs
+++ b/Jellyfin.Api/Controllers/UniversalAudioController.cs
@@ -219,10 +219,10 @@ namespace Jellyfin.Api.Controllers
AudioBitRate = audioBitRate ?? maxStreamingBitrate,
StartTimeTicks = startTimeTicks,
SubtitleMethod = SubtitleDeliveryMethod.Hls,
- RequireAvc = true,
- DeInterlace = true,
- RequireNonAnamorphic = true,
- EnableMpegtsM2TsMode = true,
+ RequireAvc = false,
+ DeInterlace = false,
+ RequireNonAnamorphic = false,
+ EnableMpegtsM2TsMode = false,
TranscodeReasons = mediaSource.TranscodeReasons == null ? null : string.Join(',', mediaSource.TranscodeReasons.Select(i => i.ToString()).ToArray()),
Context = EncodingContext.Static,
StreamOptions = new Dictionary<string, string>(),
diff --git a/Jellyfin.Api/Controllers/UserController.cs b/Jellyfin.Api/Controllers/UserController.cs
index 43ee309b7..3c0d2aca1 100644
--- a/Jellyfin.Api/Controllers/UserController.cs
+++ b/Jellyfin.Api/Controllers/UserController.cs
@@ -21,6 +21,7 @@ using MediaBrowser.Model.Users;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
+using Microsoft.Extensions.Logging;
namespace Jellyfin.Api.Controllers
{
@@ -36,6 +37,7 @@ namespace Jellyfin.Api.Controllers
private readonly IDeviceManager _deviceManager;
private readonly IAuthorizationContext _authContext;
private readonly IServerConfigurationManager _config;
+ private readonly ILogger _logger;
/// <summary>
/// Initializes a new instance of the <see cref="UserController"/> class.
@@ -46,13 +48,15 @@ namespace Jellyfin.Api.Controllers
/// <param name="deviceManager">Instance of the <see cref="IDeviceManager"/> interface.</param>
/// <param name="authContext">Instance of the <see cref="IAuthorizationContext"/> interface.</param>
/// <param name="config">Instance of the <see cref="IServerConfigurationManager"/> interface.</param>
+ /// <param name="logger">Instance of the <see cref="ILogger"/> interface.</param>
public UserController(
IUserManager userManager,
ISessionManager sessionManager,
INetworkManager networkManager,
IDeviceManager deviceManager,
IAuthorizationContext authContext,
- IServerConfigurationManager config)
+ IServerConfigurationManager config,
+ ILogger<UserController> logger)
{
_userManager = userManager;
_sessionManager = sessionManager;
@@ -60,6 +64,7 @@ namespace Jellyfin.Api.Controllers
_deviceManager = deviceManager;
_authContext = authContext;
_config = config;
+ _logger = logger;
}
/// <summary>
@@ -118,7 +123,7 @@ namespace Jellyfin.Api.Controllers
return NotFound("User not found");
}
- var result = _userManager.GetUserDto(user, HttpContext.GetNormalizedRemoteIp());
+ var result = _userManager.GetUserDto(user, HttpContext.GetNormalizedRemoteIp().ToString());
return result;
}
@@ -204,7 +209,7 @@ namespace Jellyfin.Api.Controllers
DeviceName = auth.Device,
Password = request.Pw,
PasswordSha1 = request.Password,
- RemoteEndPoint = HttpContext.GetNormalizedRemoteIp(),
+ RemoteEndPoint = HttpContext.GetNormalizedRemoteIp().ToString(),
Username = request.Username
}).ConfigureAwait(false);
@@ -291,7 +296,7 @@ namespace Jellyfin.Api.Controllers
user.Username,
request.CurrentPw,
request.CurrentPw,
- HttpContext.GetNormalizedRemoteIp(),
+ HttpContext.GetNormalizedRemoteIp().ToString(),
false).ConfigureAwait(false);
if (success == null)
@@ -483,7 +488,7 @@ namespace Jellyfin.Api.Controllers
await _userManager.ChangePassword(newUser, request.Password).ConfigureAwait(false);
}
- var result = _userManager.GetUserDto(newUser, HttpContext.GetNormalizedRemoteIp());
+ var result = _userManager.GetUserDto(newUser, HttpContext.GetNormalizedRemoteIp().ToString());
return result;
}
@@ -498,8 +503,14 @@ namespace Jellyfin.Api.Controllers
[ProducesResponseType(StatusCodes.Status200OK)]
public async Task<ActionResult<ForgotPasswordResult>> ForgotPassword([FromBody, Required] ForgotPasswordDto forgotPasswordRequest)
{
+ var ip = HttpContext.GetNormalizedRemoteIp();
var isLocal = HttpContext.IsLocal()
- || _networkManager.IsInLocalNetwork(HttpContext.GetNormalizedRemoteIp());
+ || _networkManager.IsInLocalNetwork(ip);
+
+ if (isLocal)
+ {
+ _logger.LogWarning("Password reset proccess initiated from outside the local network with IP: {IP}", ip);
+ }
var result = await _userManager.StartForgotPasswordProcess(forgotPasswordRequest.EnteredUsername, isLocal).ConfigureAwait(false);
@@ -581,7 +592,7 @@ namespace Jellyfin.Api.Controllers
var result = users
.OrderBy(u => u.Username)
- .Select(i => _userManager.GetUserDto(i, HttpContext.GetNormalizedRemoteIp()));
+ .Select(i => _userManager.GetUserDto(i, HttpContext.GetNormalizedRemoteIp().ToString()));
return result;
}
diff --git a/Jellyfin.Api/Controllers/VideoHlsController.cs b/Jellyfin.Api/Controllers/VideoHlsController.cs
index 620eef568..e95410d02 100644
--- a/Jellyfin.Api/Controllers/VideoHlsController.cs
+++ b/Jellyfin.Api/Controllers/VideoHlsController.cs
@@ -223,7 +223,7 @@ namespace Jellyfin.Api.Controllers
{
Id = itemId,
Container = container,
- Static = @static ?? true,
+ Static = @static ?? false,
Params = @params,
Tag = tag,
DeviceProfileId = deviceProfileId,
@@ -247,7 +247,7 @@ namespace Jellyfin.Api.Controllers
Level = level,
Framerate = framerate,
MaxFramerate = maxFramerate,
- CopyTimestamps = copyTimestamps ?? true,
+ CopyTimestamps = copyTimestamps ?? false,
StartTimeTicks = startTimeTicks,
Width = width,
Height = height,
@@ -256,13 +256,13 @@ namespace Jellyfin.Api.Controllers
SubtitleMethod = subtitleMethod ?? SubtitleDeliveryMethod.Encode,
MaxRefFrames = maxRefFrames,
MaxVideoBitDepth = maxVideoBitDepth,
- RequireAvc = requireAvc ?? true,
- DeInterlace = deInterlace ?? true,
- RequireNonAnamorphic = requireNonAnamorphic ?? true,
+ RequireAvc = requireAvc ?? false,
+ DeInterlace = deInterlace ?? false,
+ RequireNonAnamorphic = requireNonAnamorphic ?? false,
TranscodingMaxAudioChannels = transcodingMaxAudioChannels,
CpuCoreLimit = cpuCoreLimit,
LiveStreamId = liveStreamId,
- EnableMpegtsM2TsMode = enableMpegtsM2TsMode ?? true,
+ EnableMpegtsM2TsMode = enableMpegtsM2TsMode ?? false,
VideoCodec = videoCodec,
SubtitleCodec = subtitleCodec,
TranscodeReasons = transcodeReasons,
diff --git a/Jellyfin.Api/Controllers/VideosController.cs b/Jellyfin.Api/Controllers/VideosController.cs
index 99654e7b0..699ca5327 100644
--- a/Jellyfin.Api/Controllers/VideosController.cs
+++ b/Jellyfin.Api/Controllers/VideosController.cs
@@ -386,7 +386,7 @@ namespace Jellyfin.Api.Controllers
{
Id = itemId,
Container = container,
- Static = @static ?? true,
+ Static = @static ?? false,
Params = @params,
Tag = tag,
DeviceProfileId = deviceProfileId,
@@ -410,7 +410,7 @@ namespace Jellyfin.Api.Controllers
Level = level,
Framerate = framerate,
MaxFramerate = maxFramerate,
- CopyTimestamps = copyTimestamps ?? true,
+ CopyTimestamps = copyTimestamps ?? false,
StartTimeTicks = startTimeTicks,
Width = width,
Height = height,
@@ -419,13 +419,13 @@ namespace Jellyfin.Api.Controllers
SubtitleMethod = subtitleMethod ?? SubtitleDeliveryMethod.Encode,
MaxRefFrames = maxRefFrames,
MaxVideoBitDepth = maxVideoBitDepth,
- RequireAvc = requireAvc ?? true,
- DeInterlace = deInterlace ?? true,
- RequireNonAnamorphic = requireNonAnamorphic ?? true,
+ RequireAvc = requireAvc ?? false,
+ DeInterlace = deInterlace ?? false,
+ RequireNonAnamorphic = requireNonAnamorphic ?? false,
TranscodingMaxAudioChannels = transcodingMaxAudioChannels,
CpuCoreLimit = cpuCoreLimit,
LiveStreamId = liveStreamId,
- EnableMpegtsM2TsMode = enableMpegtsM2TsMode ?? true,
+ EnableMpegtsM2TsMode = enableMpegtsM2TsMode ?? false,
VideoCodec = videoCodec,
SubtitleCodec = subtitleCodec,
TranscodeReasons = transcodeReasons,
diff --git a/Jellyfin.Api/Helpers/DynamicHlsHelper.cs b/Jellyfin.Api/Helpers/DynamicHlsHelper.cs
index 16380f0bb..751b48682 100644
--- a/Jellyfin.Api/Helpers/DynamicHlsHelper.cs
+++ b/Jellyfin.Api/Helpers/DynamicHlsHelper.cs
@@ -434,7 +434,7 @@ namespace Jellyfin.Api.Helpers
}
}
- private bool EnableAdaptiveBitrateStreaming(StreamState state, bool isLiveStream, bool enableAdaptiveBitrateStreaming, string ipAddress)
+ private bool EnableAdaptiveBitrateStreaming(StreamState state, bool isLiveStream, bool enableAdaptiveBitrateStreaming, IPAddress ipAddress)
{
// Within the local network this will likely do more harm than good.
if (_networkManager.IsInLocalNetwork(ipAddress))
diff --git a/Jellyfin.Api/Helpers/FileStreamResponseHelpers.cs b/Jellyfin.Api/Helpers/FileStreamResponseHelpers.cs
index f828b1d9d..b0fd59e5e 100644
--- a/Jellyfin.Api/Helpers/FileStreamResponseHelpers.cs
+++ b/Jellyfin.Api/Helpers/FileStreamResponseHelpers.cs
@@ -46,7 +46,8 @@ namespace Jellyfin.Api.Helpers
if (isHeadRequest)
{
- return new FileContentResult(Array.Empty<byte>(), contentType);
+ httpContext.Response.Headers[HeaderNames.ContentType] = contentType;
+ return new OkResult();
}
return new FileStreamResult(await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false), contentType);
@@ -68,10 +69,10 @@ namespace Jellyfin.Api.Helpers
{
httpContext.Response.ContentType = contentType;
- // if the request is a head request, return a NoContent result with the same headers as it would with a GET request
+ // if the request is a head request, return an OkResult (200) with the same headers as it would with a GET request
if (isHeadRequest)
{
- return new NoContentResult();
+ return new OkResult();
}
return new PhysicalFileResult(path, contentType) { EnableRangeProcessing = true };
diff --git a/Jellyfin.Api/Helpers/MediaInfoHelper.cs b/Jellyfin.Api/Helpers/MediaInfoHelper.cs
index ce6740fc9..a2d0e7030 100644
--- a/Jellyfin.Api/Helpers/MediaInfoHelper.cs
+++ b/Jellyfin.Api/Helpers/MediaInfoHelper.cs
@@ -1,6 +1,7 @@
using System;
using System.Globalization;
using System.Linq;
+using System.Net;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
@@ -179,7 +180,7 @@ namespace Jellyfin.Api.Helpers
bool enableTranscoding,
bool allowVideoStreamCopy,
bool allowAudioStreamCopy,
- string ipAddress)
+ IPAddress ipAddress)
{
var streamBuilder = new StreamBuilder(_mediaEncoder, _logger);
@@ -551,7 +552,7 @@ namespace Jellyfin.Api.Helpers
}
}
- private int? GetMaxBitrate(int? clientMaxBitrate, User user, string ipAddress)
+ private int? GetMaxBitrate(int? clientMaxBitrate, User user, IPAddress ipAddress)
{
var maxBitrate = clientMaxBitrate;
var remoteClientMaxBitrate = user.RemoteClientBitrateLimit ?? 0;
diff --git a/Jellyfin.Api/Helpers/RequestHelpers.cs b/Jellyfin.Api/Helpers/RequestHelpers.cs
index 94856e03e..56585aeab 100644
--- a/Jellyfin.Api/Helpers/RequestHelpers.cs
+++ b/Jellyfin.Api/Helpers/RequestHelpers.cs
@@ -84,7 +84,7 @@ namespace Jellyfin.Api.Helpers
authorization.Version,
authorization.DeviceId,
authorization.Device,
- request.HttpContext.GetNormalizedRemoteIp(),
+ request.HttpContext.GetNormalizedRemoteIp().ToString(),
user);
if (session == null)
diff --git a/Jellyfin.Api/Jellyfin.Api.csproj b/Jellyfin.Api/Jellyfin.Api.csproj
index d5372d752..d6dc5a2dc 100644
--- a/Jellyfin.Api/Jellyfin.Api.csproj
+++ b/Jellyfin.Api/Jellyfin.Api.csproj
@@ -15,7 +15,7 @@
</PropertyGroup>
<ItemGroup>
- <PackageReference Include="Microsoft.AspNetCore.Authorization" Version="5.0.3" />
+ <PackageReference Include="Microsoft.AspNetCore.Authorization" Version="5.0.5" />
<PackageReference Include="Microsoft.Extensions.Http" Version="5.0.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.0.7" />
<PackageReference Include="Swashbuckle.AspNetCore.ReDoc" Version="6.0.7" />