Fix suggestions from review

pull/3592/head
David 4 years ago
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 FileStreamResponseHelpers.GetStaticFileResult( return File(Response.Body, contentType);
state.MediaPath,
contentType,
isHeadRequest,
this);
} }
}
/* return FileStreamResponseHelpers.GetStaticFileResult(
// Not static but transcode cache file exists state.MediaPath,
if (isTranscodeCached && state.VideoRequest == null) contentType,
{
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)
try
{
var encodingOptions = _serverConfigurationManager.GetEncodingOptions();
var encodingHelper = new EncodingHelper(_mediaEncoder, _fileSystem, _subtitleEncoder, _configuration);
var ffmpegCommandLineArguments = encodingHelper.GetProgressiveAudioFullCommandLine(state, encodingOptions, outputPath);
return await FileStreamResponseHelpers.GetTranscodedFile(
state,
isHeadRequest, isHeadRequest,
_streamHelper, this);
this,
_transcodingJobHelper,
ffmpegCommandLineArguments,
Request,
_transcodingJobType,
cancellationTokenSource).ConfigureAwait(false);
} }
catch
{
state.Dispose();
throw; // Need to start ffmpeg (because media can't be returned directly)
} var encodingOptions = _serverConfigurationManager.GetEncodingOptions();
var encodingHelper = new EncodingHelper(_mediaEncoder, _fileSystem, _subtitleEncoder, _configuration);
var ffmpegCommandLineArguments = encodingHelper.GetProgressiveAudioFullCommandLine(state, encodingOptions, outputPath);
return await FileStreamResponseHelpers.GetTranscodedFile(
state,
isHeadRequest,
_streamHelper,
this,
_transcodingJobHelper,
ffmpegCommandLineArguments,
Request,
_transcodingJobType,
cancellationTokenSource).ConfigureAwait(false);
} }
} }
} }

@ -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…
Cancel
Save