mirror of
https://github.com/jellyfin/jellyfin.git
synced 2025-05-31 20:24:21 -04:00
Fix suggestions from review
This commit is contained in:
parent
d39f481a5c
commit
ca3dcc3db0
@ -260,7 +260,7 @@ namespace Jellyfin.Api.Controllers
|
|||||||
StreamOptions = streamOptions
|
StreamOptions = streamOptions
|
||||||
};
|
};
|
||||||
|
|
||||||
var state = await StreamingHelpers.GetStreamingState(
|
using var state = await StreamingHelpers.GetStreamingState(
|
||||||
streamingRequest,
|
streamingRequest,
|
||||||
Request,
|
Request,
|
||||||
_authContext,
|
_authContext,
|
||||||
@ -283,14 +283,11 @@ namespace Jellyfin.Api.Controllers
|
|||||||
{
|
{
|
||||||
StreamingHelpers.AddDlnaHeaders(state, Response.Headers, true, startTimeTicks, Request, _dlnaManager);
|
StreamingHelpers.AddDlnaHeaders(state, Response.Headers, true, startTimeTicks, Request, _dlnaManager);
|
||||||
|
|
||||||
using (state)
|
// TODO AllowEndOfFile = false
|
||||||
{
|
await new ProgressiveFileCopier(_streamHelper, state.DirectStreamProvider).WriteToAsync(Response.Body, CancellationToken.None).ConfigureAwait(false);
|
||||||
// TODO AllowEndOfFile = false
|
|
||||||
await new ProgressiveFileCopier(_streamHelper, state.DirectStreamProvider).WriteToAsync(Response.Body, CancellationToken.None).ConfigureAwait(false);
|
|
||||||
|
|
||||||
// TODO (moved from MediaBrowser.Api): Don't hardcode contentType
|
// TODO (moved from MediaBrowser.Api): Don't hardcode contentType
|
||||||
return File(Response.Body, MimeTypes.GetMimeType("file.ts")!);
|
return File(Response.Body, MimeTypes.GetMimeType("file.ts")!);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Static remote stream
|
// Static remote stream
|
||||||
@ -298,10 +295,7 @@ namespace Jellyfin.Api.Controllers
|
|||||||
{
|
{
|
||||||
StreamingHelpers.AddDlnaHeaders(state, Response.Headers, true, startTimeTicks, Request, _dlnaManager);
|
StreamingHelpers.AddDlnaHeaders(state, Response.Headers, true, startTimeTicks, Request, _dlnaManager);
|
||||||
|
|
||||||
using (state)
|
return await FileStreamResponseHelpers.GetStaticRemoteStreamResult(state, isHeadRequest, this, _httpClient).ConfigureAwait(false);
|
||||||
{
|
|
||||||
return await FileStreamResponseHelpers.GetStaticRemoteStreamResult(state, isHeadRequest, this, _httpClient).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (@static.HasValue && @static.Value && state.InputProtocol != MediaProtocol.File)
|
if (@static.HasValue && @static.Value && state.InputProtocol != MediaProtocol.File)
|
||||||
@ -322,80 +316,35 @@ namespace Jellyfin.Api.Controllers
|
|||||||
{
|
{
|
||||||
var contentType = state.GetMimeType("." + state.OutputContainer, false) ?? state.GetMimeType(state.MediaPath);
|
var contentType = state.GetMimeType("." + state.OutputContainer, false) ?? state.GetMimeType(state.MediaPath);
|
||||||
|
|
||||||
using (state)
|
if (state.MediaSource.IsInfiniteStream)
|
||||||
{
|
{
|
||||||
if (state.MediaSource.IsInfiniteStream)
|
// TODO AllowEndOfFile = false
|
||||||
{
|
await new ProgressiveFileCopier(_streamHelper, state.MediaPath).WriteToAsync(Response.Body, CancellationToken.None).ConfigureAwait(false);
|
||||||
// TODO AllowEndOfFile = false
|
|
||||||
await new ProgressiveFileCopier(_streamHelper, state.MediaPath).WriteToAsync(Response.Body, CancellationToken.None).ConfigureAwait(false);
|
|
||||||
|
|
||||||
return File(Response.Body, contentType);
|
return File(Response.Body, contentType);
|
||||||
}
|
|
||||||
|
|
||||||
return FileStreamResponseHelpers.GetStaticFileResult(
|
|
||||||
state.MediaPath,
|
|
||||||
contentType,
|
|
||||||
isHeadRequest,
|
|
||||||
this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return FileStreamResponseHelpers.GetStaticFileResult(
|
||||||
|
state.MediaPath,
|
||||||
|
contentType,
|
||||||
|
isHeadRequest,
|
||||||
|
this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
// Not static but transcode cache file exists
|
|
||||||
if (isTranscodeCached && state.VideoRequest == null)
|
|
||||||
{
|
|
||||||
var contentType = state.GetMimeType(outputPath)
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (transcodingJob != null)
|
|
||||||
{
|
|
||||||
ApiEntryPoint.Instance.OnTranscodeBeginRequest(transcodingJob);
|
|
||||||
}
|
|
||||||
return await ResultFactory.GetStaticFileResult(Request, new StaticFileResultOptions
|
|
||||||
{
|
|
||||||
ResponseHeaders = responseHeaders,
|
|
||||||
ContentType = contentType,
|
|
||||||
IsHeadRequest = isHeadRequest,
|
|
||||||
Path = outputPath,
|
|
||||||
FileShare = FileShare.ReadWrite,
|
|
||||||
OnComplete = () =>
|
|
||||||
{
|
|
||||||
if (transcodingJob != null)
|
|
||||||
{
|
|
||||||
ApiEntryPoint.Instance.OnTranscodeEndRequest(transcodingJob);
|
|
||||||
}
|
|
||||||
}).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
state.Dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Need to start ffmpeg (because media can't be returned directly)
|
// Need to start ffmpeg (because media can't be returned directly)
|
||||||
try
|
var encodingOptions = _serverConfigurationManager.GetEncodingOptions();
|
||||||
{
|
var encodingHelper = new EncodingHelper(_mediaEncoder, _fileSystem, _subtitleEncoder, _configuration);
|
||||||
var encodingOptions = _serverConfigurationManager.GetEncodingOptions();
|
var ffmpegCommandLineArguments = encodingHelper.GetProgressiveAudioFullCommandLine(state, encodingOptions, outputPath);
|
||||||
var encodingHelper = new EncodingHelper(_mediaEncoder, _fileSystem, _subtitleEncoder, _configuration);
|
return await FileStreamResponseHelpers.GetTranscodedFile(
|
||||||
var ffmpegCommandLineArguments = encodingHelper.GetProgressiveAudioFullCommandLine(state, encodingOptions, outputPath);
|
state,
|
||||||
return await FileStreamResponseHelpers.GetTranscodedFile(
|
isHeadRequest,
|
||||||
state,
|
_streamHelper,
|
||||||
isHeadRequest,
|
this,
|
||||||
_streamHelper,
|
_transcodingJobHelper,
|
||||||
this,
|
ffmpegCommandLineArguments,
|
||||||
_transcodingJobHelper,
|
Request,
|
||||||
ffmpegCommandLineArguments,
|
_transcodingJobType,
|
||||||
Request,
|
cancellationTokenSource).ConfigureAwait(false);
|
||||||
_transcodingJobType,
|
|
||||||
cancellationTokenSource).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
state.Dispose();
|
|
||||||
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,17 +36,14 @@ namespace Jellyfin.Api.Helpers
|
|||||||
httpClient.DefaultRequestHeaders.Add(HeaderNames.UserAgent, useragent);
|
httpClient.DefaultRequestHeaders.Add(HeaderNames.UserAgent, useragent);
|
||||||
}
|
}
|
||||||
|
|
||||||
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";
|
controller.Response.Headers[HeaderNames.AcceptRanges] = "none";
|
||||||
|
|
||||||
if (isHeadRequest)
|
if (isHeadRequest)
|
||||||
{
|
{
|
||||||
using (response)
|
return controller.File(Array.Empty<byte>(), contentType);
|
||||||
{
|
|
||||||
return controller.File(Array.Empty<byte>(), contentType);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return controller.File(await response.Content.ReadAsStreamAsync().ConfigureAwait(false), contentType);
|
return controller.File(await response.Content.ReadAsStreamAsync().ConfigureAwait(false), contentType);
|
||||||
@ -74,7 +71,7 @@ namespace Jellyfin.Api.Helpers
|
|||||||
return controller.NoContent();
|
return controller.NoContent();
|
||||||
}
|
}
|
||||||
|
|
||||||
var stream = new FileStream(path, FileMode.Open, FileAccess.Read);
|
using var stream = new FileStream(path, FileMode.Open, FileAccess.Read);
|
||||||
return controller.File(stream, contentType);
|
return controller.File(stream, contentType);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -129,11 +126,9 @@ namespace Jellyfin.Api.Helpers
|
|||||||
state.Dispose();
|
state.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
using (var memoryStream = new MemoryStream())
|
await using var memoryStream = new MemoryStream();
|
||||||
{
|
await new ProgressiveFileCopier(streamHelper, outputPath).WriteToAsync(memoryStream, CancellationToken.None).ConfigureAwait(false);
|
||||||
await new ProgressiveFileCopier(streamHelper, outputPath).WriteToAsync(memoryStream, CancellationToken.None).ConfigureAwait(false);
|
return controller.File(memoryStream, contentType);
|
||||||
return controller.File(memoryStream, contentType);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
@ -74,7 +74,7 @@ namespace Jellyfin.Api.Helpers
|
|||||||
{
|
{
|
||||||
var timeSeek = httpRequest.Headers["TimeSeekRange.dlna.org"];
|
var timeSeek = httpRequest.Headers["TimeSeekRange.dlna.org"];
|
||||||
|
|
||||||
streamingRequest.StartTimeTicks = ParseTimeSeekHeader(timeSeek);
|
streamingRequest.StartTimeTicks = ParseTimeSeekHeader(timeSeek.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(streamingRequest.Params))
|
if (!string.IsNullOrWhiteSpace(streamingRequest.Params))
|
||||||
@ -108,31 +108,22 @@ namespace Jellyfin.Api.Helpers
|
|||||||
state.User = userManager.GetUserById(auth.UserId);
|
state.User = userManager.GetUserById(auth.UserId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
if ((Request.UserAgent ?? string.Empty).IndexOf("iphone", StringComparison.OrdinalIgnoreCase) != -1 ||
|
|
||||||
(Request.UserAgent ?? string.Empty).IndexOf("ipad", StringComparison.OrdinalIgnoreCase) != -1 ||
|
|
||||||
(Request.UserAgent ?? string.Empty).IndexOf("ipod", StringComparison.OrdinalIgnoreCase) != -1)
|
|
||||||
{
|
|
||||||
state.SegmentLength = 6;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (state.IsVideoRequest && !string.IsNullOrWhiteSpace(state.Request.VideoCodec))
|
if (state.IsVideoRequest && !string.IsNullOrWhiteSpace(state.Request.VideoCodec))
|
||||||
{
|
{
|
||||||
state.SupportedVideoCodecs = state.Request.VideoCodec.Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).ToArray();
|
state.SupportedVideoCodecs = state.Request.VideoCodec.Split(',', StringSplitOptions.RemoveEmptyEntries);
|
||||||
state.Request.VideoCodec = state.SupportedVideoCodecs.FirstOrDefault();
|
state.Request.VideoCodec = state.SupportedVideoCodecs.FirstOrDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(streamingRequest.AudioCodec))
|
if (!string.IsNullOrWhiteSpace(streamingRequest.AudioCodec))
|
||||||
{
|
{
|
||||||
state.SupportedAudioCodecs = streamingRequest.AudioCodec.Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).ToArray();
|
state.SupportedAudioCodecs = streamingRequest.AudioCodec.Split(',', StringSplitOptions.RemoveEmptyEntries);
|
||||||
state.Request.AudioCodec = state.SupportedAudioCodecs.FirstOrDefault(i => mediaEncoder.CanEncodeToAudioCodec(i))
|
state.Request.AudioCodec = state.SupportedAudioCodecs.FirstOrDefault(i => mediaEncoder.CanEncodeToAudioCodec(i))
|
||||||
?? state.SupportedAudioCodecs.FirstOrDefault();
|
?? state.SupportedAudioCodecs.FirstOrDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(streamingRequest.SubtitleCodec))
|
if (!string.IsNullOrWhiteSpace(streamingRequest.SubtitleCodec))
|
||||||
{
|
{
|
||||||
state.SupportedSubtitleCodecs = streamingRequest.SubtitleCodec.Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).ToArray();
|
state.SupportedSubtitleCodecs = streamingRequest.SubtitleCodec.Split(',', StringSplitOptions.RemoveEmptyEntries);
|
||||||
state.Request.SubtitleCodec = state.SupportedSubtitleCodecs.FirstOrDefault(i => mediaEncoder.CanEncodeToSubtitleCodec(i))
|
state.Request.SubtitleCodec = state.SupportedSubtitleCodecs.FirstOrDefault(i => mediaEncoder.CanEncodeToSubtitleCodec(i))
|
||||||
?? state.SupportedSubtitleCodecs.FirstOrDefault();
|
?? state.SupportedSubtitleCodecs.FirstOrDefault();
|
||||||
}
|
}
|
||||||
@ -141,15 +132,6 @@ namespace Jellyfin.Api.Helpers
|
|||||||
|
|
||||||
state.IsInputVideo = string.Equals(item.MediaType, MediaType.Video, StringComparison.OrdinalIgnoreCase);
|
state.IsInputVideo = string.Equals(item.MediaType, MediaType.Video, StringComparison.OrdinalIgnoreCase);
|
||||||
|
|
||||||
/*
|
|
||||||
var primaryImage = item.GetImageInfo(ImageType.Primary, 0) ??
|
|
||||||
item.Parents.Select(i => i.GetImageInfo(ImageType.Primary, 0)).FirstOrDefault(i => i != null);
|
|
||||||
if (primaryImage != null)
|
|
||||||
{
|
|
||||||
state.AlbumCoverPath = primaryImage.Path;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
MediaSourceInfo? mediaSource = null;
|
MediaSourceInfo? mediaSource = null;
|
||||||
if (string.IsNullOrWhiteSpace(streamingRequest.LiveStreamId))
|
if (string.IsNullOrWhiteSpace(streamingRequest.LiveStreamId))
|
||||||
{
|
{
|
||||||
@ -322,25 +304,24 @@ namespace Jellyfin.Api.Helpers
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="value">The time seek header string.</param>
|
/// <param name="value">The time seek header string.</param>
|
||||||
/// <returns>A nullable <see cref="long"/> representing the seek time in ticks.</returns>
|
/// <returns>A nullable <see cref="long"/> representing the seek time in ticks.</returns>
|
||||||
private static long? ParseTimeSeekHeader(string value)
|
private static long? ParseTimeSeekHeader(ReadOnlySpan<char> value)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(value))
|
if (value.IsEmpty)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const string Npt = "npt=";
|
const string npt = "npt=";
|
||||||
if (!value.StartsWith(Npt, StringComparison.OrdinalIgnoreCase))
|
if (!value.StartsWith(npt, StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
throw new ArgumentException("Invalid timeseek header");
|
throw new ArgumentException("Invalid timeseek header");
|
||||||
}
|
}
|
||||||
|
|
||||||
int index = value.IndexOf('-', StringComparison.InvariantCulture);
|
var index = value.IndexOf('-');
|
||||||
value = index == -1
|
value = index == -1
|
||||||
? value.Substring(Npt.Length)
|
? value.Slice(npt.Length)
|
||||||
: value.Substring(Npt.Length, index - Npt.Length);
|
: value.Slice(npt.Length, index - npt.Length);
|
||||||
|
if (value.IndexOf(':') == -1)
|
||||||
if (value.IndexOf(':', StringComparison.InvariantCulture) == -1)
|
|
||||||
{
|
{
|
||||||
// Parses npt times in the format of '417.33'
|
// Parses npt times in the format of '417.33'
|
||||||
if (double.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out var seconds))
|
if (double.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out var seconds))
|
||||||
@ -351,26 +332,15 @@ namespace Jellyfin.Api.Helpers
|
|||||||
throw new ArgumentException("Invalid timeseek header");
|
throw new ArgumentException("Invalid timeseek header");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parses npt times in the format of '10:19:25.7'
|
try
|
||||||
var tokens = value.Split(new[] { ':' }, 3);
|
|
||||||
double secondsSum = 0;
|
|
||||||
var timeFactor = 3600;
|
|
||||||
|
|
||||||
foreach (var time in tokens)
|
|
||||||
{
|
{
|
||||||
if (double.TryParse(time, NumberStyles.Any, CultureInfo.InvariantCulture, out var digit))
|
// Parses npt times in the format of '10:19:25.7'
|
||||||
{
|
return TimeSpan.Parse(value).Ticks;
|
||||||
secondsSum += digit * timeFactor;
|
}
|
||||||
}
|
catch
|
||||||
else
|
{
|
||||||
{
|
throw new ArgumentException("Invalid timeseek header");
|
||||||
throw new ArgumentException("Invalid timeseek header");
|
|
||||||
}
|
|
||||||
|
|
||||||
timeFactor /= 60;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return TimeSpan.FromSeconds(secondsSum).Ticks;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -88,11 +88,11 @@ namespace Jellyfin.Api.Models.StreamingDtos
|
|||||||
{
|
{
|
||||||
var userAgent = UserAgent ?? string.Empty;
|
var userAgent = UserAgent ?? string.Empty;
|
||||||
|
|
||||||
if (userAgent.IndexOf("AppleTV", StringComparison.OrdinalIgnoreCase) != -1 ||
|
if (userAgent.IndexOf("AppleTV", StringComparison.OrdinalIgnoreCase) != -1
|
||||||
userAgent.IndexOf("cfnetwork", StringComparison.OrdinalIgnoreCase) != -1 ||
|
|| userAgent.IndexOf("cfnetwork", StringComparison.OrdinalIgnoreCase) != -1
|
||||||
userAgent.IndexOf("ipad", StringComparison.OrdinalIgnoreCase) != -1 ||
|
|| userAgent.IndexOf("ipad", StringComparison.OrdinalIgnoreCase) != -1
|
||||||
userAgent.IndexOf("iphone", StringComparison.OrdinalIgnoreCase) != -1 ||
|
|| userAgent.IndexOf("iphone", StringComparison.OrdinalIgnoreCase) != -1
|
||||||
userAgent.IndexOf("ipod", StringComparison.OrdinalIgnoreCase) != -1)
|
|| userAgent.IndexOf("ipod", StringComparison.OrdinalIgnoreCase) != -1)
|
||||||
{
|
{
|
||||||
return 6;
|
return 6;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user