diff options
| author | Bond-009 <bond.009@outlook.com> | 2020-08-20 16:40:03 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-08-20 16:40:03 +0200 |
| commit | 5160e627f18fb4a763eaa77b836d20486e55c5e9 (patch) | |
| tree | 5fb90ba0ee4d217384d31d1828b6a42a74168a45 /Jellyfin.Api/Controllers/HlsSegmentController.cs | |
| parent | 3588ee5229b76bca9417813e208e86492e06d609 (diff) | |
| parent | 250e351613e0eed7977c8cdad4a9078927458feb (diff) | |
Merge branch 'master' into feature/ffmpeg-version-check
Diffstat (limited to 'Jellyfin.Api/Controllers/HlsSegmentController.cs')
| -rw-r--r-- | Jellyfin.Api/Controllers/HlsSegmentController.cs | 154 |
1 files changed, 154 insertions, 0 deletions
diff --git a/Jellyfin.Api/Controllers/HlsSegmentController.cs b/Jellyfin.Api/Controllers/HlsSegmentController.cs new file mode 100644 index 000000000..816252f80 --- /dev/null +++ b/Jellyfin.Api/Controllers/HlsSegmentController.cs @@ -0,0 +1,154 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using Jellyfin.Api.Constants; +using Jellyfin.Api.Helpers; +using MediaBrowser.Common.Configuration; +using MediaBrowser.Controller.Configuration; +using MediaBrowser.Controller.MediaEncoding; +using MediaBrowser.Model.IO; +using MediaBrowser.Model.Net; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; + +namespace Jellyfin.Api.Controllers +{ + /// <summary> + /// The hls segment controller. + /// </summary> + [Route("")] + public class HlsSegmentController : BaseJellyfinApiController + { + private readonly IFileSystem _fileSystem; + private readonly IServerConfigurationManager _serverConfigurationManager; + private readonly TranscodingJobHelper _transcodingJobHelper; + + /// <summary> + /// Initializes a new instance of the <see cref="HlsSegmentController"/> class. + /// </summary> + /// <param name="fileSystem">Instance of the <see cref="IFileSystem"/> interface.</param> + /// <param name="serverConfigurationManager">Instance of the <see cref="IServerConfigurationManager"/> interface.</param> + /// <param name="transcodingJobHelper">Initialized instance of the <see cref="TranscodingJobHelper"/>.</param> + public HlsSegmentController( + IFileSystem fileSystem, + IServerConfigurationManager serverConfigurationManager, + TranscodingJobHelper transcodingJobHelper) + { + _fileSystem = fileSystem; + _serverConfigurationManager = serverConfigurationManager; + _transcodingJobHelper = transcodingJobHelper; + } + + /// <summary> + /// Gets the specified audio segment for an audio item. + /// </summary> + /// <param name="itemId">The item id.</param> + /// <param name="segmentId">The segment id.</param> + /// <response code="200">Hls audio segment returned.</response> + /// <returns>A <see cref="FileStreamResult"/> containing the audio stream.</returns> + // Can't require authentication just yet due to seeing some requests come from Chrome without full query string + // [Authenticated] + [HttpGet("Audio/{itemId}/hls/{segmentId}/stream.mp3", Name = "GetHlsAudioSegmentLegacyMp3")] + [HttpGet("Audio/{itemId}/hls/{segmentId}/stream.aac", Name = "GetHlsAudioSegmentLegacyAac")] + [ProducesResponseType(StatusCodes.Status200OK)] + [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "itemId", Justification = "Required for ServiceStack")] + public ActionResult GetHlsAudioSegmentLegacy([FromRoute] string itemId, [FromRoute] string segmentId) + { + // TODO: Deprecate with new iOS app + var file = segmentId + Path.GetExtension(Request.Path); + file = Path.Combine(_serverConfigurationManager.GetTranscodePath(), file); + + return FileStreamResponseHelpers.GetStaticFileResult(file, MimeTypes.GetMimeType(file)!, false, HttpContext); + } + + /// <summary> + /// Gets a hls video playlist. + /// </summary> + /// <param name="itemId">The video id.</param> + /// <param name="playlistId">The playlist id.</param> + /// <response code="200">Hls video playlist returned.</response> + /// <returns>A <see cref="FileStreamResult"/> containing the playlist.</returns> + [HttpGet("Videos/{itemId}/hls/{playlistId}/stream.m3u8")] + [Authorize(Policy = Policies.DefaultAuthorization)] + [ProducesResponseType(StatusCodes.Status200OK)] + [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "itemId", Justification = "Required for ServiceStack")] + public ActionResult GetHlsPlaylistLegacy([FromRoute] string itemId, [FromRoute] string playlistId) + { + var file = playlistId + Path.GetExtension(Request.Path); + file = Path.Combine(_serverConfigurationManager.GetTranscodePath(), file); + + return GetFileResult(file, file); + } + + /// <summary> + /// Stops an active encoding. + /// </summary> + /// <param name="deviceId">The device id of the client requesting. Used to stop encoding processes when needed.</param> + /// <param name="playSessionId">The play session id.</param> + /// <response code="204">Encoding stopped successfully.</response> + /// <returns>A <see cref="NoContentResult"/> indicating success.</returns> + [HttpDelete("Videos/ActiveEncodings")] + [Authorize(Policy = Policies.DefaultAuthorization)] + [ProducesResponseType(StatusCodes.Status204NoContent)] + public ActionResult StopEncodingProcess([FromQuery] string deviceId, [FromQuery] string playSessionId) + { + _transcodingJobHelper.KillTranscodingJobs(deviceId, playSessionId, path => true); + return NoContent(); + } + + /// <summary> + /// Gets a hls video segment. + /// </summary> + /// <param name="itemId">The item id.</param> + /// <param name="playlistId">The playlist id.</param> + /// <param name="segmentId">The segment id.</param> + /// <param name="segmentContainer">The segment container.</param> + /// <response code="200">Hls video segment returned.</response> + /// <returns>A <see cref="FileStreamResult"/> containing the video segment.</returns> + // Can't require authentication just yet due to seeing some requests come from Chrome without full query string + // [Authenticated] + [HttpGet("Videos/{itemId}/hls/{playlistId}/{segmentId}.{segmentContainer}")] + [ProducesResponseType(StatusCodes.Status200OK)] + [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "itemId", Justification = "Required for ServiceStack")] + public ActionResult GetHlsVideoSegmentLegacy( + [FromRoute] string itemId, + [FromRoute] string playlistId, + [FromRoute] string segmentId, + [FromRoute] string segmentContainer) + { + var file = segmentId + Path.GetExtension(Request.Path); + var transcodeFolderPath = _serverConfigurationManager.GetTranscodePath(); + + file = Path.Combine(transcodeFolderPath, file); + + var normalizedPlaylistId = playlistId; + + var playlistPath = _fileSystem.GetFilePaths(transcodeFolderPath) + .FirstOrDefault(i => + string.Equals(Path.GetExtension(i), ".m3u8", StringComparison.OrdinalIgnoreCase) + && i.IndexOf(normalizedPlaylistId, StringComparison.OrdinalIgnoreCase) != -1); + + return GetFileResult(file, playlistPath); + } + + private ActionResult GetFileResult(string path, string playlistPath) + { + var transcodingJob = _transcodingJobHelper.OnTranscodeBeginRequest(playlistPath, TranscodingJobType.Hls); + + Response.OnCompleted(() => + { + if (transcodingJob != null) + { + _transcodingJobHelper.OnTranscodeEndRequest(transcodingJob); + } + + return Task.CompletedTask; + }); + + return FileStreamResponseHelpers.GetStaticFileResult(path, MimeTypes.GetMimeType(path)!, false, HttpContext); + } + } +} |
