using System; using System.IO; using System.Linq; using System.Threading.Tasks; using MediaBrowser.Common.Configuration; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.Controller.Net; using MediaBrowser.Model.IO; using MediaBrowser.Model.Services; using Microsoft.Extensions.Logging; namespace MediaBrowser.Api.Playback.Hls { /// /// Class GetHlsAudioSegment /// // Can't require authentication just yet due to seeing some requests come from Chrome without full query string //[Authenticated] [Route("/Audio/{Id}/hls/{SegmentId}/stream.mp3", "GET")] [Route("/Audio/{Id}/hls/{SegmentId}/stream.aac", "GET")] public class GetHlsAudioSegmentLegacy { // TODO: Deprecate with new iOS app /// /// Gets or sets the id. /// /// The id. public string Id { get; set; } /// /// Gets or sets the segment id. /// /// The segment id. public string SegmentId { get; set; } } /// /// Class GetHlsVideoSegment /// [Route("/Videos/{Id}/hls/{PlaylistId}/stream.m3u8", "GET")] [Authenticated] public class GetHlsPlaylistLegacy { // TODO: Deprecate with new iOS app /// /// Gets or sets the id. /// /// The id. public string Id { get; set; } public string PlaylistId { get; set; } } [Route("/Videos/ActiveEncodings", "DELETE")] [Authenticated] public class StopEncodingProcess { [ApiMember(Name = "DeviceId", Description = "The device id of the client requesting. Used to stop encoding processes when needed.", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "DELETE")] public string DeviceId { get; set; } [ApiMember(Name = "PlaySessionId", Description = "The play session id", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "DELETE")] public string PlaySessionId { get; set; } } /// /// Class GetHlsVideoSegment /// // Can't require authentication just yet due to seeing some requests come from Chrome without full query string //[Authenticated] [Route("/Videos/{Id}/hls/{PlaylistId}/{SegmentId}.{SegmentContainer}", "GET")] public class GetHlsVideoSegmentLegacy : VideoStreamRequest { public string PlaylistId { get; set; } /// /// Gets or sets the segment id. /// /// The segment id. public string SegmentId { get; set; } } public class HlsSegmentService : BaseApiService { private readonly IFileSystem _fileSystem; public HlsSegmentService( ILogger logger, IServerConfigurationManager serverConfigurationManager, IHttpResultFactory httpResultFactory, IFileSystem fileSystem) : base(logger, serverConfigurationManager, httpResultFactory) { _fileSystem = fileSystem; } public Task Get(GetHlsPlaylistLegacy request) { var file = request.PlaylistId + Path.GetExtension(Request.PathInfo); file = Path.Combine(ServerConfigurationManager.GetTranscodePath(), file); return GetFileResult(file, file); } public Task Delete(StopEncodingProcess request) { return ApiEntryPoint.Instance.KillTranscodingJobs(request.DeviceId, request.PlaySessionId, path => true); } /// /// Gets the specified request. /// /// The request. /// System.Object. public Task Get(GetHlsVideoSegmentLegacy request) { var file = request.SegmentId + Path.GetExtension(Request.PathInfo); var transcodeFolderPath = ServerConfigurationManager.GetTranscodePath(); file = Path.Combine(transcodeFolderPath, file); var normalizedPlaylistId = request.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); } /// /// Gets the specified request. /// /// The request. /// System.Object. public Task Get(GetHlsAudioSegmentLegacy request) { // TODO: Deprecate with new iOS app var file = request.SegmentId + Path.GetExtension(Request.PathInfo); file = Path.Combine(ServerConfigurationManager.GetTranscodePath(), file); return ResultFactory.GetStaticFileResult(Request, file, FileShare.ReadWrite); } private Task GetFileResult(string path, string playlistPath) { var transcodingJob = ApiEntryPoint.Instance.OnTranscodeBeginRequest(playlistPath, TranscodingJobType.Hls); return ResultFactory.GetStaticFileResult(Request, new StaticFileResultOptions { Path = path, FileShare = FileShare.ReadWrite, OnComplete = () => { if (transcodingJob != null) { ApiEntryPoint.Instance.OnTranscodeEndRequest(transcodingJob); } } }); } } }