mirror of https://github.com/jellyfin/jellyfin.git
Remove DLNA API code
This commit is contained in:
parent
0a03539dc4
commit
01fd42cf95
|
@ -1,25 +0,0 @@
|
||||||
using Emby.Dlna;
|
|
||||||
using MediaBrowser.Controller.Configuration;
|
|
||||||
using Microsoft.AspNetCore.Http;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
using Microsoft.AspNetCore.Mvc.Filters;
|
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
|
||||||
|
|
||||||
namespace Jellyfin.Api.Attributes;
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public sealed class DlnaEnabledAttribute : ActionFilterAttribute
|
|
||||||
{
|
|
||||||
/// <inheritdoc />
|
|
||||||
public override void OnActionExecuting(ActionExecutingContext context)
|
|
||||||
{
|
|
||||||
var serverConfigurationManager = context.HttpContext.RequestServices.GetRequiredService<IServerConfigurationManager>();
|
|
||||||
|
|
||||||
var enabled = serverConfigurationManager.GetDlnaConfiguration().EnableServer;
|
|
||||||
|
|
||||||
if (!enabled)
|
|
||||||
{
|
|
||||||
context.Result = new StatusCodeResult(StatusCodes.Status503ServiceUnavailable);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,29 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using Microsoft.AspNetCore.Mvc.Routing;
|
|
||||||
|
|
||||||
namespace Jellyfin.Api.Attributes;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Identifies an action that supports the HTTP GET method.
|
|
||||||
/// </summary>
|
|
||||||
public sealed class HttpSubscribeAttribute : HttpMethodAttribute
|
|
||||||
{
|
|
||||||
private static readonly IEnumerable<string> _supportedMethods = new[] { "SUBSCRIBE" };
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="HttpSubscribeAttribute"/> class.
|
|
||||||
/// </summary>
|
|
||||||
public HttpSubscribeAttribute()
|
|
||||||
: base(_supportedMethods)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="HttpSubscribeAttribute"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="template">The route template. May not be null.</param>
|
|
||||||
public HttpSubscribeAttribute(string template)
|
|
||||||
: base(_supportedMethods, template)
|
|
||||||
=> ArgumentNullException.ThrowIfNull(template);
|
|
||||||
}
|
|
|
@ -1,29 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using Microsoft.AspNetCore.Mvc.Routing;
|
|
||||||
|
|
||||||
namespace Jellyfin.Api.Attributes;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Identifies an action that supports the HTTP GET method.
|
|
||||||
/// </summary>
|
|
||||||
public sealed class HttpUnsubscribeAttribute : HttpMethodAttribute
|
|
||||||
{
|
|
||||||
private static readonly IEnumerable<string> _supportedMethods = new[] { "UNSUBSCRIBE" };
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="HttpUnsubscribeAttribute"/> class.
|
|
||||||
/// </summary>
|
|
||||||
public HttpUnsubscribeAttribute()
|
|
||||||
: base(_supportedMethods)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="HttpUnsubscribeAttribute"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="template">The route template. May not be null.</param>
|
|
||||||
public HttpUnsubscribeAttribute(string template)
|
|
||||||
: base(_supportedMethods, template)
|
|
||||||
=> ArgumentNullException.ThrowIfNull(template);
|
|
||||||
}
|
|
|
@ -15,7 +15,6 @@ namespace Jellyfin.Api.Controllers;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The audio controller.
|
/// The audio controller.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
// TODO: In order to authenticate this in the future, Dlna playback will require updating
|
|
||||||
public class AudioController : BaseJellyfinApiController
|
public class AudioController : BaseJellyfinApiController
|
||||||
{
|
{
|
||||||
private readonly AudioHelper _audioHelper;
|
private readonly AudioHelper _audioHelper;
|
||||||
|
@ -95,7 +94,7 @@ public class AudioController : BaseJellyfinApiController
|
||||||
[FromQuery] bool? @static,
|
[FromQuery] bool? @static,
|
||||||
[FromQuery] string? @params,
|
[FromQuery] string? @params,
|
||||||
[FromQuery] string? tag,
|
[FromQuery] string? tag,
|
||||||
[FromQuery] string? deviceProfileId,
|
[FromQuery, ParameterObsolete] string? deviceProfileId,
|
||||||
[FromQuery] string? playSessionId,
|
[FromQuery] string? playSessionId,
|
||||||
[FromQuery] string? segmentContainer,
|
[FromQuery] string? segmentContainer,
|
||||||
[FromQuery] int? segmentLength,
|
[FromQuery] int? segmentLength,
|
||||||
|
@ -147,7 +146,6 @@ public class AudioController : BaseJellyfinApiController
|
||||||
Static = @static ?? false,
|
Static = @static ?? false,
|
||||||
Params = @params,
|
Params = @params,
|
||||||
Tag = tag,
|
Tag = tag,
|
||||||
DeviceProfileId = deviceProfileId,
|
|
||||||
PlaySessionId = playSessionId,
|
PlaySessionId = playSessionId,
|
||||||
SegmentContainer = segmentContainer,
|
SegmentContainer = segmentContainer,
|
||||||
SegmentLength = segmentLength,
|
SegmentLength = segmentLength,
|
||||||
|
@ -260,7 +258,7 @@ public class AudioController : BaseJellyfinApiController
|
||||||
[FromQuery] bool? @static,
|
[FromQuery] bool? @static,
|
||||||
[FromQuery] string? @params,
|
[FromQuery] string? @params,
|
||||||
[FromQuery] string? tag,
|
[FromQuery] string? tag,
|
||||||
[FromQuery] string? deviceProfileId,
|
[FromQuery, ParameterObsolete] string? deviceProfileId,
|
||||||
[FromQuery] string? playSessionId,
|
[FromQuery] string? playSessionId,
|
||||||
[FromQuery] string? segmentContainer,
|
[FromQuery] string? segmentContainer,
|
||||||
[FromQuery] int? segmentLength,
|
[FromQuery] int? segmentLength,
|
||||||
|
@ -312,7 +310,6 @@ public class AudioController : BaseJellyfinApiController
|
||||||
Static = @static ?? false,
|
Static = @static ?? false,
|
||||||
Params = @params,
|
Params = @params,
|
||||||
Tag = tag,
|
Tag = tag,
|
||||||
DeviceProfileId = deviceProfileId,
|
|
||||||
PlaySessionId = playSessionId,
|
PlaySessionId = playSessionId,
|
||||||
SegmentContainer = segmentContainer,
|
SegmentContainer = segmentContainer,
|
||||||
SegmentLength = segmentLength,
|
SegmentLength = segmentLength,
|
||||||
|
|
|
@ -1,133 +0,0 @@
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.ComponentModel.DataAnnotations;
|
|
||||||
using Jellyfin.Api.Constants;
|
|
||||||
using MediaBrowser.Common.Api;
|
|
||||||
using MediaBrowser.Controller.Dlna;
|
|
||||||
using MediaBrowser.Model.Dlna;
|
|
||||||
using Microsoft.AspNetCore.Authorization;
|
|
||||||
using Microsoft.AspNetCore.Http;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
|
|
||||||
namespace Jellyfin.Api.Controllers;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Dlna Controller.
|
|
||||||
/// </summary>
|
|
||||||
[Authorize(Policy = Policies.RequiresElevation)]
|
|
||||||
public class DlnaController : BaseJellyfinApiController
|
|
||||||
{
|
|
||||||
private readonly IDlnaManager _dlnaManager;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="DlnaController"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="dlnaManager">Instance of the <see cref="IDlnaManager"/> interface.</param>
|
|
||||||
public DlnaController(IDlnaManager dlnaManager)
|
|
||||||
{
|
|
||||||
_dlnaManager = dlnaManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Get profile infos.
|
|
||||||
/// </summary>
|
|
||||||
/// <response code="200">Device profile infos returned.</response>
|
|
||||||
/// <returns>An <see cref="OkResult"/> containing the device profile infos.</returns>
|
|
||||||
[HttpGet("ProfileInfos")]
|
|
||||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
|
||||||
public ActionResult<IEnumerable<DeviceProfileInfo>> GetProfileInfos()
|
|
||||||
{
|
|
||||||
return Ok(_dlnaManager.GetProfileInfos());
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the default profile.
|
|
||||||
/// </summary>
|
|
||||||
/// <response code="200">Default device profile returned.</response>
|
|
||||||
/// <returns>An <see cref="OkResult"/> containing the default profile.</returns>
|
|
||||||
[HttpGet("Profiles/Default")]
|
|
||||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
|
||||||
public ActionResult<DeviceProfile> GetDefaultProfile()
|
|
||||||
{
|
|
||||||
return _dlnaManager.GetDefaultProfile();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a single profile.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="profileId">Profile Id.</param>
|
|
||||||
/// <response code="200">Device profile returned.</response>
|
|
||||||
/// <response code="404">Device profile not found.</response>
|
|
||||||
/// <returns>An <see cref="OkResult"/> containing the profile on success, or a <see cref="NotFoundResult"/> if device profile not found.</returns>
|
|
||||||
[HttpGet("Profiles/{profileId}")]
|
|
||||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
|
||||||
public ActionResult<DeviceProfile> GetProfile([FromRoute, Required] string profileId)
|
|
||||||
{
|
|
||||||
var profile = _dlnaManager.GetProfile(profileId);
|
|
||||||
if (profile is null)
|
|
||||||
{
|
|
||||||
return NotFound();
|
|
||||||
}
|
|
||||||
|
|
||||||
return profile;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Deletes a profile.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="profileId">Profile id.</param>
|
|
||||||
/// <response code="204">Device profile deleted.</response>
|
|
||||||
/// <response code="404">Device profile not found.</response>
|
|
||||||
/// <returns>A <see cref="NoContentResult"/> on success, or a <see cref="NotFoundResult"/> if profile not found.</returns>
|
|
||||||
[HttpDelete("Profiles/{profileId}")]
|
|
||||||
[ProducesResponseType(StatusCodes.Status204NoContent)]
|
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
|
||||||
public ActionResult DeleteProfile([FromRoute, Required] string profileId)
|
|
||||||
{
|
|
||||||
var existingDeviceProfile = _dlnaManager.GetProfile(profileId);
|
|
||||||
if (existingDeviceProfile is null)
|
|
||||||
{
|
|
||||||
return NotFound();
|
|
||||||
}
|
|
||||||
|
|
||||||
_dlnaManager.DeleteProfile(profileId);
|
|
||||||
return NoContent();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a profile.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="deviceProfile">Device profile.</param>
|
|
||||||
/// <response code="204">Device profile created.</response>
|
|
||||||
/// <returns>A <see cref="NoContentResult"/>.</returns>
|
|
||||||
[HttpPost("Profiles")]
|
|
||||||
[ProducesResponseType(StatusCodes.Status204NoContent)]
|
|
||||||
public ActionResult CreateProfile([FromBody] DeviceProfile deviceProfile)
|
|
||||||
{
|
|
||||||
_dlnaManager.CreateProfile(deviceProfile);
|
|
||||||
return NoContent();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Updates a profile.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="profileId">Profile id.</param>
|
|
||||||
/// <param name="deviceProfile">Device profile.</param>
|
|
||||||
/// <response code="204">Device profile updated.</response>
|
|
||||||
/// <response code="404">Device profile not found.</response>
|
|
||||||
/// <returns>A <see cref="NoContentResult"/> on success, or a <see cref="NotFoundResult"/> if profile not found.</returns>
|
|
||||||
[HttpPost("Profiles/{profileId}")]
|
|
||||||
[ProducesResponseType(StatusCodes.Status204NoContent)]
|
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
|
||||||
public ActionResult UpdateProfile([FromRoute, Required] string profileId, [FromBody] DeviceProfile deviceProfile)
|
|
||||||
{
|
|
||||||
var existingDeviceProfile = _dlnaManager.GetProfile(profileId);
|
|
||||||
if (existingDeviceProfile is null)
|
|
||||||
{
|
|
||||||
return NotFound();
|
|
||||||
}
|
|
||||||
|
|
||||||
_dlnaManager.UpdateProfile(profileId, deviceProfile);
|
|
||||||
return NoContent();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,330 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.ComponentModel.DataAnnotations;
|
|
||||||
using System.Diagnostics.CodeAnalysis;
|
|
||||||
using System.IO;
|
|
||||||
using System.Net.Mime;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Emby.Dlna;
|
|
||||||
using Jellyfin.Api.Attributes;
|
|
||||||
using Jellyfin.Api.Constants;
|
|
||||||
using MediaBrowser.Common.Api;
|
|
||||||
using MediaBrowser.Controller.Dlna;
|
|
||||||
using MediaBrowser.Model.Net;
|
|
||||||
using Microsoft.AspNetCore.Authorization;
|
|
||||||
using Microsoft.AspNetCore.Http;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
|
|
||||||
namespace Jellyfin.Api.Controllers;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Dlna Server Controller.
|
|
||||||
/// </summary>
|
|
||||||
[Route("Dlna")]
|
|
||||||
[DlnaEnabled]
|
|
||||||
[Authorize(Policy = Policies.AnonymousLanAccessPolicy)]
|
|
||||||
public class DlnaServerController : BaseJellyfinApiController
|
|
||||||
{
|
|
||||||
private readonly IDlnaManager _dlnaManager;
|
|
||||||
private readonly IContentDirectory _contentDirectory;
|
|
||||||
private readonly IConnectionManager _connectionManager;
|
|
||||||
private readonly IMediaReceiverRegistrar _mediaReceiverRegistrar;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="DlnaServerController"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="dlnaManager">Instance of the <see cref="IDlnaManager"/> interface.</param>
|
|
||||||
/// <param name="contentDirectory">Instance of the <see cref="IContentDirectory"/> interface.</param>
|
|
||||||
/// <param name="connectionManager">Instance of the <see cref="IConnectionManager"/> interface.</param>
|
|
||||||
/// <param name="mediaReceiverRegistrar">Instance of the <see cref="IMediaReceiverRegistrar"/> interface.</param>
|
|
||||||
public DlnaServerController(
|
|
||||||
IDlnaManager dlnaManager,
|
|
||||||
IContentDirectory contentDirectory,
|
|
||||||
IConnectionManager connectionManager,
|
|
||||||
IMediaReceiverRegistrar mediaReceiverRegistrar)
|
|
||||||
{
|
|
||||||
_dlnaManager = dlnaManager;
|
|
||||||
_contentDirectory = contentDirectory;
|
|
||||||
_connectionManager = connectionManager;
|
|
||||||
_mediaReceiverRegistrar = mediaReceiverRegistrar;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Get Description Xml.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="serverId">Server UUID.</param>
|
|
||||||
/// <response code="200">Description xml returned.</response>
|
|
||||||
/// <response code="503">DLNA is disabled.</response>
|
|
||||||
/// <returns>An <see cref="OkResult"/> containing the description xml.</returns>
|
|
||||||
[HttpGet("{serverId}/description")]
|
|
||||||
[HttpGet("{serverId}/description.xml", Name = "GetDescriptionXml_2")]
|
|
||||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
|
||||||
[ProducesResponseType(StatusCodes.Status503ServiceUnavailable)]
|
|
||||||
[Produces(MediaTypeNames.Text.Xml)]
|
|
||||||
[ProducesFile(MediaTypeNames.Text.Xml)]
|
|
||||||
public ActionResult<string> GetDescriptionXml([FromRoute, Required] string serverId)
|
|
||||||
{
|
|
||||||
var url = GetAbsoluteUri();
|
|
||||||
var serverAddress = url.Substring(0, url.IndexOf("/dlna/", StringComparison.OrdinalIgnoreCase));
|
|
||||||
var xml = _dlnaManager.GetServerDescriptionXml(Request.Headers, serverId, serverAddress);
|
|
||||||
return Ok(xml);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets Dlna content directory xml.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="serverId">Server UUID.</param>
|
|
||||||
/// <response code="200">Dlna content directory returned.</response>
|
|
||||||
/// <response code="503">DLNA is disabled.</response>
|
|
||||||
/// <returns>An <see cref="OkResult"/> containing the dlna content directory xml.</returns>
|
|
||||||
[HttpGet("{serverId}/ContentDirectory")]
|
|
||||||
[HttpGet("{serverId}/ContentDirectory/ContentDirectory", Name = "GetContentDirectory_2")]
|
|
||||||
[HttpGet("{serverId}/ContentDirectory/ContentDirectory.xml", Name = "GetContentDirectory_3")]
|
|
||||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
|
||||||
[ProducesResponseType(StatusCodes.Status503ServiceUnavailable)]
|
|
||||||
[Produces(MediaTypeNames.Text.Xml)]
|
|
||||||
[ProducesFile(MediaTypeNames.Text.Xml)]
|
|
||||||
[SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "serverId", Justification = "Required for DLNA")]
|
|
||||||
public ActionResult<string> GetContentDirectory([FromRoute, Required] string serverId)
|
|
||||||
{
|
|
||||||
return Ok(_contentDirectory.GetServiceXml());
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets Dlna media receiver registrar xml.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="serverId">Server UUID.</param>
|
|
||||||
/// <response code="200">Dlna media receiver registrar xml returned.</response>
|
|
||||||
/// <response code="503">DLNA is disabled.</response>
|
|
||||||
/// <returns>Dlna media receiver registrar xml.</returns>
|
|
||||||
[HttpGet("{serverId}/MediaReceiverRegistrar")]
|
|
||||||
[HttpGet("{serverId}/MediaReceiverRegistrar/MediaReceiverRegistrar", Name = "GetMediaReceiverRegistrar_2")]
|
|
||||||
[HttpGet("{serverId}/MediaReceiverRegistrar/MediaReceiverRegistrar.xml", Name = "GetMediaReceiverRegistrar_3")]
|
|
||||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
|
||||||
[ProducesResponseType(StatusCodes.Status503ServiceUnavailable)]
|
|
||||||
[Produces(MediaTypeNames.Text.Xml)]
|
|
||||||
[ProducesFile(MediaTypeNames.Text.Xml)]
|
|
||||||
[SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "serverId", Justification = "Required for DLNA")]
|
|
||||||
public ActionResult<string> GetMediaReceiverRegistrar([FromRoute, Required] string serverId)
|
|
||||||
{
|
|
||||||
return Ok(_mediaReceiverRegistrar.GetServiceXml());
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets Dlna media receiver registrar xml.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="serverId">Server UUID.</param>
|
|
||||||
/// <response code="200">Dlna media receiver registrar xml returned.</response>
|
|
||||||
/// <response code="503">DLNA is disabled.</response>
|
|
||||||
/// <returns>Dlna media receiver registrar xml.</returns>
|
|
||||||
[HttpGet("{serverId}/ConnectionManager")]
|
|
||||||
[HttpGet("{serverId}/ConnectionManager/ConnectionManager", Name = "GetConnectionManager_2")]
|
|
||||||
[HttpGet("{serverId}/ConnectionManager/ConnectionManager.xml", Name = "GetConnectionManager_3")]
|
|
||||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
|
||||||
[ProducesResponseType(StatusCodes.Status503ServiceUnavailable)]
|
|
||||||
[Produces(MediaTypeNames.Text.Xml)]
|
|
||||||
[ProducesFile(MediaTypeNames.Text.Xml)]
|
|
||||||
[SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "serverId", Justification = "Required for DLNA")]
|
|
||||||
public ActionResult<string> GetConnectionManager([FromRoute, Required] string serverId)
|
|
||||||
{
|
|
||||||
return Ok(_connectionManager.GetServiceXml());
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Process a content directory control request.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="serverId">Server UUID.</param>
|
|
||||||
/// <response code="200">Request processed.</response>
|
|
||||||
/// <response code="503">DLNA is disabled.</response>
|
|
||||||
/// <returns>Control response.</returns>
|
|
||||||
[HttpPost("{serverId}/ContentDirectory/Control")]
|
|
||||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
|
||||||
[ProducesResponseType(StatusCodes.Status503ServiceUnavailable)]
|
|
||||||
[Produces(MediaTypeNames.Text.Xml)]
|
|
||||||
[ProducesFile(MediaTypeNames.Text.Xml)]
|
|
||||||
public async Task<ActionResult<ControlResponse>> ProcessContentDirectoryControlRequest([FromRoute, Required] string serverId)
|
|
||||||
{
|
|
||||||
return await ProcessControlRequestInternalAsync(serverId, Request.Body, _contentDirectory).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Process a connection manager control request.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="serverId">Server UUID.</param>
|
|
||||||
/// <response code="200">Request processed.</response>
|
|
||||||
/// <response code="503">DLNA is disabled.</response>
|
|
||||||
/// <returns>Control response.</returns>
|
|
||||||
[HttpPost("{serverId}/ConnectionManager/Control")]
|
|
||||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
|
||||||
[ProducesResponseType(StatusCodes.Status503ServiceUnavailable)]
|
|
||||||
[Produces(MediaTypeNames.Text.Xml)]
|
|
||||||
[ProducesFile(MediaTypeNames.Text.Xml)]
|
|
||||||
public async Task<ActionResult<ControlResponse>> ProcessConnectionManagerControlRequest([FromRoute, Required] string serverId)
|
|
||||||
{
|
|
||||||
return await ProcessControlRequestInternalAsync(serverId, Request.Body, _connectionManager).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Process a media receiver registrar control request.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="serverId">Server UUID.</param>
|
|
||||||
/// <response code="200">Request processed.</response>
|
|
||||||
/// <response code="503">DLNA is disabled.</response>
|
|
||||||
/// <returns>Control response.</returns>
|
|
||||||
[HttpPost("{serverId}/MediaReceiverRegistrar/Control")]
|
|
||||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
|
||||||
[ProducesResponseType(StatusCodes.Status503ServiceUnavailable)]
|
|
||||||
[Produces(MediaTypeNames.Text.Xml)]
|
|
||||||
[ProducesFile(MediaTypeNames.Text.Xml)]
|
|
||||||
public async Task<ActionResult<ControlResponse>> ProcessMediaReceiverRegistrarControlRequest([FromRoute, Required] string serverId)
|
|
||||||
{
|
|
||||||
return await ProcessControlRequestInternalAsync(serverId, Request.Body, _mediaReceiverRegistrar).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Processes an event subscription request.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="serverId">Server UUID.</param>
|
|
||||||
/// <response code="200">Request processed.</response>
|
|
||||||
/// <response code="503">DLNA is disabled.</response>
|
|
||||||
/// <returns>Event subscription response.</returns>
|
|
||||||
[HttpSubscribe("{serverId}/MediaReceiverRegistrar/Events")]
|
|
||||||
[HttpUnsubscribe("{serverId}/MediaReceiverRegistrar/Events")]
|
|
||||||
[ApiExplorerSettings(IgnoreApi = true)] // Ignore in openapi docs
|
|
||||||
[SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "serverId", Justification = "Required for DLNA")]
|
|
||||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
|
||||||
[ProducesResponseType(StatusCodes.Status503ServiceUnavailable)]
|
|
||||||
[Produces(MediaTypeNames.Text.Xml)]
|
|
||||||
[ProducesFile(MediaTypeNames.Text.Xml)]
|
|
||||||
public ActionResult<EventSubscriptionResponse> ProcessMediaReceiverRegistrarEventRequest(string serverId)
|
|
||||||
{
|
|
||||||
return ProcessEventRequest(_mediaReceiverRegistrar);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Processes an event subscription request.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="serverId">Server UUID.</param>
|
|
||||||
/// <response code="200">Request processed.</response>
|
|
||||||
/// <response code="503">DLNA is disabled.</response>
|
|
||||||
/// <returns>Event subscription response.</returns>
|
|
||||||
[HttpSubscribe("{serverId}/ContentDirectory/Events")]
|
|
||||||
[HttpUnsubscribe("{serverId}/ContentDirectory/Events")]
|
|
||||||
[ApiExplorerSettings(IgnoreApi = true)] // Ignore in openapi docs
|
|
||||||
[SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "serverId", Justification = "Required for DLNA")]
|
|
||||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
|
||||||
[ProducesResponseType(StatusCodes.Status503ServiceUnavailable)]
|
|
||||||
[Produces(MediaTypeNames.Text.Xml)]
|
|
||||||
[ProducesFile(MediaTypeNames.Text.Xml)]
|
|
||||||
public ActionResult<EventSubscriptionResponse> ProcessContentDirectoryEventRequest(string serverId)
|
|
||||||
{
|
|
||||||
return ProcessEventRequest(_contentDirectory);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Processes an event subscription request.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="serverId">Server UUID.</param>
|
|
||||||
/// <response code="200">Request processed.</response>
|
|
||||||
/// <response code="503">DLNA is disabled.</response>
|
|
||||||
/// <returns>Event subscription response.</returns>
|
|
||||||
[HttpSubscribe("{serverId}/ConnectionManager/Events")]
|
|
||||||
[HttpUnsubscribe("{serverId}/ConnectionManager/Events")]
|
|
||||||
[ApiExplorerSettings(IgnoreApi = true)] // Ignore in openapi docs
|
|
||||||
[SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "serverId", Justification = "Required for DLNA")]
|
|
||||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
|
||||||
[ProducesResponseType(StatusCodes.Status503ServiceUnavailable)]
|
|
||||||
[Produces(MediaTypeNames.Text.Xml)]
|
|
||||||
[ProducesFile(MediaTypeNames.Text.Xml)]
|
|
||||||
public ActionResult<EventSubscriptionResponse> ProcessConnectionManagerEventRequest(string serverId)
|
|
||||||
{
|
|
||||||
return ProcessEventRequest(_connectionManager);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a server icon.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="serverId">Server UUID.</param>
|
|
||||||
/// <param name="fileName">The icon filename.</param>
|
|
||||||
/// <response code="200">Request processed.</response>
|
|
||||||
/// <response code="404">Not Found.</response>
|
|
||||||
/// <response code="503">DLNA is disabled.</response>
|
|
||||||
/// <returns>Icon stream.</returns>
|
|
||||||
[HttpGet("{serverId}/icons/{fileName}")]
|
|
||||||
[SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "serverId", Justification = "Required for DLNA")]
|
|
||||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
|
||||||
[ProducesResponseType(StatusCodes.Status503ServiceUnavailable)]
|
|
||||||
[ProducesImageFile]
|
|
||||||
public ActionResult GetIconId([FromRoute, Required] string serverId, [FromRoute, Required] string fileName)
|
|
||||||
{
|
|
||||||
return GetIconInternal(fileName);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a server icon.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="fileName">The icon filename.</param>
|
|
||||||
/// <returns>Icon stream.</returns>
|
|
||||||
/// <response code="200">Request processed.</response>
|
|
||||||
/// <response code="404">Not Found.</response>
|
|
||||||
/// <response code="503">DLNA is disabled.</response>
|
|
||||||
[HttpGet("icons/{fileName}")]
|
|
||||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
|
||||||
[ProducesResponseType(StatusCodes.Status503ServiceUnavailable)]
|
|
||||||
[ProducesImageFile]
|
|
||||||
public ActionResult GetIcon([FromRoute, Required] string fileName)
|
|
||||||
{
|
|
||||||
return GetIconInternal(fileName);
|
|
||||||
}
|
|
||||||
|
|
||||||
private ActionResult GetIconInternal(string fileName)
|
|
||||||
{
|
|
||||||
var icon = _dlnaManager.GetIcon(fileName);
|
|
||||||
if (icon is null)
|
|
||||||
{
|
|
||||||
return NotFound();
|
|
||||||
}
|
|
||||||
|
|
||||||
return File(icon.Stream, MimeTypes.GetMimeType(fileName));
|
|
||||||
}
|
|
||||||
|
|
||||||
private string GetAbsoluteUri()
|
|
||||||
{
|
|
||||||
return $"{Request.Scheme}://{Request.Host}{Request.PathBase}{Request.Path}";
|
|
||||||
}
|
|
||||||
|
|
||||||
private Task<ControlResponse> ProcessControlRequestInternalAsync(string id, Stream requestStream, IUpnpService service)
|
|
||||||
{
|
|
||||||
return service.ProcessControlRequestAsync(new ControlRequest(Request.Headers)
|
|
||||||
{
|
|
||||||
InputXml = requestStream,
|
|
||||||
TargetServerUuId = id,
|
|
||||||
RequestedUrl = GetAbsoluteUri()
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private EventSubscriptionResponse ProcessEventRequest(IDlnaEventManager dlnaEventManager)
|
|
||||||
{
|
|
||||||
var subscriptionId = Request.Headers["SID"];
|
|
||||||
if (string.Equals(Request.Method, "subscribe", StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
var notificationType = Request.Headers["NT"];
|
|
||||||
var callback = Request.Headers["CALLBACK"];
|
|
||||||
var timeoutString = Request.Headers["TIMEOUT"];
|
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(notificationType))
|
|
||||||
{
|
|
||||||
return dlnaEventManager.RenewEventSubscription(
|
|
||||||
subscriptionId,
|
|
||||||
notificationType,
|
|
||||||
timeoutString,
|
|
||||||
callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
return dlnaEventManager.CreateEventSubscription(notificationType, timeoutString, callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
return dlnaEventManager.CancelEventSubscription(subscriptionId);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -17,8 +17,6 @@ using Jellyfin.Extensions;
|
||||||
using Jellyfin.MediaEncoding.Hls.Playlist;
|
using Jellyfin.MediaEncoding.Hls.Playlist;
|
||||||
using MediaBrowser.Common.Configuration;
|
using MediaBrowser.Common.Configuration;
|
||||||
using MediaBrowser.Controller.Configuration;
|
using MediaBrowser.Controller.Configuration;
|
||||||
using MediaBrowser.Controller.Devices;
|
|
||||||
using MediaBrowser.Controller.Dlna;
|
|
||||||
using MediaBrowser.Controller.Library;
|
using MediaBrowser.Controller.Library;
|
||||||
using MediaBrowser.Controller.MediaEncoding;
|
using MediaBrowser.Controller.MediaEncoding;
|
||||||
using MediaBrowser.MediaEncoding.Encoder;
|
using MediaBrowser.MediaEncoding.Encoder;
|
||||||
|
@ -49,12 +47,10 @@ public class DynamicHlsController : BaseJellyfinApiController
|
||||||
|
|
||||||
private readonly ILibraryManager _libraryManager;
|
private readonly ILibraryManager _libraryManager;
|
||||||
private readonly IUserManager _userManager;
|
private readonly IUserManager _userManager;
|
||||||
private readonly IDlnaManager _dlnaManager;
|
|
||||||
private readonly IMediaSourceManager _mediaSourceManager;
|
private readonly IMediaSourceManager _mediaSourceManager;
|
||||||
private readonly IServerConfigurationManager _serverConfigurationManager;
|
private readonly IServerConfigurationManager _serverConfigurationManager;
|
||||||
private readonly IMediaEncoder _mediaEncoder;
|
private readonly IMediaEncoder _mediaEncoder;
|
||||||
private readonly IFileSystem _fileSystem;
|
private readonly IFileSystem _fileSystem;
|
||||||
private readonly IDeviceManager _deviceManager;
|
|
||||||
private readonly TranscodingJobHelper _transcodingJobHelper;
|
private readonly TranscodingJobHelper _transcodingJobHelper;
|
||||||
private readonly ILogger<DynamicHlsController> _logger;
|
private readonly ILogger<DynamicHlsController> _logger;
|
||||||
private readonly EncodingHelper _encodingHelper;
|
private readonly EncodingHelper _encodingHelper;
|
||||||
|
@ -67,12 +63,10 @@ public class DynamicHlsController : BaseJellyfinApiController
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="libraryManager">Instance of the <see cref="ILibraryManager"/> interface.</param>
|
/// <param name="libraryManager">Instance of the <see cref="ILibraryManager"/> interface.</param>
|
||||||
/// <param name="userManager">Instance of the <see cref="IUserManager"/> interface.</param>
|
/// <param name="userManager">Instance of the <see cref="IUserManager"/> interface.</param>
|
||||||
/// <param name="dlnaManager">Instance of the <see cref="IDlnaManager"/> interface.</param>
|
|
||||||
/// <param name="mediaSourceManager">Instance of the <see cref="IMediaSourceManager"/> interface.</param>
|
/// <param name="mediaSourceManager">Instance of the <see cref="IMediaSourceManager"/> interface.</param>
|
||||||
/// <param name="serverConfigurationManager">Instance of the <see cref="IServerConfigurationManager"/> interface.</param>
|
/// <param name="serverConfigurationManager">Instance of the <see cref="IServerConfigurationManager"/> interface.</param>
|
||||||
/// <param name="mediaEncoder">Instance of the <see cref="IMediaEncoder"/> interface.</param>
|
/// <param name="mediaEncoder">Instance of the <see cref="IMediaEncoder"/> interface.</param>
|
||||||
/// <param name="fileSystem">Instance of the <see cref="IFileSystem"/> interface.</param>
|
/// <param name="fileSystem">Instance of the <see cref="IFileSystem"/> interface.</param>
|
||||||
/// <param name="deviceManager">Instance of the <see cref="IDeviceManager"/> interface.</param>
|
|
||||||
/// <param name="transcodingJobHelper">Instance of the <see cref="TranscodingJobHelper"/> class.</param>
|
/// <param name="transcodingJobHelper">Instance of the <see cref="TranscodingJobHelper"/> class.</param>
|
||||||
/// <param name="logger">Instance of the <see cref="ILogger{DynamicHlsController}"/> interface.</param>
|
/// <param name="logger">Instance of the <see cref="ILogger{DynamicHlsController}"/> interface.</param>
|
||||||
/// <param name="dynamicHlsHelper">Instance of <see cref="DynamicHlsHelper"/>.</param>
|
/// <param name="dynamicHlsHelper">Instance of <see cref="DynamicHlsHelper"/>.</param>
|
||||||
|
@ -81,12 +75,10 @@ public class DynamicHlsController : BaseJellyfinApiController
|
||||||
public DynamicHlsController(
|
public DynamicHlsController(
|
||||||
ILibraryManager libraryManager,
|
ILibraryManager libraryManager,
|
||||||
IUserManager userManager,
|
IUserManager userManager,
|
||||||
IDlnaManager dlnaManager,
|
|
||||||
IMediaSourceManager mediaSourceManager,
|
IMediaSourceManager mediaSourceManager,
|
||||||
IServerConfigurationManager serverConfigurationManager,
|
IServerConfigurationManager serverConfigurationManager,
|
||||||
IMediaEncoder mediaEncoder,
|
IMediaEncoder mediaEncoder,
|
||||||
IFileSystem fileSystem,
|
IFileSystem fileSystem,
|
||||||
IDeviceManager deviceManager,
|
|
||||||
TranscodingJobHelper transcodingJobHelper,
|
TranscodingJobHelper transcodingJobHelper,
|
||||||
ILogger<DynamicHlsController> logger,
|
ILogger<DynamicHlsController> logger,
|
||||||
DynamicHlsHelper dynamicHlsHelper,
|
DynamicHlsHelper dynamicHlsHelper,
|
||||||
|
@ -95,12 +87,10 @@ public class DynamicHlsController : BaseJellyfinApiController
|
||||||
{
|
{
|
||||||
_libraryManager = libraryManager;
|
_libraryManager = libraryManager;
|
||||||
_userManager = userManager;
|
_userManager = userManager;
|
||||||
_dlnaManager = dlnaManager;
|
|
||||||
_mediaSourceManager = mediaSourceManager;
|
_mediaSourceManager = mediaSourceManager;
|
||||||
_serverConfigurationManager = serverConfigurationManager;
|
_serverConfigurationManager = serverConfigurationManager;
|
||||||
_mediaEncoder = mediaEncoder;
|
_mediaEncoder = mediaEncoder;
|
||||||
_fileSystem = fileSystem;
|
_fileSystem = fileSystem;
|
||||||
_deviceManager = deviceManager;
|
|
||||||
_transcodingJobHelper = transcodingJobHelper;
|
_transcodingJobHelper = transcodingJobHelper;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_dynamicHlsHelper = dynamicHlsHelper;
|
_dynamicHlsHelper = dynamicHlsHelper;
|
||||||
|
@ -176,7 +166,7 @@ public class DynamicHlsController : BaseJellyfinApiController
|
||||||
[FromQuery] bool? @static,
|
[FromQuery] bool? @static,
|
||||||
[FromQuery] string? @params,
|
[FromQuery] string? @params,
|
||||||
[FromQuery] string? tag,
|
[FromQuery] string? tag,
|
||||||
[FromQuery] string? deviceProfileId,
|
[FromQuery, ParameterObsolete] string? deviceProfileId,
|
||||||
[FromQuery] string? playSessionId,
|
[FromQuery] string? playSessionId,
|
||||||
[FromQuery] string? segmentContainer,
|
[FromQuery] string? segmentContainer,
|
||||||
[FromQuery] int? segmentLength,
|
[FromQuery] int? segmentLength,
|
||||||
|
@ -231,7 +221,6 @@ public class DynamicHlsController : BaseJellyfinApiController
|
||||||
Static = @static ?? false,
|
Static = @static ?? false,
|
||||||
Params = @params,
|
Params = @params,
|
||||||
Tag = tag,
|
Tag = tag,
|
||||||
DeviceProfileId = deviceProfileId,
|
|
||||||
PlaySessionId = playSessionId,
|
PlaySessionId = playSessionId,
|
||||||
SegmentContainer = segmentContainer,
|
SegmentContainer = segmentContainer,
|
||||||
SegmentLength = segmentLength,
|
SegmentLength = segmentLength,
|
||||||
|
@ -294,8 +283,6 @@ public class DynamicHlsController : BaseJellyfinApiController
|
||||||
_serverConfigurationManager,
|
_serverConfigurationManager,
|
||||||
_mediaEncoder,
|
_mediaEncoder,
|
||||||
_encodingHelper,
|
_encodingHelper,
|
||||||
_dlnaManager,
|
|
||||||
_deviceManager,
|
|
||||||
_transcodingJobHelper,
|
_transcodingJobHelper,
|
||||||
TranscodingJobType,
|
TranscodingJobType,
|
||||||
cancellationToken)
|
cancellationToken)
|
||||||
|
@ -422,7 +409,7 @@ public class DynamicHlsController : BaseJellyfinApiController
|
||||||
[FromQuery] bool? @static,
|
[FromQuery] bool? @static,
|
||||||
[FromQuery] string? @params,
|
[FromQuery] string? @params,
|
||||||
[FromQuery] string? tag,
|
[FromQuery] string? tag,
|
||||||
[FromQuery] string? deviceProfileId,
|
[FromQuery, ParameterObsolete] string? deviceProfileId,
|
||||||
[FromQuery] string? playSessionId,
|
[FromQuery] string? playSessionId,
|
||||||
[FromQuery] string? segmentContainer,
|
[FromQuery] string? segmentContainer,
|
||||||
[FromQuery] int? segmentLength,
|
[FromQuery] int? segmentLength,
|
||||||
|
@ -477,7 +464,6 @@ public class DynamicHlsController : BaseJellyfinApiController
|
||||||
Static = @static ?? false,
|
Static = @static ?? false,
|
||||||
Params = @params,
|
Params = @params,
|
||||||
Tag = tag,
|
Tag = tag,
|
||||||
DeviceProfileId = deviceProfileId,
|
|
||||||
PlaySessionId = playSessionId,
|
PlaySessionId = playSessionId,
|
||||||
SegmentContainer = segmentContainer,
|
SegmentContainer = segmentContainer,
|
||||||
SegmentLength = segmentLength,
|
SegmentLength = segmentLength,
|
||||||
|
@ -594,7 +580,7 @@ public class DynamicHlsController : BaseJellyfinApiController
|
||||||
[FromQuery] bool? @static,
|
[FromQuery] bool? @static,
|
||||||
[FromQuery] string? @params,
|
[FromQuery] string? @params,
|
||||||
[FromQuery] string? tag,
|
[FromQuery] string? tag,
|
||||||
[FromQuery] string? deviceProfileId,
|
[FromQuery, ParameterObsolete] string? deviceProfileId,
|
||||||
[FromQuery] string? playSessionId,
|
[FromQuery] string? playSessionId,
|
||||||
[FromQuery] string? segmentContainer,
|
[FromQuery] string? segmentContainer,
|
||||||
[FromQuery] int? segmentLength,
|
[FromQuery] int? segmentLength,
|
||||||
|
@ -647,7 +633,6 @@ public class DynamicHlsController : BaseJellyfinApiController
|
||||||
Static = @static ?? false,
|
Static = @static ?? false,
|
||||||
Params = @params,
|
Params = @params,
|
||||||
Tag = tag,
|
Tag = tag,
|
||||||
DeviceProfileId = deviceProfileId,
|
|
||||||
PlaySessionId = playSessionId,
|
PlaySessionId = playSessionId,
|
||||||
SegmentContainer = segmentContainer,
|
SegmentContainer = segmentContainer,
|
||||||
SegmentLength = segmentLength,
|
SegmentLength = segmentLength,
|
||||||
|
@ -760,7 +745,7 @@ public class DynamicHlsController : BaseJellyfinApiController
|
||||||
[FromQuery] bool? @static,
|
[FromQuery] bool? @static,
|
||||||
[FromQuery] string? @params,
|
[FromQuery] string? @params,
|
||||||
[FromQuery] string? tag,
|
[FromQuery] string? tag,
|
||||||
[FromQuery] string? deviceProfileId,
|
[FromQuery, ParameterObsolete] string? deviceProfileId,
|
||||||
[FromQuery] string? playSessionId,
|
[FromQuery] string? playSessionId,
|
||||||
[FromQuery] string? segmentContainer,
|
[FromQuery] string? segmentContainer,
|
||||||
[FromQuery] int? segmentLength,
|
[FromQuery] int? segmentLength,
|
||||||
|
@ -814,7 +799,6 @@ public class DynamicHlsController : BaseJellyfinApiController
|
||||||
Static = @static ?? false,
|
Static = @static ?? false,
|
||||||
Params = @params,
|
Params = @params,
|
||||||
Tag = tag,
|
Tag = tag,
|
||||||
DeviceProfileId = deviceProfileId,
|
|
||||||
PlaySessionId = playSessionId,
|
PlaySessionId = playSessionId,
|
||||||
SegmentContainer = segmentContainer,
|
SegmentContainer = segmentContainer,
|
||||||
SegmentLength = segmentLength,
|
SegmentLength = segmentLength,
|
||||||
|
@ -928,7 +912,7 @@ public class DynamicHlsController : BaseJellyfinApiController
|
||||||
[FromQuery] bool? @static,
|
[FromQuery] bool? @static,
|
||||||
[FromQuery] string? @params,
|
[FromQuery] string? @params,
|
||||||
[FromQuery] string? tag,
|
[FromQuery] string? tag,
|
||||||
[FromQuery] string? deviceProfileId,
|
[FromQuery, ParameterObsolete] string? deviceProfileId,
|
||||||
[FromQuery] string? playSessionId,
|
[FromQuery] string? playSessionId,
|
||||||
[FromQuery] string? segmentContainer,
|
[FromQuery] string? segmentContainer,
|
||||||
[FromQuery] int? segmentLength,
|
[FromQuery] int? segmentLength,
|
||||||
|
@ -981,7 +965,6 @@ public class DynamicHlsController : BaseJellyfinApiController
|
||||||
Static = @static ?? false,
|
Static = @static ?? false,
|
||||||
Params = @params,
|
Params = @params,
|
||||||
Tag = tag,
|
Tag = tag,
|
||||||
DeviceProfileId = deviceProfileId,
|
|
||||||
PlaySessionId = playSessionId,
|
PlaySessionId = playSessionId,
|
||||||
SegmentContainer = segmentContainer,
|
SegmentContainer = segmentContainer,
|
||||||
SegmentLength = segmentLength,
|
SegmentLength = segmentLength,
|
||||||
|
@ -1105,7 +1088,7 @@ public class DynamicHlsController : BaseJellyfinApiController
|
||||||
[FromQuery] bool? @static,
|
[FromQuery] bool? @static,
|
||||||
[FromQuery] string? @params,
|
[FromQuery] string? @params,
|
||||||
[FromQuery] string? tag,
|
[FromQuery] string? tag,
|
||||||
[FromQuery] string? deviceProfileId,
|
[FromQuery, ParameterObsolete] string? deviceProfileId,
|
||||||
[FromQuery] string? playSessionId,
|
[FromQuery] string? playSessionId,
|
||||||
[FromQuery] string? segmentContainer,
|
[FromQuery] string? segmentContainer,
|
||||||
[FromQuery] int? segmentLength,
|
[FromQuery] int? segmentLength,
|
||||||
|
@ -1161,7 +1144,6 @@ public class DynamicHlsController : BaseJellyfinApiController
|
||||||
Static = @static ?? false,
|
Static = @static ?? false,
|
||||||
Params = @params,
|
Params = @params,
|
||||||
Tag = tag,
|
Tag = tag,
|
||||||
DeviceProfileId = deviceProfileId,
|
|
||||||
PlaySessionId = playSessionId,
|
PlaySessionId = playSessionId,
|
||||||
SegmentContainer = segmentContainer,
|
SegmentContainer = segmentContainer,
|
||||||
SegmentLength = segmentLength,
|
SegmentLength = segmentLength,
|
||||||
|
@ -1286,7 +1268,7 @@ public class DynamicHlsController : BaseJellyfinApiController
|
||||||
[FromQuery] bool? @static,
|
[FromQuery] bool? @static,
|
||||||
[FromQuery] string? @params,
|
[FromQuery] string? @params,
|
||||||
[FromQuery] string? tag,
|
[FromQuery] string? tag,
|
||||||
[FromQuery] string? deviceProfileId,
|
[FromQuery, ParameterObsolete] string? deviceProfileId,
|
||||||
[FromQuery] string? playSessionId,
|
[FromQuery] string? playSessionId,
|
||||||
[FromQuery] string? segmentContainer,
|
[FromQuery] string? segmentContainer,
|
||||||
[FromQuery] int? segmentLength,
|
[FromQuery] int? segmentLength,
|
||||||
|
@ -1341,7 +1323,6 @@ public class DynamicHlsController : BaseJellyfinApiController
|
||||||
Static = @static ?? false,
|
Static = @static ?? false,
|
||||||
Params = @params,
|
Params = @params,
|
||||||
Tag = tag,
|
Tag = tag,
|
||||||
DeviceProfileId = deviceProfileId,
|
|
||||||
PlaySessionId = playSessionId,
|
PlaySessionId = playSessionId,
|
||||||
SegmentContainer = segmentContainer,
|
SegmentContainer = segmentContainer,
|
||||||
SegmentLength = segmentLength,
|
SegmentLength = segmentLength,
|
||||||
|
@ -1402,8 +1383,6 @@ public class DynamicHlsController : BaseJellyfinApiController
|
||||||
_serverConfigurationManager,
|
_serverConfigurationManager,
|
||||||
_mediaEncoder,
|
_mediaEncoder,
|
||||||
_encodingHelper,
|
_encodingHelper,
|
||||||
_dlnaManager,
|
|
||||||
_deviceManager,
|
|
||||||
_transcodingJobHelper,
|
_transcodingJobHelper,
|
||||||
TranscodingJobType,
|
TranscodingJobType,
|
||||||
cancellationTokenSource.Token)
|
cancellationTokenSource.Token)
|
||||||
|
@ -1442,8 +1421,6 @@ public class DynamicHlsController : BaseJellyfinApiController
|
||||||
_serverConfigurationManager,
|
_serverConfigurationManager,
|
||||||
_mediaEncoder,
|
_mediaEncoder,
|
||||||
_encodingHelper,
|
_encodingHelper,
|
||||||
_dlnaManager,
|
|
||||||
_deviceManager,
|
|
||||||
_transcodingJobHelper,
|
_transcodingJobHelper,
|
||||||
TranscodingJobType,
|
TranscodingJobType,
|
||||||
cancellationToken)
|
cancellationToken)
|
||||||
|
|
|
@ -16,8 +16,6 @@ using MediaBrowser.Common.Api;
|
||||||
using MediaBrowser.Common.Configuration;
|
using MediaBrowser.Common.Configuration;
|
||||||
using MediaBrowser.Common.Net;
|
using MediaBrowser.Common.Net;
|
||||||
using MediaBrowser.Controller.Configuration;
|
using MediaBrowser.Controller.Configuration;
|
||||||
using MediaBrowser.Controller.Devices;
|
|
||||||
using MediaBrowser.Controller.Dlna;
|
|
||||||
using MediaBrowser.Controller.Dto;
|
using MediaBrowser.Controller.Dto;
|
||||||
using MediaBrowser.Controller.Entities;
|
using MediaBrowser.Controller.Entities;
|
||||||
using MediaBrowser.Controller.Library;
|
using MediaBrowser.Controller.Library;
|
||||||
|
@ -42,11 +40,9 @@ public class VideosController : BaseJellyfinApiController
|
||||||
private readonly ILibraryManager _libraryManager;
|
private readonly ILibraryManager _libraryManager;
|
||||||
private readonly IUserManager _userManager;
|
private readonly IUserManager _userManager;
|
||||||
private readonly IDtoService _dtoService;
|
private readonly IDtoService _dtoService;
|
||||||
private readonly IDlnaManager _dlnaManager;
|
|
||||||
private readonly IMediaSourceManager _mediaSourceManager;
|
private readonly IMediaSourceManager _mediaSourceManager;
|
||||||
private readonly IServerConfigurationManager _serverConfigurationManager;
|
private readonly IServerConfigurationManager _serverConfigurationManager;
|
||||||
private readonly IMediaEncoder _mediaEncoder;
|
private readonly IMediaEncoder _mediaEncoder;
|
||||||
private readonly IDeviceManager _deviceManager;
|
|
||||||
private readonly TranscodingJobHelper _transcodingJobHelper;
|
private readonly TranscodingJobHelper _transcodingJobHelper;
|
||||||
private readonly IHttpClientFactory _httpClientFactory;
|
private readonly IHttpClientFactory _httpClientFactory;
|
||||||
private readonly EncodingHelper _encodingHelper;
|
private readonly EncodingHelper _encodingHelper;
|
||||||
|
@ -59,11 +55,9 @@ public class VideosController : BaseJellyfinApiController
|
||||||
/// <param name="libraryManager">Instance of the <see cref="ILibraryManager"/> interface.</param>
|
/// <param name="libraryManager">Instance of the <see cref="ILibraryManager"/> interface.</param>
|
||||||
/// <param name="userManager">Instance of the <see cref="IUserManager"/> interface.</param>
|
/// <param name="userManager">Instance of the <see cref="IUserManager"/> interface.</param>
|
||||||
/// <param name="dtoService">Instance of the <see cref="IDtoService"/> interface.</param>
|
/// <param name="dtoService">Instance of the <see cref="IDtoService"/> interface.</param>
|
||||||
/// <param name="dlnaManager">Instance of the <see cref="IDlnaManager"/> interface.</param>
|
|
||||||
/// <param name="mediaSourceManager">Instance of the <see cref="IMediaSourceManager"/> interface.</param>
|
/// <param name="mediaSourceManager">Instance of the <see cref="IMediaSourceManager"/> interface.</param>
|
||||||
/// <param name="serverConfigurationManager">Instance of the <see cref="IServerConfigurationManager"/> interface.</param>
|
/// <param name="serverConfigurationManager">Instance of the <see cref="IServerConfigurationManager"/> interface.</param>
|
||||||
/// <param name="mediaEncoder">Instance of the <see cref="IMediaEncoder"/> interface.</param>
|
/// <param name="mediaEncoder">Instance of the <see cref="IMediaEncoder"/> interface.</param>
|
||||||
/// <param name="deviceManager">Instance of the <see cref="IDeviceManager"/> interface.</param>
|
|
||||||
/// <param name="transcodingJobHelper">Instance of the <see cref="TranscodingJobHelper"/> class.</param>
|
/// <param name="transcodingJobHelper">Instance of the <see cref="TranscodingJobHelper"/> class.</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="encodingHelper">Instance of <see cref="EncodingHelper"/>.</param>
|
/// <param name="encodingHelper">Instance of <see cref="EncodingHelper"/>.</param>
|
||||||
|
@ -71,11 +65,9 @@ public class VideosController : BaseJellyfinApiController
|
||||||
ILibraryManager libraryManager,
|
ILibraryManager libraryManager,
|
||||||
IUserManager userManager,
|
IUserManager userManager,
|
||||||
IDtoService dtoService,
|
IDtoService dtoService,
|
||||||
IDlnaManager dlnaManager,
|
|
||||||
IMediaSourceManager mediaSourceManager,
|
IMediaSourceManager mediaSourceManager,
|
||||||
IServerConfigurationManager serverConfigurationManager,
|
IServerConfigurationManager serverConfigurationManager,
|
||||||
IMediaEncoder mediaEncoder,
|
IMediaEncoder mediaEncoder,
|
||||||
IDeviceManager deviceManager,
|
|
||||||
TranscodingJobHelper transcodingJobHelper,
|
TranscodingJobHelper transcodingJobHelper,
|
||||||
IHttpClientFactory httpClientFactory,
|
IHttpClientFactory httpClientFactory,
|
||||||
EncodingHelper encodingHelper)
|
EncodingHelper encodingHelper)
|
||||||
|
@ -83,11 +75,9 @@ public class VideosController : BaseJellyfinApiController
|
||||||
_libraryManager = libraryManager;
|
_libraryManager = libraryManager;
|
||||||
_userManager = userManager;
|
_userManager = userManager;
|
||||||
_dtoService = dtoService;
|
_dtoService = dtoService;
|
||||||
_dlnaManager = dlnaManager;
|
|
||||||
_mediaSourceManager = mediaSourceManager;
|
_mediaSourceManager = mediaSourceManager;
|
||||||
_serverConfigurationManager = serverConfigurationManager;
|
_serverConfigurationManager = serverConfigurationManager;
|
||||||
_mediaEncoder = mediaEncoder;
|
_mediaEncoder = mediaEncoder;
|
||||||
_deviceManager = deviceManager;
|
|
||||||
_transcodingJobHelper = transcodingJobHelper;
|
_transcodingJobHelper = transcodingJobHelper;
|
||||||
_httpClientFactory = httpClientFactory;
|
_httpClientFactory = httpClientFactory;
|
||||||
_encodingHelper = encodingHelper;
|
_encodingHelper = encodingHelper;
|
||||||
|
@ -324,7 +314,7 @@ public class VideosController : BaseJellyfinApiController
|
||||||
[FromQuery] bool? @static,
|
[FromQuery] bool? @static,
|
||||||
[FromQuery] string? @params,
|
[FromQuery] string? @params,
|
||||||
[FromQuery] string? tag,
|
[FromQuery] string? tag,
|
||||||
[FromQuery] string? deviceProfileId,
|
[FromQuery, ParameterObsolete] string? deviceProfileId,
|
||||||
[FromQuery] string? playSessionId,
|
[FromQuery] string? playSessionId,
|
||||||
[FromQuery] string? segmentContainer,
|
[FromQuery] string? segmentContainer,
|
||||||
[FromQuery] int? segmentLength,
|
[FromQuery] int? segmentLength,
|
||||||
|
@ -381,7 +371,6 @@ public class VideosController : BaseJellyfinApiController
|
||||||
Static = @static ?? false,
|
Static = @static ?? false,
|
||||||
Params = @params,
|
Params = @params,
|
||||||
Tag = tag,
|
Tag = tag,
|
||||||
DeviceProfileId = deviceProfileId,
|
|
||||||
PlaySessionId = playSessionId,
|
PlaySessionId = playSessionId,
|
||||||
SegmentContainer = segmentContainer,
|
SegmentContainer = segmentContainer,
|
||||||
SegmentLength = segmentLength,
|
SegmentLength = segmentLength,
|
||||||
|
@ -438,8 +427,6 @@ public class VideosController : BaseJellyfinApiController
|
||||||
_serverConfigurationManager,
|
_serverConfigurationManager,
|
||||||
_mediaEncoder,
|
_mediaEncoder,
|
||||||
_encodingHelper,
|
_encodingHelper,
|
||||||
_dlnaManager,
|
|
||||||
_deviceManager,
|
|
||||||
_transcodingJobHelper,
|
_transcodingJobHelper,
|
||||||
_transcodingJobType,
|
_transcodingJobType,
|
||||||
cancellationTokenSource.Token)
|
cancellationTokenSource.Token)
|
||||||
|
@ -447,8 +434,6 @@ public class VideosController : BaseJellyfinApiController
|
||||||
|
|
||||||
if (@static.HasValue && @static.Value && state.DirectStreamProvider is not null)
|
if (@static.HasValue && @static.Value && state.DirectStreamProvider is not null)
|
||||||
{
|
{
|
||||||
StreamingHelpers.AddDlnaHeaders(state, Response.Headers, true, state.Request.StartTimeTicks, Request, _dlnaManager);
|
|
||||||
|
|
||||||
var liveStreamInfo = _mediaSourceManager.GetLiveStreamInfo(streamingRequest.LiveStreamId);
|
var liveStreamInfo = _mediaSourceManager.GetLiveStreamInfo(streamingRequest.LiveStreamId);
|
||||||
if (liveStreamInfo is null)
|
if (liveStreamInfo is null)
|
||||||
{
|
{
|
||||||
|
@ -463,8 +448,6 @@ public class VideosController : BaseJellyfinApiController
|
||||||
// Static remote stream
|
// Static remote stream
|
||||||
if (@static.HasValue && @static.Value && state.InputProtocol == MediaProtocol.Http)
|
if (@static.HasValue && @static.Value && state.InputProtocol == MediaProtocol.Http)
|
||||||
{
|
{
|
||||||
StreamingHelpers.AddDlnaHeaders(state, Response.Headers, true, state.Request.StartTimeTicks, Request, _dlnaManager);
|
|
||||||
|
|
||||||
var httpClient = _httpClientFactory.CreateClient(NamedClient.Default);
|
var httpClient = _httpClientFactory.CreateClient(NamedClient.Default);
|
||||||
return await FileStreamResponseHelpers.GetStaticRemoteStreamResult(state, httpClient, HttpContext).ConfigureAwait(false);
|
return await FileStreamResponseHelpers.GetStaticRemoteStreamResult(state, httpClient, HttpContext).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
@ -475,12 +458,6 @@ public class VideosController : BaseJellyfinApiController
|
||||||
}
|
}
|
||||||
|
|
||||||
var outputPath = state.OutputFilePath;
|
var outputPath = state.OutputFilePath;
|
||||||
var outputPathExists = System.IO.File.Exists(outputPath);
|
|
||||||
|
|
||||||
var transcodingJob = _transcodingJobHelper.GetTranscodingJob(outputPath, TranscodingJobType.Progressive);
|
|
||||||
var isTranscodeCached = outputPathExists && transcodingJob is not null;
|
|
||||||
|
|
||||||
StreamingHelpers.AddDlnaHeaders(state, Response.Headers, (@static.HasValue && @static.Value) || isTranscodeCached, state.Request.StartTimeTicks, Request, _dlnaManager);
|
|
||||||
|
|
||||||
// Static stream
|
// Static stream
|
||||||
if (@static.HasValue && @static.Value)
|
if (@static.HasValue && @static.Value)
|
||||||
|
|
|
@ -7,8 +7,6 @@ using MediaBrowser.Common.Configuration;
|
||||||
using MediaBrowser.Common.Extensions;
|
using MediaBrowser.Common.Extensions;
|
||||||
using MediaBrowser.Common.Net;
|
using MediaBrowser.Common.Net;
|
||||||
using MediaBrowser.Controller.Configuration;
|
using MediaBrowser.Controller.Configuration;
|
||||||
using MediaBrowser.Controller.Devices;
|
|
||||||
using MediaBrowser.Controller.Dlna;
|
|
||||||
using MediaBrowser.Controller.Library;
|
using MediaBrowser.Controller.Library;
|
||||||
using MediaBrowser.Controller.MediaEncoding;
|
using MediaBrowser.Controller.MediaEncoding;
|
||||||
using MediaBrowser.Model.MediaInfo;
|
using MediaBrowser.Model.MediaInfo;
|
||||||
|
@ -23,13 +21,11 @@ namespace Jellyfin.Api.Helpers;
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class AudioHelper
|
public class AudioHelper
|
||||||
{
|
{
|
||||||
private readonly IDlnaManager _dlnaManager;
|
|
||||||
private readonly IUserManager _userManager;
|
private readonly IUserManager _userManager;
|
||||||
private readonly ILibraryManager _libraryManager;
|
private readonly ILibraryManager _libraryManager;
|
||||||
private readonly IMediaSourceManager _mediaSourceManager;
|
private readonly IMediaSourceManager _mediaSourceManager;
|
||||||
private readonly IServerConfigurationManager _serverConfigurationManager;
|
private readonly IServerConfigurationManager _serverConfigurationManager;
|
||||||
private readonly IMediaEncoder _mediaEncoder;
|
private readonly IMediaEncoder _mediaEncoder;
|
||||||
private readonly IDeviceManager _deviceManager;
|
|
||||||
private readonly TranscodingJobHelper _transcodingJobHelper;
|
private readonly TranscodingJobHelper _transcodingJobHelper;
|
||||||
private readonly IHttpClientFactory _httpClientFactory;
|
private readonly IHttpClientFactory _httpClientFactory;
|
||||||
private readonly IHttpContextAccessor _httpContextAccessor;
|
private readonly IHttpContextAccessor _httpContextAccessor;
|
||||||
|
@ -38,37 +34,31 @@ public class AudioHelper
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="AudioHelper"/> class.
|
/// Initializes a new instance of the <see cref="AudioHelper"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="dlnaManager">Instance of the <see cref="IDlnaManager"/> interface.</param>
|
|
||||||
/// <param name="userManager">Instance of the <see cref="IUserManager"/> interface.</param>
|
/// <param name="userManager">Instance of the <see cref="IUserManager"/> interface.</param>
|
||||||
/// <param name="libraryManager">Instance of the <see cref="ILibraryManager"/> interface.</param>
|
/// <param name="libraryManager">Instance of the <see cref="ILibraryManager"/> interface.</param>
|
||||||
/// <param name="mediaSourceManager">Instance of the <see cref="IMediaSourceManager"/> interface.</param>
|
/// <param name="mediaSourceManager">Instance of the <see cref="IMediaSourceManager"/> interface.</param>
|
||||||
/// <param name="serverConfigurationManager">Instance of the <see cref="IServerConfigurationManager"/> interface.</param>
|
/// <param name="serverConfigurationManager">Instance of the <see cref="IServerConfigurationManager"/> interface.</param>
|
||||||
/// <param name="mediaEncoder">Instance of the <see cref="IMediaEncoder"/> interface.</param>
|
/// <param name="mediaEncoder">Instance of the <see cref="IMediaEncoder"/> 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>
|
/// <param name="httpContextAccessor">Instance of the <see cref="IHttpContextAccessor"/> interface.</param>
|
||||||
/// <param name="encodingHelper">Instance of <see cref="EncodingHelper"/>.</param>
|
/// <param name="encodingHelper">Instance of <see cref="EncodingHelper"/>.</param>
|
||||||
public AudioHelper(
|
public AudioHelper(
|
||||||
IDlnaManager dlnaManager,
|
|
||||||
IUserManager userManager,
|
IUserManager userManager,
|
||||||
ILibraryManager libraryManager,
|
ILibraryManager libraryManager,
|
||||||
IMediaSourceManager mediaSourceManager,
|
IMediaSourceManager mediaSourceManager,
|
||||||
IServerConfigurationManager serverConfigurationManager,
|
IServerConfigurationManager serverConfigurationManager,
|
||||||
IMediaEncoder mediaEncoder,
|
IMediaEncoder mediaEncoder,
|
||||||
IDeviceManager deviceManager,
|
|
||||||
TranscodingJobHelper transcodingJobHelper,
|
TranscodingJobHelper transcodingJobHelper,
|
||||||
IHttpClientFactory httpClientFactory,
|
IHttpClientFactory httpClientFactory,
|
||||||
IHttpContextAccessor httpContextAccessor,
|
IHttpContextAccessor httpContextAccessor,
|
||||||
EncodingHelper encodingHelper)
|
EncodingHelper encodingHelper)
|
||||||
{
|
{
|
||||||
_dlnaManager = dlnaManager;
|
|
||||||
_userManager = userManager;
|
_userManager = userManager;
|
||||||
_libraryManager = libraryManager;
|
_libraryManager = libraryManager;
|
||||||
_mediaSourceManager = mediaSourceManager;
|
_mediaSourceManager = mediaSourceManager;
|
||||||
_serverConfigurationManager = serverConfigurationManager;
|
_serverConfigurationManager = serverConfigurationManager;
|
||||||
_mediaEncoder = mediaEncoder;
|
_mediaEncoder = mediaEncoder;
|
||||||
_deviceManager = deviceManager;
|
|
||||||
_transcodingJobHelper = transcodingJobHelper;
|
_transcodingJobHelper = transcodingJobHelper;
|
||||||
_httpClientFactory = httpClientFactory;
|
_httpClientFactory = httpClientFactory;
|
||||||
_httpContextAccessor = httpContextAccessor;
|
_httpContextAccessor = httpContextAccessor;
|
||||||
|
@ -104,8 +94,6 @@ public class AudioHelper
|
||||||
_serverConfigurationManager,
|
_serverConfigurationManager,
|
||||||
_mediaEncoder,
|
_mediaEncoder,
|
||||||
_encodingHelper,
|
_encodingHelper,
|
||||||
_dlnaManager,
|
|
||||||
_deviceManager,
|
|
||||||
_transcodingJobHelper,
|
_transcodingJobHelper,
|
||||||
transcodingJobType,
|
transcodingJobType,
|
||||||
cancellationTokenSource.Token)
|
cancellationTokenSource.Token)
|
||||||
|
@ -113,8 +101,6 @@ public class AudioHelper
|
||||||
|
|
||||||
if (streamingRequest.Static && state.DirectStreamProvider is not null)
|
if (streamingRequest.Static && state.DirectStreamProvider is not null)
|
||||||
{
|
{
|
||||||
StreamingHelpers.AddDlnaHeaders(state, _httpContextAccessor.HttpContext.Response.Headers, true, streamingRequest.StartTimeTicks, _httpContextAccessor.HttpContext.Request, _dlnaManager);
|
|
||||||
|
|
||||||
var liveStreamInfo = _mediaSourceManager.GetLiveStreamInfo(streamingRequest.LiveStreamId);
|
var liveStreamInfo = _mediaSourceManager.GetLiveStreamInfo(streamingRequest.LiveStreamId);
|
||||||
if (liveStreamInfo is null)
|
if (liveStreamInfo is null)
|
||||||
{
|
{
|
||||||
|
@ -129,8 +115,6 @@ public class AudioHelper
|
||||||
// Static remote stream
|
// Static remote stream
|
||||||
if (streamingRequest.Static && state.InputProtocol == MediaProtocol.Http)
|
if (streamingRequest.Static && state.InputProtocol == MediaProtocol.Http)
|
||||||
{
|
{
|
||||||
StreamingHelpers.AddDlnaHeaders(state, _httpContextAccessor.HttpContext.Response.Headers, true, streamingRequest.StartTimeTicks, _httpContextAccessor.HttpContext.Request, _dlnaManager);
|
|
||||||
|
|
||||||
var httpClient = _httpClientFactory.CreateClient(NamedClient.Default);
|
var httpClient = _httpClientFactory.CreateClient(NamedClient.Default);
|
||||||
return await FileStreamResponseHelpers.GetStaticRemoteStreamResult(state, httpClient, _httpContextAccessor.HttpContext).ConfigureAwait(false);
|
return await FileStreamResponseHelpers.GetStaticRemoteStreamResult(state, httpClient, _httpContextAccessor.HttpContext).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
@ -141,12 +125,6 @@ public class AudioHelper
|
||||||
}
|
}
|
||||||
|
|
||||||
var outputPath = state.OutputFilePath;
|
var outputPath = state.OutputFilePath;
|
||||||
var outputPathExists = File.Exists(outputPath);
|
|
||||||
|
|
||||||
var transcodingJob = _transcodingJobHelper.GetTranscodingJob(outputPath, TranscodingJobType.Progressive);
|
|
||||||
var isTranscodeCached = outputPathExists && transcodingJob is not null;
|
|
||||||
|
|
||||||
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)
|
||||||
|
|
|
@ -16,8 +16,6 @@ using MediaBrowser.Common.Configuration;
|
||||||
using MediaBrowser.Common.Extensions;
|
using MediaBrowser.Common.Extensions;
|
||||||
using MediaBrowser.Common.Net;
|
using MediaBrowser.Common.Net;
|
||||||
using MediaBrowser.Controller.Configuration;
|
using MediaBrowser.Controller.Configuration;
|
||||||
using MediaBrowser.Controller.Devices;
|
|
||||||
using MediaBrowser.Controller.Dlna;
|
|
||||||
using MediaBrowser.Controller.Library;
|
using MediaBrowser.Controller.Library;
|
||||||
using MediaBrowser.Controller.MediaEncoding;
|
using MediaBrowser.Controller.MediaEncoding;
|
||||||
using MediaBrowser.Controller.Trickplay;
|
using MediaBrowser.Controller.Trickplay;
|
||||||
|
@ -38,11 +36,9 @@ public class DynamicHlsHelper
|
||||||
{
|
{
|
||||||
private readonly ILibraryManager _libraryManager;
|
private readonly ILibraryManager _libraryManager;
|
||||||
private readonly IUserManager _userManager;
|
private readonly IUserManager _userManager;
|
||||||
private readonly IDlnaManager _dlnaManager;
|
|
||||||
private readonly IMediaSourceManager _mediaSourceManager;
|
private readonly IMediaSourceManager _mediaSourceManager;
|
||||||
private readonly IServerConfigurationManager _serverConfigurationManager;
|
private readonly IServerConfigurationManager _serverConfigurationManager;
|
||||||
private readonly IMediaEncoder _mediaEncoder;
|
private readonly IMediaEncoder _mediaEncoder;
|
||||||
private readonly IDeviceManager _deviceManager;
|
|
||||||
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;
|
||||||
|
@ -55,11 +51,9 @@ public class DynamicHlsHelper
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="libraryManager">Instance of the <see cref="ILibraryManager"/> interface.</param>
|
/// <param name="libraryManager">Instance of the <see cref="ILibraryManager"/> interface.</param>
|
||||||
/// <param name="userManager">Instance of the <see cref="IUserManager"/> interface.</param>
|
/// <param name="userManager">Instance of the <see cref="IUserManager"/> interface.</param>
|
||||||
/// <param name="dlnaManager">Instance of the <see cref="IDlnaManager"/> interface.</param>
|
|
||||||
/// <param name="mediaSourceManager">Instance of the <see cref="IMediaSourceManager"/> interface.</param>
|
/// <param name="mediaSourceManager">Instance of the <see cref="IMediaSourceManager"/> interface.</param>
|
||||||
/// <param name="serverConfigurationManager">Instance of the <see cref="IServerConfigurationManager"/> interface.</param>
|
/// <param name="serverConfigurationManager">Instance of the <see cref="IServerConfigurationManager"/> interface.</param>
|
||||||
/// <param name="mediaEncoder">Instance of the <see cref="IMediaEncoder"/> interface.</param>
|
/// <param name="mediaEncoder">Instance of the <see cref="IMediaEncoder"/> 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="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>
|
||||||
|
@ -69,11 +63,9 @@ public class DynamicHlsHelper
|
||||||
public DynamicHlsHelper(
|
public DynamicHlsHelper(
|
||||||
ILibraryManager libraryManager,
|
ILibraryManager libraryManager,
|
||||||
IUserManager userManager,
|
IUserManager userManager,
|
||||||
IDlnaManager dlnaManager,
|
|
||||||
IMediaSourceManager mediaSourceManager,
|
IMediaSourceManager mediaSourceManager,
|
||||||
IServerConfigurationManager serverConfigurationManager,
|
IServerConfigurationManager serverConfigurationManager,
|
||||||
IMediaEncoder mediaEncoder,
|
IMediaEncoder mediaEncoder,
|
||||||
IDeviceManager deviceManager,
|
|
||||||
TranscodingJobHelper transcodingJobHelper,
|
TranscodingJobHelper transcodingJobHelper,
|
||||||
INetworkManager networkManager,
|
INetworkManager networkManager,
|
||||||
ILogger<DynamicHlsHelper> logger,
|
ILogger<DynamicHlsHelper> logger,
|
||||||
|
@ -83,11 +75,9 @@ public class DynamicHlsHelper
|
||||||
{
|
{
|
||||||
_libraryManager = libraryManager;
|
_libraryManager = libraryManager;
|
||||||
_userManager = userManager;
|
_userManager = userManager;
|
||||||
_dlnaManager = dlnaManager;
|
|
||||||
_mediaSourceManager = mediaSourceManager;
|
_mediaSourceManager = mediaSourceManager;
|
||||||
_serverConfigurationManager = serverConfigurationManager;
|
_serverConfigurationManager = serverConfigurationManager;
|
||||||
_mediaEncoder = mediaEncoder;
|
_mediaEncoder = mediaEncoder;
|
||||||
_deviceManager = deviceManager;
|
|
||||||
_transcodingJobHelper = transcodingJobHelper;
|
_transcodingJobHelper = transcodingJobHelper;
|
||||||
_networkManager = networkManager;
|
_networkManager = networkManager;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
|
@ -140,8 +130,6 @@ public class DynamicHlsHelper
|
||||||
_serverConfigurationManager,
|
_serverConfigurationManager,
|
||||||
_mediaEncoder,
|
_mediaEncoder,
|
||||||
_encodingHelper,
|
_encodingHelper,
|
||||||
_dlnaManager,
|
|
||||||
_deviceManager,
|
|
||||||
_transcodingJobHelper,
|
_transcodingJobHelper,
|
||||||
transcodingJobType,
|
transcodingJobType,
|
||||||
cancellationTokenSource.Token)
|
cancellationTokenSource.Token)
|
||||||
|
|
|
@ -12,15 +12,12 @@ using Jellyfin.Extensions;
|
||||||
using MediaBrowser.Common.Configuration;
|
using MediaBrowser.Common.Configuration;
|
||||||
using MediaBrowser.Common.Extensions;
|
using MediaBrowser.Common.Extensions;
|
||||||
using MediaBrowser.Controller.Configuration;
|
using MediaBrowser.Controller.Configuration;
|
||||||
using MediaBrowser.Controller.Devices;
|
|
||||||
using MediaBrowser.Controller.Dlna;
|
|
||||||
using MediaBrowser.Controller.Library;
|
using MediaBrowser.Controller.Library;
|
||||||
using MediaBrowser.Controller.MediaEncoding;
|
using MediaBrowser.Controller.MediaEncoding;
|
||||||
using MediaBrowser.Model.Dlna;
|
using MediaBrowser.Model.Dlna;
|
||||||
using MediaBrowser.Model.Dto;
|
using MediaBrowser.Model.Dto;
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.Extensions.Primitives;
|
|
||||||
using Microsoft.Net.Http.Headers;
|
using Microsoft.Net.Http.Headers;
|
||||||
|
|
||||||
namespace Jellyfin.Api.Helpers;
|
namespace Jellyfin.Api.Helpers;
|
||||||
|
@ -41,8 +38,6 @@ public static class StreamingHelpers
|
||||||
/// <param name="serverConfigurationManager">Instance of the <see cref="IServerConfigurationManager"/> interface.</param>
|
/// <param name="serverConfigurationManager">Instance of the <see cref="IServerConfigurationManager"/> interface.</param>
|
||||||
/// <param name="mediaEncoder">Instance of the <see cref="IMediaEncoder"/> interface.</param>
|
/// <param name="mediaEncoder">Instance of the <see cref="IMediaEncoder"/> interface.</param>
|
||||||
/// <param name="encodingHelper">Instance of <see cref="EncodingHelper"/>.</param>
|
/// <param name="encodingHelper">Instance of <see cref="EncodingHelper"/>.</param>
|
||||||
/// <param name="dlnaManager">Instance of the <see cref="IDlnaManager"/> interface.</param>
|
|
||||||
/// <param name="deviceManager">Instance of the <see cref="IDeviceManager"/> interface.</param>
|
|
||||||
/// <param name="transcodingJobHelper">Initialized <see cref="TranscodingJobHelper"/>.</param>
|
/// <param name="transcodingJobHelper">Initialized <see cref="TranscodingJobHelper"/>.</param>
|
||||||
/// <param name="transcodingJobType">The <see cref="TranscodingJobType"/>.</param>
|
/// <param name="transcodingJobType">The <see cref="TranscodingJobType"/>.</param>
|
||||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/>.</param>
|
/// <param name="cancellationToken">The <see cref="CancellationToken"/>.</param>
|
||||||
|
@ -56,21 +51,11 @@ public static class StreamingHelpers
|
||||||
IServerConfigurationManager serverConfigurationManager,
|
IServerConfigurationManager serverConfigurationManager,
|
||||||
IMediaEncoder mediaEncoder,
|
IMediaEncoder mediaEncoder,
|
||||||
EncodingHelper encodingHelper,
|
EncodingHelper encodingHelper,
|
||||||
IDlnaManager dlnaManager,
|
|
||||||
IDeviceManager deviceManager,
|
|
||||||
TranscodingJobHelper transcodingJobHelper,
|
TranscodingJobHelper transcodingJobHelper,
|
||||||
TranscodingJobType transcodingJobType,
|
TranscodingJobType transcodingJobType,
|
||||||
CancellationToken cancellationToken)
|
CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var httpRequest = httpContext.Request;
|
var httpRequest = httpContext.Request;
|
||||||
// Parse the DLNA time seek header
|
|
||||||
if (!streamingRequest.StartTimeTicks.HasValue)
|
|
||||||
{
|
|
||||||
var timeSeek = httpRequest.Headers["TimeSeekRange.dlna.org"];
|
|
||||||
|
|
||||||
streamingRequest.StartTimeTicks = ParseTimeSeekHeader(timeSeek.ToString());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(streamingRequest.Params))
|
if (!string.IsNullOrWhiteSpace(streamingRequest.Params))
|
||||||
{
|
{
|
||||||
ParseParams(streamingRequest);
|
ParseParams(streamingRequest);
|
||||||
|
@ -89,16 +74,11 @@ public static class StreamingHelpers
|
||||||
streamingRequest.AudioCodec = encodingHelper.InferAudioCodec(url);
|
streamingRequest.AudioCodec = encodingHelper.InferAudioCodec(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
var enableDlnaHeaders = !string.IsNullOrWhiteSpace(streamingRequest.Params) ||
|
|
||||||
streamingRequest.StreamOptions.ContainsKey("dlnaheaders") ||
|
|
||||||
string.Equals(httpRequest.Headers["GetContentFeatures.DLNA.ORG"], "1", StringComparison.OrdinalIgnoreCase);
|
|
||||||
|
|
||||||
var state = new StreamState(mediaSourceManager, transcodingJobType, transcodingJobHelper)
|
var state = new StreamState(mediaSourceManager, transcodingJobType, transcodingJobHelper)
|
||||||
{
|
{
|
||||||
Request = streamingRequest,
|
Request = streamingRequest,
|
||||||
RequestedUrl = url,
|
RequestedUrl = url,
|
||||||
UserAgent = httpRequest.Headers[HeaderNames.UserAgent],
|
UserAgent = httpRequest.Headers[HeaderNames.UserAgent]
|
||||||
EnableDlnaHeaders = enableDlnaHeaders
|
|
||||||
};
|
};
|
||||||
|
|
||||||
var userId = httpContext.User.GetUserId();
|
var userId = httpContext.User.GetUserId();
|
||||||
|
@ -243,8 +223,6 @@ public static class StreamingHelpers
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ApplyDeviceProfileSettings(state, dlnaManager, deviceManager, httpRequest, streamingRequest.DeviceProfileId, streamingRequest.Static);
|
|
||||||
|
|
||||||
var ext = string.IsNullOrWhiteSpace(state.OutputContainer)
|
var ext = string.IsNullOrWhiteSpace(state.OutputContainer)
|
||||||
? GetOutputFileExtension(state, mediaSource)
|
? GetOutputFileExtension(state, mediaSource)
|
||||||
: ("." + state.OutputContainer);
|
: ("." + state.OutputContainer);
|
||||||
|
@ -254,123 +232,6 @@ public static class StreamingHelpers
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Adds the dlna headers.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="state">The state.</param>
|
|
||||||
/// <param name="responseHeaders">The response headers.</param>
|
|
||||||
/// <param name="isStaticallyStreamed">if set to <c>true</c> [is statically streamed].</param>
|
|
||||||
/// <param name="startTimeTicks">The start time in ticks.</param>
|
|
||||||
/// <param name="request">The <see cref="HttpRequest"/>.</param>
|
|
||||||
/// <param name="dlnaManager">Instance of the <see cref="IDlnaManager"/> interface.</param>
|
|
||||||
public static void AddDlnaHeaders(
|
|
||||||
StreamState state,
|
|
||||||
IHeaderDictionary responseHeaders,
|
|
||||||
bool isStaticallyStreamed,
|
|
||||||
long? startTimeTicks,
|
|
||||||
HttpRequest request,
|
|
||||||
IDlnaManager dlnaManager)
|
|
||||||
{
|
|
||||||
if (!state.EnableDlnaHeaders)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var profile = state.DeviceProfile;
|
|
||||||
|
|
||||||
StringValues transferMode = request.Headers["transferMode.dlna.org"];
|
|
||||||
responseHeaders.Append("transferMode.dlna.org", string.IsNullOrEmpty(transferMode) ? "Streaming" : transferMode.ToString());
|
|
||||||
responseHeaders.Append("realTimeInfo.dlna.org", "DLNA.ORG_TLAG=*");
|
|
||||||
|
|
||||||
if (state.RunTimeTicks.HasValue)
|
|
||||||
{
|
|
||||||
if (string.Equals(request.Headers["getMediaInfo.sec"], "1", StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
var ms = TimeSpan.FromTicks(state.RunTimeTicks.Value).TotalMilliseconds;
|
|
||||||
responseHeaders.Append("MediaInfo.sec", string.Format(
|
|
||||||
CultureInfo.InvariantCulture,
|
|
||||||
"SEC_Duration={0};",
|
|
||||||
Convert.ToInt32(ms)));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isStaticallyStreamed && profile is not null)
|
|
||||||
{
|
|
||||||
AddTimeSeekResponseHeaders(state, responseHeaders, startTimeTicks);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
profile ??= dlnaManager.GetDefaultProfile();
|
|
||||||
|
|
||||||
var audioCodec = state.ActualOutputAudioCodec;
|
|
||||||
|
|
||||||
if (!state.IsVideoRequest)
|
|
||||||
{
|
|
||||||
responseHeaders.Append("contentFeatures.dlna.org", ContentFeatureBuilder.BuildAudioHeader(
|
|
||||||
profile,
|
|
||||||
state.OutputContainer,
|
|
||||||
audioCodec,
|
|
||||||
state.OutputAudioBitrate,
|
|
||||||
state.OutputAudioSampleRate,
|
|
||||||
state.OutputAudioChannels,
|
|
||||||
state.OutputAudioBitDepth,
|
|
||||||
isStaticallyStreamed,
|
|
||||||
state.RunTimeTicks,
|
|
||||||
state.TranscodeSeekInfo));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var videoCodec = state.ActualOutputVideoCodec;
|
|
||||||
|
|
||||||
responseHeaders.Append(
|
|
||||||
"contentFeatures.dlna.org",
|
|
||||||
ContentFeatureBuilder.BuildVideoHeader(profile, state.OutputContainer, videoCodec, audioCodec, state.OutputWidth, state.OutputHeight, state.TargetVideoBitDepth, state.OutputVideoBitrate, state.TargetTimestamp, isStaticallyStreamed, state.RunTimeTicks, state.TargetVideoProfile, state.TargetVideoRangeType, state.TargetVideoLevel, state.TargetFramerate, state.TargetPacketLength, state.TranscodeSeekInfo, state.IsTargetAnamorphic, state.IsTargetInterlaced, state.TargetRefFrames, state.TargetVideoStreamCount, state.TargetAudioStreamCount, state.TargetVideoCodecTag, state.IsTargetAVC).FirstOrDefault() ?? string.Empty);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Parses the time seek header.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="value">The time seek header string.</param>
|
|
||||||
/// <returns>A nullable <see cref="long"/> representing the seek time in ticks.</returns>
|
|
||||||
private static long? ParseTimeSeekHeader(ReadOnlySpan<char> value)
|
|
||||||
{
|
|
||||||
if (value.IsEmpty)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const string npt = "npt=";
|
|
||||||
if (!value.StartsWith(npt, StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
throw new ArgumentException("Invalid timeseek header");
|
|
||||||
}
|
|
||||||
|
|
||||||
var index = value.IndexOf('-');
|
|
||||||
value = index == -1
|
|
||||||
? value.Slice(npt.Length)
|
|
||||||
: value.Slice(npt.Length, index - npt.Length);
|
|
||||||
if (!value.Contains(':'))
|
|
||||||
{
|
|
||||||
// Parses npt times in the format of '417.33'
|
|
||||||
if (double.TryParse(value, CultureInfo.InvariantCulture, out var seconds))
|
|
||||||
{
|
|
||||||
return TimeSpan.FromSeconds(seconds).Ticks;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new ArgumentException("Invalid timeseek header");
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// Parses npt times in the format of '10:19:25.7'
|
|
||||||
return TimeSpan.Parse(value, CultureInfo.InvariantCulture).Ticks;
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
throw new ArgumentException("Invalid timeseek header");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Parses query parameters as StreamOptions.
|
/// Parses query parameters as StreamOptions.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -393,29 +254,6 @@ public static class StreamingHelpers
|
||||||
return streamOptions;
|
return streamOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Adds the dlna time seek headers to the response.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="state">The current <see cref="StreamState"/>.</param>
|
|
||||||
/// <param name="responseHeaders">The <see cref="IHeaderDictionary"/> of the response.</param>
|
|
||||||
/// <param name="startTimeTicks">The start time in ticks.</param>
|
|
||||||
private static void AddTimeSeekResponseHeaders(StreamState state, IHeaderDictionary responseHeaders, long? startTimeTicks)
|
|
||||||
{
|
|
||||||
var runtimeSeconds = TimeSpan.FromTicks(state.RunTimeTicks!.Value).TotalSeconds.ToString(CultureInfo.InvariantCulture);
|
|
||||||
var startSeconds = TimeSpan.FromTicks(startTimeTicks ?? 0).TotalSeconds.ToString(CultureInfo.InvariantCulture);
|
|
||||||
|
|
||||||
responseHeaders.Append("TimeSeekRange.dlna.org", string.Format(
|
|
||||||
CultureInfo.InvariantCulture,
|
|
||||||
"npt={0}-{1}/{1}",
|
|
||||||
startSeconds,
|
|
||||||
runtimeSeconds));
|
|
||||||
responseHeaders.Append("X-AvailableSeekRange", string.Format(
|
|
||||||
CultureInfo.InvariantCulture,
|
|
||||||
"1 npt={0}-{1}",
|
|
||||||
startSeconds,
|
|
||||||
runtimeSeconds));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the output file extension.
|
/// Gets the output file extension.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -519,79 +357,6 @@ public static class StreamingHelpers
|
||||||
return Path.Combine(folder, filename + ext);
|
return Path.Combine(folder, filename + ext);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ApplyDeviceProfileSettings(StreamState state, IDlnaManager dlnaManager, IDeviceManager deviceManager, HttpRequest request, string? deviceProfileId, bool? @static)
|
|
||||||
{
|
|
||||||
if (!string.IsNullOrWhiteSpace(deviceProfileId))
|
|
||||||
{
|
|
||||||
state.DeviceProfile = dlnaManager.GetProfile(deviceProfileId);
|
|
||||||
|
|
||||||
if (state.DeviceProfile is null)
|
|
||||||
{
|
|
||||||
var caps = deviceManager.GetCapabilities(deviceProfileId);
|
|
||||||
state.DeviceProfile = caps is null ? dlnaManager.GetProfile(request.Headers) : caps.DeviceProfile;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var profile = state.DeviceProfile;
|
|
||||||
|
|
||||||
if (profile is null)
|
|
||||||
{
|
|
||||||
// Don't use settings from the default profile.
|
|
||||||
// Only use a specific profile if it was requested.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var audioCodec = state.ActualOutputAudioCodec;
|
|
||||||
var videoCodec = state.ActualOutputVideoCodec;
|
|
||||||
|
|
||||||
var mediaProfile = !state.IsVideoRequest
|
|
||||||
? profile.GetAudioMediaProfile(state.OutputContainer, audioCodec, state.OutputAudioChannels, state.OutputAudioBitrate, state.OutputAudioSampleRate, state.OutputAudioBitDepth)
|
|
||||||
: profile.GetVideoMediaProfile(
|
|
||||||
state.OutputContainer,
|
|
||||||
audioCodec,
|
|
||||||
videoCodec,
|
|
||||||
state.OutputWidth,
|
|
||||||
state.OutputHeight,
|
|
||||||
state.TargetVideoBitDepth,
|
|
||||||
state.OutputVideoBitrate,
|
|
||||||
state.TargetVideoProfile,
|
|
||||||
state.TargetVideoRangeType,
|
|
||||||
state.TargetVideoLevel,
|
|
||||||
state.TargetFramerate,
|
|
||||||
state.TargetPacketLength,
|
|
||||||
state.TargetTimestamp,
|
|
||||||
state.IsTargetAnamorphic,
|
|
||||||
state.IsTargetInterlaced,
|
|
||||||
state.TargetRefFrames,
|
|
||||||
state.TargetVideoStreamCount,
|
|
||||||
state.TargetAudioStreamCount,
|
|
||||||
state.TargetVideoCodecTag,
|
|
||||||
state.IsTargetAVC);
|
|
||||||
|
|
||||||
if (mediaProfile is not null)
|
|
||||||
{
|
|
||||||
state.MimeType = mediaProfile.MimeType;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(@static.HasValue && @static.Value))
|
|
||||||
{
|
|
||||||
var transcodingProfile = !state.IsVideoRequest ? profile.GetAudioTranscodingProfile(state.OutputContainer, audioCodec) : profile.GetVideoTranscodingProfile(state.OutputContainer, audioCodec, videoCodec);
|
|
||||||
|
|
||||||
if (transcodingProfile is not null)
|
|
||||||
{
|
|
||||||
state.EstimateContentLength = transcodingProfile.EstimateContentLength;
|
|
||||||
// state.EnableMpegtsM2TsMode = transcodingProfile.EnableMpegtsM2TsMode;
|
|
||||||
state.TranscodeSeekInfo = transcodingProfile.TranscodeSeekInfo;
|
|
||||||
|
|
||||||
if (state.VideoRequest is not null)
|
|
||||||
{
|
|
||||||
state.VideoRequest.CopyTimestamps = transcodingProfile.CopyTimestamps;
|
|
||||||
state.VideoRequest.EnableSubtitlesInManifest = transcodingProfile.EnableSubtitlesInManifest;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Parses the parameters.
|
/// Parses the parameters.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -619,7 +384,7 @@ public static class StreamingHelpers
|
||||||
switch (i)
|
switch (i)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
request.DeviceProfileId = val;
|
// DeviceProfileId
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
request.DeviceId = val;
|
request.DeviceId = val;
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Emby.Dlna\Emby.Dlna.csproj" />
|
<ProjectReference Include="..\Jellyfin.Networking\Jellyfin.Networking.csproj" />
|
||||||
<ProjectReference Include="..\MediaBrowser.Controller\MediaBrowser.Controller.csproj" />
|
<ProjectReference Include="..\MediaBrowser.Controller\MediaBrowser.Controller.csproj" />
|
||||||
<ProjectReference Include="..\MediaBrowser.MediaEncoding\MediaBrowser.MediaEncoding.csproj" />
|
<ProjectReference Include="..\MediaBrowser.MediaEncoding\MediaBrowser.MediaEncoding.csproj" />
|
||||||
<ProjectReference Include="..\src\Jellyfin.MediaEncoding.Hls\Jellyfin.MediaEncoding.Hls.csproj" />
|
<ProjectReference Include="..\src\Jellyfin.MediaEncoding.Hls\Jellyfin.MediaEncoding.Hls.csproj" />
|
||||||
|
|
|
@ -138,16 +138,6 @@ public class StreamState : EncodingJobInfo, IDisposable
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public TranscodeSeekInfo TranscodeSeekInfo { get; set; }
|
public TranscodeSeekInfo TranscodeSeekInfo { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets a value indicating whether to enable dlna headers.
|
|
||||||
/// </summary>
|
|
||||||
public bool EnableDlnaHeaders { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the device profile.
|
|
||||||
/// </summary>
|
|
||||||
public DeviceProfile? DeviceProfile { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the transcoding job.
|
/// Gets or sets the transcoding job.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -7,11 +7,6 @@ namespace Jellyfin.Api.Models.StreamingDtos;
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class StreamingRequestDto : BaseEncodingJobOptions
|
public class StreamingRequestDto : BaseEncodingJobOptions
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the device profile.
|
|
||||||
/// </summary>
|
|
||||||
public string? DeviceProfileId { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the params.
|
/// Gets or sets the params.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
Loading…
Reference in New Issue