mirror of
https://github.com/jellyfin/jellyfin.git
synced 2025-06-03 13:44:22 -04:00
Use proper IHttpContextAccessor
This commit is contained in:
parent
460c3dd351
commit
c5e9cf15f6
@ -192,7 +192,7 @@ namespace Jellyfin.Api.Controllers
|
|||||||
StreamOptions = streamOptions
|
StreamOptions = streamOptions
|
||||||
};
|
};
|
||||||
|
|
||||||
return await _audioHelper.GetAudioStream(this, _transcodingJobType, streamingRequest).ConfigureAwait(false);
|
return await _audioHelper.GetAudioStream(_transcodingJobType, streamingRequest).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -272,7 +272,7 @@ namespace Jellyfin.Api.Controllers
|
|||||||
EnableAdaptiveBitrateStreaming = enableAdaptiveBitrateStreaming
|
EnableAdaptiveBitrateStreaming = enableAdaptiveBitrateStreaming
|
||||||
};
|
};
|
||||||
|
|
||||||
return await _dynamicHlsHelper.GetMasterHlsPlaylist(this, _transcodingJobType, streamingRequest, enableAdaptiveBitrateStreaming).ConfigureAwait(false);
|
return await _dynamicHlsHelper.GetMasterHlsPlaylist(_transcodingJobType, streamingRequest, enableAdaptiveBitrateStreaming).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -439,7 +439,7 @@ namespace Jellyfin.Api.Controllers
|
|||||||
EnableAdaptiveBitrateStreaming = enableAdaptiveBitrateStreaming
|
EnableAdaptiveBitrateStreaming = enableAdaptiveBitrateStreaming
|
||||||
};
|
};
|
||||||
|
|
||||||
return await _dynamicHlsHelper.GetMasterHlsPlaylist(this, _transcodingJobType, streamingRequest, enableAdaptiveBitrateStreaming).ConfigureAwait(false);
|
return await _dynamicHlsHelper.GetMasterHlsPlaylist(_transcodingJobType, streamingRequest, enableAdaptiveBitrateStreaming).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -1657,7 +1657,7 @@ namespace Jellyfin.Api.Controllers
|
|||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
});
|
});
|
||||||
|
|
||||||
return FileStreamResponseHelpers.GetStaticFileResult(segmentPath, MimeTypes.GetMimeType(segmentPath)!, false, this);
|
return FileStreamResponseHelpers.GetStaticFileResult(segmentPath, MimeTypes.GetMimeType(segmentPath)!, false, HttpContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
private long GetEndPositionTicks(StreamState state, int requestedIndex)
|
private long GetEndPositionTicks(StreamState state, int requestedIndex)
|
||||||
|
@ -61,7 +61,7 @@ namespace Jellyfin.Api.Controllers
|
|||||||
var file = segmentId + Path.GetExtension(Request.Path);
|
var file = segmentId + Path.GetExtension(Request.Path);
|
||||||
file = Path.Combine(_serverConfigurationManager.GetTranscodePath(), file);
|
file = Path.Combine(_serverConfigurationManager.GetTranscodePath(), file);
|
||||||
|
|
||||||
return FileStreamResponseHelpers.GetStaticFileResult(file, MimeTypes.GetMimeType(file)!, false, this);
|
return FileStreamResponseHelpers.GetStaticFileResult(file, MimeTypes.GetMimeType(file)!, false, HttpContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -148,7 +148,7 @@ namespace Jellyfin.Api.Controllers
|
|||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
});
|
});
|
||||||
|
|
||||||
return FileStreamResponseHelpers.GetStaticFileResult(path, MimeTypes.GetMimeType(path)!, false, this);
|
return FileStreamResponseHelpers.GetStaticFileResult(path, MimeTypes.GetMimeType(path)!, false, HttpContext);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -110,7 +110,6 @@ namespace Jellyfin.Api.Controllers
|
|||||||
[FromQuery] bool breakOnNonKeyFrames,
|
[FromQuery] bool breakOnNonKeyFrames,
|
||||||
[FromQuery] bool enableRedirection = true)
|
[FromQuery] bool enableRedirection = true)
|
||||||
{
|
{
|
||||||
bool isHeadRequest = Request.Method == System.Net.WebRequestMethods.Http.Head;
|
|
||||||
var deviceProfile = GetDeviceProfile(container, transcodingContainer, audioCodec, transcodingProtocol, breakOnNonKeyFrames, transcodingAudioChannels, maxAudioSampleRate, maxAudioBitDepth, maxAudioChannels);
|
var deviceProfile = GetDeviceProfile(container, transcodingContainer, audioCodec, transcodingProtocol, breakOnNonKeyFrames, transcodingAudioChannels, maxAudioSampleRate, maxAudioBitDepth, maxAudioChannels);
|
||||||
_authorizationContext.GetAuthorizationInfo(Request).DeviceId = deviceId;
|
_authorizationContext.GetAuthorizationInfo(Request).DeviceId = deviceId;
|
||||||
|
|
||||||
@ -222,7 +221,7 @@ namespace Jellyfin.Api.Controllers
|
|||||||
EnableAdaptiveBitrateStreaming = true
|
EnableAdaptiveBitrateStreaming = true
|
||||||
};
|
};
|
||||||
|
|
||||||
return await _dynamicHlsHelper.GetMasterHlsPlaylist(this, TranscodingJobType.Hls, dynamicHlsRequestDto, true)
|
return await _dynamicHlsHelper.GetMasterHlsPlaylist(TranscodingJobType.Hls, dynamicHlsRequestDto, true)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -251,7 +250,7 @@ namespace Jellyfin.Api.Controllers
|
|||||||
Context = EncodingContext.Static
|
Context = EncodingContext.Static
|
||||||
};
|
};
|
||||||
|
|
||||||
return await _audioHelper.GetAudioStream(this, TranscodingJobType.Progressive, audioStreamingDto).ConfigureAwait(false);
|
return await _audioHelper.GetAudioStream(TranscodingJobType.Progressive, audioStreamingDto).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private DeviceProfile GetDeviceProfile(
|
private DeviceProfile GetDeviceProfile(
|
||||||
|
@ -471,7 +471,7 @@ namespace Jellyfin.Api.Controllers
|
|||||||
StreamingHelpers.AddDlnaHeaders(state, Response.Headers, true, startTimeTicks, Request, _dlnaManager);
|
StreamingHelpers.AddDlnaHeaders(state, Response.Headers, true, startTimeTicks, Request, _dlnaManager);
|
||||||
|
|
||||||
using var httpClient = _httpClientFactory.CreateClient();
|
using var httpClient = _httpClientFactory.CreateClient();
|
||||||
return await FileStreamResponseHelpers.GetStaticRemoteStreamResult(state, isHeadRequest, this, httpClient).ConfigureAwait(false);
|
return await FileStreamResponseHelpers.GetStaticRemoteStreamResult(state, isHeadRequest, httpClient, HttpContext).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (@static.HasValue && @static.Value && state.InputProtocol != MediaProtocol.File)
|
if (@static.HasValue && @static.Value && state.InputProtocol != MediaProtocol.File)
|
||||||
@ -507,7 +507,7 @@ namespace Jellyfin.Api.Controllers
|
|||||||
state.MediaPath,
|
state.MediaPath,
|
||||||
contentType,
|
contentType,
|
||||||
isHeadRequest,
|
isHeadRequest,
|
||||||
this);
|
HttpContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Need to start ffmpeg (because media can't be returned directly)
|
// Need to start ffmpeg (because media can't be returned directly)
|
||||||
@ -517,10 +517,9 @@ namespace Jellyfin.Api.Controllers
|
|||||||
return await FileStreamResponseHelpers.GetTranscodedFile(
|
return await FileStreamResponseHelpers.GetTranscodedFile(
|
||||||
state,
|
state,
|
||||||
isHeadRequest,
|
isHeadRequest,
|
||||||
this,
|
HttpContext,
|
||||||
_transcodingJobHelper,
|
_transcodingJobHelper,
|
||||||
ffmpegCommandLineArguments,
|
ffmpegCommandLineArguments,
|
||||||
Request,
|
|
||||||
_transcodingJobType,
|
_transcodingJobType,
|
||||||
cancellationTokenSource).ConfigureAwait(false);
|
cancellationTokenSource).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@ using MediaBrowser.Controller.Net;
|
|||||||
using MediaBrowser.Model.IO;
|
using MediaBrowser.Model.IO;
|
||||||
using MediaBrowser.Model.MediaInfo;
|
using MediaBrowser.Model.MediaInfo;
|
||||||
using MediaBrowser.Model.Net;
|
using MediaBrowser.Model.Net;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
|
|
||||||
@ -35,6 +36,7 @@ namespace Jellyfin.Api.Helpers
|
|||||||
private readonly IDeviceManager _deviceManager;
|
private readonly IDeviceManager _deviceManager;
|
||||||
private readonly TranscodingJobHelper _transcodingJobHelper;
|
private readonly TranscodingJobHelper _transcodingJobHelper;
|
||||||
private readonly IHttpClientFactory _httpClientFactory;
|
private readonly IHttpClientFactory _httpClientFactory;
|
||||||
|
private readonly IHttpContextAccessor _httpContextAccessor;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="AudioHelper"/> class.
|
/// Initializes a new instance of the <see cref="AudioHelper"/> class.
|
||||||
@ -52,6 +54,7 @@ namespace Jellyfin.Api.Helpers
|
|||||||
/// <param name="deviceManager">Instance of the <see cref="IDeviceManager"/> interface.</param>
|
/// <param name="deviceManager">Instance of the <see cref="IDeviceManager"/> interface.</param>
|
||||||
/// <param name="transcodingJobHelper">Instance of <see cref="TranscodingJobHelper"/>.</param>
|
/// <param name="transcodingJobHelper">Instance of <see cref="TranscodingJobHelper"/>.</param>
|
||||||
/// <param name="httpClientFactory">Instance of the <see cref="IHttpClientFactory"/> interface.</param>
|
/// <param name="httpClientFactory">Instance of the <see cref="IHttpClientFactory"/> interface.</param>
|
||||||
|
/// <param name="httpContextAccessor">Instance of the <see cref="IHttpContextAccessor"/> interface.</param>
|
||||||
public AudioHelper(
|
public AudioHelper(
|
||||||
IDlnaManager dlnaManager,
|
IDlnaManager dlnaManager,
|
||||||
IAuthorizationContext authContext,
|
IAuthorizationContext authContext,
|
||||||
@ -65,7 +68,8 @@ namespace Jellyfin.Api.Helpers
|
|||||||
IConfiguration configuration,
|
IConfiguration configuration,
|
||||||
IDeviceManager deviceManager,
|
IDeviceManager deviceManager,
|
||||||
TranscodingJobHelper transcodingJobHelper,
|
TranscodingJobHelper transcodingJobHelper,
|
||||||
IHttpClientFactory httpClientFactory)
|
IHttpClientFactory httpClientFactory,
|
||||||
|
IHttpContextAccessor httpContextAccessor)
|
||||||
{
|
{
|
||||||
_dlnaManager = dlnaManager;
|
_dlnaManager = dlnaManager;
|
||||||
_authContext = authContext;
|
_authContext = authContext;
|
||||||
@ -80,26 +84,25 @@ namespace Jellyfin.Api.Helpers
|
|||||||
_deviceManager = deviceManager;
|
_deviceManager = deviceManager;
|
||||||
_transcodingJobHelper = transcodingJobHelper;
|
_transcodingJobHelper = transcodingJobHelper;
|
||||||
_httpClientFactory = httpClientFactory;
|
_httpClientFactory = httpClientFactory;
|
||||||
|
_httpContextAccessor = httpContextAccessor;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get audio stream.
|
/// Get audio stream.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="controller">Requesting controller.</param>
|
|
||||||
/// <param name="transcodingJobType">Transcoding job type.</param>
|
/// <param name="transcodingJobType">Transcoding job type.</param>
|
||||||
/// <param name="streamingRequest">Streaming controller.Request dto.</param>
|
/// <param name="streamingRequest">Streaming controller.Request dto.</param>
|
||||||
/// <returns>A <see cref="Task"/> containing the resulting <see cref="ActionResult"/>.</returns>
|
/// <returns>A <see cref="Task"/> containing the resulting <see cref="ActionResult"/>.</returns>
|
||||||
public async Task<ActionResult> GetAudioStream(
|
public async Task<ActionResult> GetAudioStream(
|
||||||
BaseJellyfinApiController controller,
|
|
||||||
TranscodingJobType transcodingJobType,
|
TranscodingJobType transcodingJobType,
|
||||||
StreamingRequestDto streamingRequest)
|
StreamingRequestDto streamingRequest)
|
||||||
{
|
{
|
||||||
bool isHeadRequest = controller.Request.Method == System.Net.WebRequestMethods.Http.Head;
|
bool isHeadRequest = _httpContextAccessor.HttpContext.Request.Method == System.Net.WebRequestMethods.Http.Head;
|
||||||
var cancellationTokenSource = new CancellationTokenSource();
|
var cancellationTokenSource = new CancellationTokenSource();
|
||||||
|
|
||||||
using var state = await StreamingHelpers.GetStreamingState(
|
using var state = await StreamingHelpers.GetStreamingState(
|
||||||
streamingRequest,
|
streamingRequest,
|
||||||
controller.Request,
|
_httpContextAccessor.HttpContext.Request,
|
||||||
_authContext,
|
_authContext,
|
||||||
_mediaSourceManager,
|
_mediaSourceManager,
|
||||||
_userManager,
|
_userManager,
|
||||||
@ -118,30 +121,30 @@ namespace Jellyfin.Api.Helpers
|
|||||||
|
|
||||||
if (streamingRequest.Static && state.DirectStreamProvider != null)
|
if (streamingRequest.Static && state.DirectStreamProvider != null)
|
||||||
{
|
{
|
||||||
StreamingHelpers.AddDlnaHeaders(state, controller.Response.Headers, true, streamingRequest.StartTimeTicks, controller.Request, _dlnaManager);
|
StreamingHelpers.AddDlnaHeaders(state, _httpContextAccessor.HttpContext.Response.Headers, true, streamingRequest.StartTimeTicks, _httpContextAccessor.HttpContext.Request, _dlnaManager);
|
||||||
|
|
||||||
await new ProgressiveFileCopier(state.DirectStreamProvider, null, _transcodingJobHelper, CancellationToken.None)
|
await new ProgressiveFileCopier(state.DirectStreamProvider, null, _transcodingJobHelper, CancellationToken.None)
|
||||||
{
|
{
|
||||||
AllowEndOfFile = false
|
AllowEndOfFile = false
|
||||||
}.WriteToAsync(controller.Response.Body, CancellationToken.None)
|
}.WriteToAsync(_httpContextAccessor.HttpContext.Response.Body, CancellationToken.None)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
// TODO (moved from MediaBrowser.Api): Don't hardcode contentType
|
// TODO (moved from MediaBrowser.Api): Don't hardcode contentType
|
||||||
return controller.File(controller.Response.Body, MimeTypes.GetMimeType("file.ts")!);
|
return new FileStreamResult(_httpContextAccessor.HttpContext.Response.Body, MimeTypes.GetMimeType("file.ts")!);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Static remote stream
|
// Static remote stream
|
||||||
if (streamingRequest.Static && state.InputProtocol == MediaProtocol.Http)
|
if (streamingRequest.Static && state.InputProtocol == MediaProtocol.Http)
|
||||||
{
|
{
|
||||||
StreamingHelpers.AddDlnaHeaders(state, controller.Response.Headers, true, streamingRequest.StartTimeTicks, controller.Request, _dlnaManager);
|
StreamingHelpers.AddDlnaHeaders(state, _httpContextAccessor.HttpContext.Response.Headers, true, streamingRequest.StartTimeTicks, _httpContextAccessor.HttpContext.Request, _dlnaManager);
|
||||||
|
|
||||||
using var httpClient = _httpClientFactory.CreateClient();
|
using var httpClient = _httpClientFactory.CreateClient();
|
||||||
return await FileStreamResponseHelpers.GetStaticRemoteStreamResult(state, isHeadRequest, controller, httpClient).ConfigureAwait(false);
|
return await FileStreamResponseHelpers.GetStaticRemoteStreamResult(state, isHeadRequest, httpClient, _httpContextAccessor.HttpContext).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (streamingRequest.Static && state.InputProtocol != MediaProtocol.File)
|
if (streamingRequest.Static && state.InputProtocol != MediaProtocol.File)
|
||||||
{
|
{
|
||||||
return controller.BadRequest($"Input protocol {state.InputProtocol} cannot be streamed statically");
|
return new BadRequestObjectResult($"Input protocol {state.InputProtocol} cannot be streamed statically");
|
||||||
}
|
}
|
||||||
|
|
||||||
var outputPath = state.OutputFilePath;
|
var outputPath = state.OutputFilePath;
|
||||||
@ -150,7 +153,7 @@ namespace Jellyfin.Api.Helpers
|
|||||||
var transcodingJob = _transcodingJobHelper.GetTranscodingJob(outputPath, TranscodingJobType.Progressive);
|
var transcodingJob = _transcodingJobHelper.GetTranscodingJob(outputPath, TranscodingJobType.Progressive);
|
||||||
var isTranscodeCached = outputPathExists && transcodingJob != null;
|
var isTranscodeCached = outputPathExists && transcodingJob != null;
|
||||||
|
|
||||||
StreamingHelpers.AddDlnaHeaders(state, controller.Response.Headers, streamingRequest.Static || isTranscodeCached, streamingRequest.StartTimeTicks, controller.Request, _dlnaManager);
|
StreamingHelpers.AddDlnaHeaders(state, _httpContextAccessor.HttpContext.Response.Headers, streamingRequest.Static || isTranscodeCached, streamingRequest.StartTimeTicks, _httpContextAccessor.HttpContext.Request, _dlnaManager);
|
||||||
|
|
||||||
// Static stream
|
// Static stream
|
||||||
if (streamingRequest.Static)
|
if (streamingRequest.Static)
|
||||||
@ -162,17 +165,17 @@ namespace Jellyfin.Api.Helpers
|
|||||||
await new ProgressiveFileCopier(state.MediaPath, null, _transcodingJobHelper, CancellationToken.None)
|
await new ProgressiveFileCopier(state.MediaPath, null, _transcodingJobHelper, CancellationToken.None)
|
||||||
{
|
{
|
||||||
AllowEndOfFile = false
|
AllowEndOfFile = false
|
||||||
}.WriteToAsync(controller.Response.Body, CancellationToken.None)
|
}.WriteToAsync(_httpContextAccessor.HttpContext.Response.Body, CancellationToken.None)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
return controller.File(controller.Response.Body, contentType);
|
return new FileStreamResult(_httpContextAccessor.HttpContext.Response.Body, contentType);
|
||||||
}
|
}
|
||||||
|
|
||||||
return FileStreamResponseHelpers.GetStaticFileResult(
|
return FileStreamResponseHelpers.GetStaticFileResult(
|
||||||
state.MediaPath,
|
state.MediaPath,
|
||||||
contentType,
|
contentType,
|
||||||
isHeadRequest,
|
isHeadRequest,
|
||||||
controller);
|
_httpContextAccessor.HttpContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Need to start ffmpeg (because media can't be returned directly)
|
// Need to start ffmpeg (because media can't be returned directly)
|
||||||
@ -182,10 +185,9 @@ namespace Jellyfin.Api.Helpers
|
|||||||
return await FileStreamResponseHelpers.GetTranscodedFile(
|
return await FileStreamResponseHelpers.GetTranscodedFile(
|
||||||
state,
|
state,
|
||||||
isHeadRequest,
|
isHeadRequest,
|
||||||
controller,
|
_httpContextAccessor.HttpContext,
|
||||||
_transcodingJobHelper,
|
_transcodingJobHelper,
|
||||||
ffmpegCommandLineArguments,
|
ffmpegCommandLineArguments,
|
||||||
controller.Request,
|
|
||||||
transcodingJobType,
|
transcodingJobType,
|
||||||
cancellationTokenSource).ConfigureAwait(false);
|
cancellationTokenSource).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,7 @@ using MediaBrowser.Model.Dlna;
|
|||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
using MediaBrowser.Model.IO;
|
using MediaBrowser.Model.IO;
|
||||||
using MediaBrowser.Model.Net;
|
using MediaBrowser.Model.Net;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
@ -45,6 +46,7 @@ namespace Jellyfin.Api.Helpers
|
|||||||
private readonly TranscodingJobHelper _transcodingJobHelper;
|
private readonly TranscodingJobHelper _transcodingJobHelper;
|
||||||
private readonly INetworkManager _networkManager;
|
private readonly INetworkManager _networkManager;
|
||||||
private readonly ILogger<DynamicHlsHelper> _logger;
|
private readonly ILogger<DynamicHlsHelper> _logger;
|
||||||
|
private readonly IHttpContextAccessor _httpContextAccessor;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="DynamicHlsHelper"/> class.
|
/// Initializes a new instance of the <see cref="DynamicHlsHelper"/> class.
|
||||||
@ -63,6 +65,7 @@ namespace Jellyfin.Api.Helpers
|
|||||||
/// <param name="transcodingJobHelper">Instance of <see cref="TranscodingJobHelper"/>.</param>
|
/// <param name="transcodingJobHelper">Instance of <see cref="TranscodingJobHelper"/>.</param>
|
||||||
/// <param name="networkManager">Instance of the <see cref="INetworkManager"/> interface.</param>
|
/// <param name="networkManager">Instance of the <see cref="INetworkManager"/> interface.</param>
|
||||||
/// <param name="logger">Instance of the <see cref="ILogger{DynamicHlsHelper}"/> interface.</param>
|
/// <param name="logger">Instance of the <see cref="ILogger{DynamicHlsHelper}"/> interface.</param>
|
||||||
|
/// <param name="httpContextAccessor">Instance of the <see cref="IHttpContextAccessor"/> interface.</param>
|
||||||
public DynamicHlsHelper(
|
public DynamicHlsHelper(
|
||||||
ILibraryManager libraryManager,
|
ILibraryManager libraryManager,
|
||||||
IUserManager userManager,
|
IUserManager userManager,
|
||||||
@ -77,7 +80,8 @@ namespace Jellyfin.Api.Helpers
|
|||||||
IDeviceManager deviceManager,
|
IDeviceManager deviceManager,
|
||||||
TranscodingJobHelper transcodingJobHelper,
|
TranscodingJobHelper transcodingJobHelper,
|
||||||
INetworkManager networkManager,
|
INetworkManager networkManager,
|
||||||
ILogger<DynamicHlsHelper> logger)
|
ILogger<DynamicHlsHelper> logger,
|
||||||
|
IHttpContextAccessor httpContextAccessor)
|
||||||
{
|
{
|
||||||
_libraryManager = libraryManager;
|
_libraryManager = libraryManager;
|
||||||
_userManager = userManager;
|
_userManager = userManager;
|
||||||
@ -93,26 +97,24 @@ namespace Jellyfin.Api.Helpers
|
|||||||
_transcodingJobHelper = transcodingJobHelper;
|
_transcodingJobHelper = transcodingJobHelper;
|
||||||
_networkManager = networkManager;
|
_networkManager = networkManager;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
|
_httpContextAccessor = httpContextAccessor;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get master hls playlist.
|
/// Get master hls playlist.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="controller">Requesting controller.</param>
|
|
||||||
/// <param name="transcodingJobType">Transcoding job type.</param>
|
/// <param name="transcodingJobType">Transcoding job type.</param>
|
||||||
/// <param name="streamingRequest">Streaming request dto.</param>
|
/// <param name="streamingRequest">Streaming request dto.</param>
|
||||||
/// <param name="enableAdaptiveBitrateStreaming">Enable adaptive bitrate streaming.</param>
|
/// <param name="enableAdaptiveBitrateStreaming">Enable adaptive bitrate streaming.</param>
|
||||||
/// <returns>A <see cref="Task"/> containing the resulting <see cref="ActionResult"/>.</returns>
|
/// <returns>A <see cref="Task"/> containing the resulting <see cref="ActionResult"/>.</returns>
|
||||||
public async Task<ActionResult> GetMasterHlsPlaylist(
|
public async Task<ActionResult> GetMasterHlsPlaylist(
|
||||||
BaseJellyfinApiController controller,
|
|
||||||
TranscodingJobType transcodingJobType,
|
TranscodingJobType transcodingJobType,
|
||||||
StreamingRequestDto streamingRequest,
|
StreamingRequestDto streamingRequest,
|
||||||
bool enableAdaptiveBitrateStreaming)
|
bool enableAdaptiveBitrateStreaming)
|
||||||
{
|
{
|
||||||
var isHeadRequest = controller.Request.Method == WebRequestMethods.Http.Head;
|
var isHeadRequest = _httpContextAccessor.HttpContext.Request.Method == WebRequestMethods.Http.Head;
|
||||||
var cancellationTokenSource = new CancellationTokenSource();
|
var cancellationTokenSource = new CancellationTokenSource();
|
||||||
return await GetMasterPlaylistInternal(
|
return await GetMasterPlaylistInternal(
|
||||||
controller,
|
|
||||||
streamingRequest,
|
streamingRequest,
|
||||||
isHeadRequest,
|
isHeadRequest,
|
||||||
enableAdaptiveBitrateStreaming,
|
enableAdaptiveBitrateStreaming,
|
||||||
@ -121,7 +123,6 @@ namespace Jellyfin.Api.Helpers
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async Task<ActionResult> GetMasterPlaylistInternal(
|
private async Task<ActionResult> GetMasterPlaylistInternal(
|
||||||
BaseJellyfinApiController controller,
|
|
||||||
StreamingRequestDto streamingRequest,
|
StreamingRequestDto streamingRequest,
|
||||||
bool isHeadRequest,
|
bool isHeadRequest,
|
||||||
bool enableAdaptiveBitrateStreaming,
|
bool enableAdaptiveBitrateStreaming,
|
||||||
@ -130,7 +131,7 @@ namespace Jellyfin.Api.Helpers
|
|||||||
{
|
{
|
||||||
using var state = await StreamingHelpers.GetStreamingState(
|
using var state = await StreamingHelpers.GetStreamingState(
|
||||||
streamingRequest,
|
streamingRequest,
|
||||||
controller.Request,
|
_httpContextAccessor.HttpContext.Request,
|
||||||
_authContext,
|
_authContext,
|
||||||
_mediaSourceManager,
|
_mediaSourceManager,
|
||||||
_userManager,
|
_userManager,
|
||||||
@ -147,7 +148,7 @@ namespace Jellyfin.Api.Helpers
|
|||||||
cancellationTokenSource.Token)
|
cancellationTokenSource.Token)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
controller.Response.Headers.Add(HeaderNames.Expires, "0");
|
_httpContextAccessor.HttpContext.Response.Headers.Add(HeaderNames.Expires, "0");
|
||||||
if (isHeadRequest)
|
if (isHeadRequest)
|
||||||
{
|
{
|
||||||
return new FileContentResult(Array.Empty<byte>(), MimeTypes.GetMimeType("playlist.m3u8"));
|
return new FileContentResult(Array.Empty<byte>(), MimeTypes.GetMimeType("playlist.m3u8"));
|
||||||
@ -161,7 +162,7 @@ namespace Jellyfin.Api.Helpers
|
|||||||
|
|
||||||
var isLiveStream = state.IsSegmentedLiveStream;
|
var isLiveStream = state.IsSegmentedLiveStream;
|
||||||
|
|
||||||
var queryString = controller.Request.QueryString.ToString();
|
var queryString = _httpContextAccessor.HttpContext.Request.QueryString.ToString();
|
||||||
|
|
||||||
// from universal audio service
|
// from universal audio service
|
||||||
if (queryString.IndexOf("SegmentContainer", StringComparison.OrdinalIgnoreCase) == -1 && !string.IsNullOrWhiteSpace(state.Request.SegmentContainer))
|
if (queryString.IndexOf("SegmentContainer", StringComparison.OrdinalIgnoreCase) == -1 && !string.IsNullOrWhiteSpace(state.Request.SegmentContainer))
|
||||||
@ -197,12 +198,12 @@ namespace Jellyfin.Api.Helpers
|
|||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(subtitleGroup))
|
if (!string.IsNullOrWhiteSpace(subtitleGroup))
|
||||||
{
|
{
|
||||||
AddSubtitles(state, subtitleStreams, builder, controller.Request.HttpContext.User);
|
AddSubtitles(state, subtitleStreams, builder, _httpContextAccessor.HttpContext.Request.HttpContext.User);
|
||||||
}
|
}
|
||||||
|
|
||||||
AppendPlaylist(builder, state, playlistUrl, totalBitrate, subtitleGroup);
|
AppendPlaylist(builder, state, playlistUrl, totalBitrate, subtitleGroup);
|
||||||
|
|
||||||
if (EnableAdaptiveBitrateStreaming(state, isLiveStream, enableAdaptiveBitrateStreaming, controller.Request.HttpContext.Connection.RemoteIpAddress))
|
if (EnableAdaptiveBitrateStreaming(state, isLiveStream, enableAdaptiveBitrateStreaming, _httpContextAccessor.HttpContext.Request.HttpContext.Connection.RemoteIpAddress))
|
||||||
{
|
{
|
||||||
var requestedVideoBitrate = state.VideoRequest == null ? 0 : state.VideoRequest.VideoBitRate ?? 0;
|
var requestedVideoBitrate = state.VideoRequest == null ? 0 : state.VideoRequest.VideoBitRate ?? 0;
|
||||||
|
|
||||||
|
@ -22,14 +22,14 @@ namespace Jellyfin.Api.Helpers
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="state">The current <see cref="StreamState"/>.</param>
|
/// <param name="state">The current <see cref="StreamState"/>.</param>
|
||||||
/// <param name="isHeadRequest">Whether the current request is a HTTP HEAD request so only the headers get returned.</param>
|
/// <param name="isHeadRequest">Whether the current request is a HTTP HEAD request so only the headers get returned.</param>
|
||||||
/// <param name="controller">The <see cref="ControllerBase"/> managing the response.</param>
|
|
||||||
/// <param name="httpClient">The <see cref="HttpClient"/> making the remote request.</param>
|
/// <param name="httpClient">The <see cref="HttpClient"/> making the remote request.</param>
|
||||||
|
/// <param name="httpContext">The current http context.</param>
|
||||||
/// <returns>A <see cref="Task{ActionResult}"/> containing the API response.</returns>
|
/// <returns>A <see cref="Task{ActionResult}"/> containing the API response.</returns>
|
||||||
public static async Task<ActionResult> GetStaticRemoteStreamResult(
|
public static async Task<ActionResult> GetStaticRemoteStreamResult(
|
||||||
StreamState state,
|
StreamState state,
|
||||||
bool isHeadRequest,
|
bool isHeadRequest,
|
||||||
ControllerBase controller,
|
HttpClient httpClient,
|
||||||
HttpClient httpClient)
|
HttpContext httpContext)
|
||||||
{
|
{
|
||||||
if (state.RemoteHttpHeaders.TryGetValue(HeaderNames.UserAgent, out var useragent))
|
if (state.RemoteHttpHeaders.TryGetValue(HeaderNames.UserAgent, out var useragent))
|
||||||
{
|
{
|
||||||
@ -39,14 +39,14 @@ namespace Jellyfin.Api.Helpers
|
|||||||
using var response = await httpClient.GetAsync(state.MediaPath).ConfigureAwait(false);
|
using var response = await httpClient.GetAsync(state.MediaPath).ConfigureAwait(false);
|
||||||
var contentType = response.Content.Headers.ContentType.ToString();
|
var contentType = response.Content.Headers.ContentType.ToString();
|
||||||
|
|
||||||
controller.Response.Headers[HeaderNames.AcceptRanges] = "none";
|
httpContext.Response.Headers[HeaderNames.AcceptRanges] = "none";
|
||||||
|
|
||||||
if (isHeadRequest)
|
if (isHeadRequest)
|
||||||
{
|
{
|
||||||
return controller.File(Array.Empty<byte>(), contentType);
|
return new FileContentResult(Array.Empty<byte>(), contentType);
|
||||||
}
|
}
|
||||||
|
|
||||||
return controller.File(await response.Content.ReadAsStreamAsync().ConfigureAwait(false), contentType);
|
return new FileStreamResult(await response.Content.ReadAsStreamAsync().ConfigureAwait(false), contentType);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -55,23 +55,23 @@ namespace Jellyfin.Api.Helpers
|
|||||||
/// <param name="path">The path to the file.</param>
|
/// <param name="path">The path to the file.</param>
|
||||||
/// <param name="contentType">The content type of the file.</param>
|
/// <param name="contentType">The content type of the file.</param>
|
||||||
/// <param name="isHeadRequest">Whether the current request is a HTTP HEAD request so only the headers get returned.</param>
|
/// <param name="isHeadRequest">Whether the current request is a HTTP HEAD request so only the headers get returned.</param>
|
||||||
/// <param name="controller">The <see cref="ControllerBase"/> managing the response.</param>
|
/// <param name="httpContext">The current http context.</param>
|
||||||
/// <returns>An <see cref="ActionResult"/> the file.</returns>
|
/// <returns>An <see cref="ActionResult"/> the file.</returns>
|
||||||
public static ActionResult GetStaticFileResult(
|
public static ActionResult GetStaticFileResult(
|
||||||
string path,
|
string path,
|
||||||
string contentType,
|
string contentType,
|
||||||
bool isHeadRequest,
|
bool isHeadRequest,
|
||||||
ControllerBase controller)
|
HttpContext httpContext)
|
||||||
{
|
{
|
||||||
controller.Response.ContentType = contentType;
|
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 a NoContent result with the same headers as it would with a GET request
|
||||||
if (isHeadRequest)
|
if (isHeadRequest)
|
||||||
{
|
{
|
||||||
return controller.NoContent();
|
return new NoContentResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
return controller.PhysicalFile(path, contentType);
|
return new PhysicalFileResult(path, contentType);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -79,34 +79,32 @@ namespace Jellyfin.Api.Helpers
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="state">The current <see cref="StreamState"/>.</param>
|
/// <param name="state">The current <see cref="StreamState"/>.</param>
|
||||||
/// <param name="isHeadRequest">Whether the current request is a HTTP HEAD request so only the headers get returned.</param>
|
/// <param name="isHeadRequest">Whether the current request is a HTTP HEAD request so only the headers get returned.</param>
|
||||||
/// <param name="controller">The <see cref="ControllerBase"/> managing the response.</param>
|
/// <param name="httpContext">The current http context.</param>
|
||||||
/// <param name="transcodingJobHelper">The <see cref="TranscodingJobHelper"/> singleton.</param>
|
/// <param name="transcodingJobHelper">The <see cref="TranscodingJobHelper"/> singleton.</param>
|
||||||
/// <param name="ffmpegCommandLineArguments">The command line arguments to start ffmpeg.</param>
|
/// <param name="ffmpegCommandLineArguments">The command line arguments to start ffmpeg.</param>
|
||||||
/// <param name="request">The <see cref="HttpRequest"/> starting the transcoding.</param>
|
|
||||||
/// <param name="transcodingJobType">The <see cref="TranscodingJobType"/>.</param>
|
/// <param name="transcodingJobType">The <see cref="TranscodingJobType"/>.</param>
|
||||||
/// <param name="cancellationTokenSource">The <see cref="CancellationTokenSource"/>.</param>
|
/// <param name="cancellationTokenSource">The <see cref="CancellationTokenSource"/>.</param>
|
||||||
/// <returns>A <see cref="Task{ActionResult}"/> containing the transcoded file.</returns>
|
/// <returns>A <see cref="Task{ActionResult}"/> containing the transcoded file.</returns>
|
||||||
public static async Task<ActionResult> GetTranscodedFile(
|
public static async Task<ActionResult> GetTranscodedFile(
|
||||||
StreamState state,
|
StreamState state,
|
||||||
bool isHeadRequest,
|
bool isHeadRequest,
|
||||||
ControllerBase controller,
|
HttpContext httpContext,
|
||||||
TranscodingJobHelper transcodingJobHelper,
|
TranscodingJobHelper transcodingJobHelper,
|
||||||
string ffmpegCommandLineArguments,
|
string ffmpegCommandLineArguments,
|
||||||
HttpRequest request,
|
|
||||||
TranscodingJobType transcodingJobType,
|
TranscodingJobType transcodingJobType,
|
||||||
CancellationTokenSource cancellationTokenSource)
|
CancellationTokenSource cancellationTokenSource)
|
||||||
{
|
{
|
||||||
// Use the command line args with a dummy playlist path
|
// Use the command line args with a dummy playlist path
|
||||||
var outputPath = state.OutputFilePath;
|
var outputPath = state.OutputFilePath;
|
||||||
|
|
||||||
controller.Response.Headers[HeaderNames.AcceptRanges] = "none";
|
httpContext.Response.Headers[HeaderNames.AcceptRanges] = "none";
|
||||||
|
|
||||||
var contentType = state.GetMimeType(outputPath);
|
var contentType = state.GetMimeType(outputPath);
|
||||||
|
|
||||||
// Headers only
|
// Headers only
|
||||||
if (isHeadRequest)
|
if (isHeadRequest)
|
||||||
{
|
{
|
||||||
return controller.File(Array.Empty<byte>(), contentType);
|
return new FileContentResult(Array.Empty<byte>(), contentType);
|
||||||
}
|
}
|
||||||
|
|
||||||
var transcodingLock = transcodingJobHelper.GetTranscodingLock(outputPath);
|
var transcodingLock = transcodingJobHelper.GetTranscodingLock(outputPath);
|
||||||
@ -116,7 +114,7 @@ namespace Jellyfin.Api.Helpers
|
|||||||
TranscodingJobDto? job;
|
TranscodingJobDto? job;
|
||||||
if (!File.Exists(outputPath))
|
if (!File.Exists(outputPath))
|
||||||
{
|
{
|
||||||
job = await transcodingJobHelper.StartFfMpeg(state, outputPath, ffmpegCommandLineArguments, request, transcodingJobType, cancellationTokenSource).ConfigureAwait(false);
|
job = await transcodingJobHelper.StartFfMpeg(state, outputPath, ffmpegCommandLineArguments, httpContext.Request, transcodingJobType, cancellationTokenSource).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -127,7 +125,7 @@ namespace Jellyfin.Api.Helpers
|
|||||||
var memoryStream = new MemoryStream();
|
var memoryStream = new MemoryStream();
|
||||||
await new ProgressiveFileCopier(outputPath, job, transcodingJobHelper, CancellationToken.None).WriteToAsync(memoryStream, CancellationToken.None).ConfigureAwait(false);
|
await new ProgressiveFileCopier(outputPath, job, transcodingJobHelper, CancellationToken.None).WriteToAsync(memoryStream, CancellationToken.None).ConfigureAwait(false);
|
||||||
memoryStream.Position = 0;
|
memoryStream.Position = 0;
|
||||||
return controller.File(memoryStream, contentType);
|
return new FileStreamResult(memoryStream, contentType);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user