mirror of
https://github.com/jellyfin/jellyfin.git
synced 2025-05-24 02:02:29 -04:00
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>
|
||||
/// The audio controller.
|
||||
/// </summary>
|
||||
// TODO: In order to authenticate this in the future, Dlna playback will require updating
|
||||
public class AudioController : BaseJellyfinApiController
|
||||
{
|
||||
private readonly AudioHelper _audioHelper;
|
||||
@ -95,7 +94,7 @@ public class AudioController : BaseJellyfinApiController
|
||||
[FromQuery] bool? @static,
|
||||
[FromQuery] string? @params,
|
||||
[FromQuery] string? tag,
|
||||
[FromQuery] string? deviceProfileId,
|
||||
[FromQuery, ParameterObsolete] string? deviceProfileId,
|
||||
[FromQuery] string? playSessionId,
|
||||
[FromQuery] string? segmentContainer,
|
||||
[FromQuery] int? segmentLength,
|
||||
@ -147,7 +146,6 @@ public class AudioController : BaseJellyfinApiController
|
||||
Static = @static ?? false,
|
||||
Params = @params,
|
||||
Tag = tag,
|
||||
DeviceProfileId = deviceProfileId,
|
||||
PlaySessionId = playSessionId,
|
||||
SegmentContainer = segmentContainer,
|
||||
SegmentLength = segmentLength,
|
||||
@ -260,7 +258,7 @@ public class AudioController : BaseJellyfinApiController
|
||||
[FromQuery] bool? @static,
|
||||
[FromQuery] string? @params,
|
||||
[FromQuery] string? tag,
|
||||
[FromQuery] string? deviceProfileId,
|
||||
[FromQuery, ParameterObsolete] string? deviceProfileId,
|
||||
[FromQuery] string? playSessionId,
|
||||
[FromQuery] string? segmentContainer,
|
||||
[FromQuery] int? segmentLength,
|
||||
@ -312,7 +310,6 @@ public class AudioController : BaseJellyfinApiController
|
||||
Static = @static ?? false,
|
||||
Params = @params,
|
||||
Tag = tag,
|
||||
DeviceProfileId = deviceProfileId,
|
||||
PlaySessionId = playSessionId,
|
||||
SegmentContainer = segmentContainer,
|
||||
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 MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Devices;
|
||||
using MediaBrowser.Controller.Dlna;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.MediaEncoding;
|
||||
using MediaBrowser.MediaEncoding.Encoder;
|
||||
@ -49,12 +47,10 @@ public class DynamicHlsController : BaseJellyfinApiController
|
||||
|
||||
private readonly ILibraryManager _libraryManager;
|
||||
private readonly IUserManager _userManager;
|
||||
private readonly IDlnaManager _dlnaManager;
|
||||
private readonly IMediaSourceManager _mediaSourceManager;
|
||||
private readonly IServerConfigurationManager _serverConfigurationManager;
|
||||
private readonly IMediaEncoder _mediaEncoder;
|
||||
private readonly IFileSystem _fileSystem;
|
||||
private readonly IDeviceManager _deviceManager;
|
||||
private readonly TranscodingJobHelper _transcodingJobHelper;
|
||||
private readonly ILogger<DynamicHlsController> _logger;
|
||||
private readonly EncodingHelper _encodingHelper;
|
||||
@ -67,12 +63,10 @@ public class DynamicHlsController : BaseJellyfinApiController
|
||||
/// </summary>
|
||||
/// <param name="libraryManager">Instance of the <see cref="ILibraryManager"/> 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="serverConfigurationManager">Instance of the <see cref="IServerConfigurationManager"/> 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="deviceManager">Instance of the <see cref="IDeviceManager"/> interface.</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="dynamicHlsHelper">Instance of <see cref="DynamicHlsHelper"/>.</param>
|
||||
@ -81,12 +75,10 @@ public class DynamicHlsController : BaseJellyfinApiController
|
||||
public DynamicHlsController(
|
||||
ILibraryManager libraryManager,
|
||||
IUserManager userManager,
|
||||
IDlnaManager dlnaManager,
|
||||
IMediaSourceManager mediaSourceManager,
|
||||
IServerConfigurationManager serverConfigurationManager,
|
||||
IMediaEncoder mediaEncoder,
|
||||
IFileSystem fileSystem,
|
||||
IDeviceManager deviceManager,
|
||||
TranscodingJobHelper transcodingJobHelper,
|
||||
ILogger<DynamicHlsController> logger,
|
||||
DynamicHlsHelper dynamicHlsHelper,
|
||||
@ -95,12 +87,10 @@ public class DynamicHlsController : BaseJellyfinApiController
|
||||
{
|
||||
_libraryManager = libraryManager;
|
||||
_userManager = userManager;
|
||||
_dlnaManager = dlnaManager;
|
||||
_mediaSourceManager = mediaSourceManager;
|
||||
_serverConfigurationManager = serverConfigurationManager;
|
||||
_mediaEncoder = mediaEncoder;
|
||||
_fileSystem = fileSystem;
|
||||
_deviceManager = deviceManager;
|
||||
_transcodingJobHelper = transcodingJobHelper;
|
||||
_logger = logger;
|
||||
_dynamicHlsHelper = dynamicHlsHelper;
|
||||
@ -176,7 +166,7 @@ public class DynamicHlsController : BaseJellyfinApiController
|
||||
[FromQuery] bool? @static,
|
||||
[FromQuery] string? @params,
|
||||
[FromQuery] string? tag,
|
||||
[FromQuery] string? deviceProfileId,
|
||||
[FromQuery, ParameterObsolete] string? deviceProfileId,
|
||||
[FromQuery] string? playSessionId,
|
||||
[FromQuery] string? segmentContainer,
|
||||
[FromQuery] int? segmentLength,
|
||||
@ -231,7 +221,6 @@ public class DynamicHlsController : BaseJellyfinApiController
|
||||
Static = @static ?? false,
|
||||
Params = @params,
|
||||
Tag = tag,
|
||||
DeviceProfileId = deviceProfileId,
|
||||
PlaySessionId = playSessionId,
|
||||
SegmentContainer = segmentContainer,
|
||||
SegmentLength = segmentLength,
|
||||
@ -294,8 +283,6 @@ public class DynamicHlsController : BaseJellyfinApiController
|
||||
_serverConfigurationManager,
|
||||
_mediaEncoder,
|
||||
_encodingHelper,
|
||||
_dlnaManager,
|
||||
_deviceManager,
|
||||
_transcodingJobHelper,
|
||||
TranscodingJobType,
|
||||
cancellationToken)
|
||||
@ -422,7 +409,7 @@ public class DynamicHlsController : BaseJellyfinApiController
|
||||
[FromQuery] bool? @static,
|
||||
[FromQuery] string? @params,
|
||||
[FromQuery] string? tag,
|
||||
[FromQuery] string? deviceProfileId,
|
||||
[FromQuery, ParameterObsolete] string? deviceProfileId,
|
||||
[FromQuery] string? playSessionId,
|
||||
[FromQuery] string? segmentContainer,
|
||||
[FromQuery] int? segmentLength,
|
||||
@ -477,7 +464,6 @@ public class DynamicHlsController : BaseJellyfinApiController
|
||||
Static = @static ?? false,
|
||||
Params = @params,
|
||||
Tag = tag,
|
||||
DeviceProfileId = deviceProfileId,
|
||||
PlaySessionId = playSessionId,
|
||||
SegmentContainer = segmentContainer,
|
||||
SegmentLength = segmentLength,
|
||||
@ -594,7 +580,7 @@ public class DynamicHlsController : BaseJellyfinApiController
|
||||
[FromQuery] bool? @static,
|
||||
[FromQuery] string? @params,
|
||||
[FromQuery] string? tag,
|
||||
[FromQuery] string? deviceProfileId,
|
||||
[FromQuery, ParameterObsolete] string? deviceProfileId,
|
||||
[FromQuery] string? playSessionId,
|
||||
[FromQuery] string? segmentContainer,
|
||||
[FromQuery] int? segmentLength,
|
||||
@ -647,7 +633,6 @@ public class DynamicHlsController : BaseJellyfinApiController
|
||||
Static = @static ?? false,
|
||||
Params = @params,
|
||||
Tag = tag,
|
||||
DeviceProfileId = deviceProfileId,
|
||||
PlaySessionId = playSessionId,
|
||||
SegmentContainer = segmentContainer,
|
||||
SegmentLength = segmentLength,
|
||||
@ -760,7 +745,7 @@ public class DynamicHlsController : BaseJellyfinApiController
|
||||
[FromQuery] bool? @static,
|
||||
[FromQuery] string? @params,
|
||||
[FromQuery] string? tag,
|
||||
[FromQuery] string? deviceProfileId,
|
||||
[FromQuery, ParameterObsolete] string? deviceProfileId,
|
||||
[FromQuery] string? playSessionId,
|
||||
[FromQuery] string? segmentContainer,
|
||||
[FromQuery] int? segmentLength,
|
||||
@ -814,7 +799,6 @@ public class DynamicHlsController : BaseJellyfinApiController
|
||||
Static = @static ?? false,
|
||||
Params = @params,
|
||||
Tag = tag,
|
||||
DeviceProfileId = deviceProfileId,
|
||||
PlaySessionId = playSessionId,
|
||||
SegmentContainer = segmentContainer,
|
||||
SegmentLength = segmentLength,
|
||||
@ -928,7 +912,7 @@ public class DynamicHlsController : BaseJellyfinApiController
|
||||
[FromQuery] bool? @static,
|
||||
[FromQuery] string? @params,
|
||||
[FromQuery] string? tag,
|
||||
[FromQuery] string? deviceProfileId,
|
||||
[FromQuery, ParameterObsolete] string? deviceProfileId,
|
||||
[FromQuery] string? playSessionId,
|
||||
[FromQuery] string? segmentContainer,
|
||||
[FromQuery] int? segmentLength,
|
||||
@ -981,7 +965,6 @@ public class DynamicHlsController : BaseJellyfinApiController
|
||||
Static = @static ?? false,
|
||||
Params = @params,
|
||||
Tag = tag,
|
||||
DeviceProfileId = deviceProfileId,
|
||||
PlaySessionId = playSessionId,
|
||||
SegmentContainer = segmentContainer,
|
||||
SegmentLength = segmentLength,
|
||||
@ -1105,7 +1088,7 @@ public class DynamicHlsController : BaseJellyfinApiController
|
||||
[FromQuery] bool? @static,
|
||||
[FromQuery] string? @params,
|
||||
[FromQuery] string? tag,
|
||||
[FromQuery] string? deviceProfileId,
|
||||
[FromQuery, ParameterObsolete] string? deviceProfileId,
|
||||
[FromQuery] string? playSessionId,
|
||||
[FromQuery] string? segmentContainer,
|
||||
[FromQuery] int? segmentLength,
|
||||
@ -1161,7 +1144,6 @@ public class DynamicHlsController : BaseJellyfinApiController
|
||||
Static = @static ?? false,
|
||||
Params = @params,
|
||||
Tag = tag,
|
||||
DeviceProfileId = deviceProfileId,
|
||||
PlaySessionId = playSessionId,
|
||||
SegmentContainer = segmentContainer,
|
||||
SegmentLength = segmentLength,
|
||||
@ -1286,7 +1268,7 @@ public class DynamicHlsController : BaseJellyfinApiController
|
||||
[FromQuery] bool? @static,
|
||||
[FromQuery] string? @params,
|
||||
[FromQuery] string? tag,
|
||||
[FromQuery] string? deviceProfileId,
|
||||
[FromQuery, ParameterObsolete] string? deviceProfileId,
|
||||
[FromQuery] string? playSessionId,
|
||||
[FromQuery] string? segmentContainer,
|
||||
[FromQuery] int? segmentLength,
|
||||
@ -1341,7 +1323,6 @@ public class DynamicHlsController : BaseJellyfinApiController
|
||||
Static = @static ?? false,
|
||||
Params = @params,
|
||||
Tag = tag,
|
||||
DeviceProfileId = deviceProfileId,
|
||||
PlaySessionId = playSessionId,
|
||||
SegmentContainer = segmentContainer,
|
||||
SegmentLength = segmentLength,
|
||||
@ -1402,8 +1383,6 @@ public class DynamicHlsController : BaseJellyfinApiController
|
||||
_serverConfigurationManager,
|
||||
_mediaEncoder,
|
||||
_encodingHelper,
|
||||
_dlnaManager,
|
||||
_deviceManager,
|
||||
_transcodingJobHelper,
|
||||
TranscodingJobType,
|
||||
cancellationTokenSource.Token)
|
||||
@ -1442,8 +1421,6 @@ public class DynamicHlsController : BaseJellyfinApiController
|
||||
_serverConfigurationManager,
|
||||
_mediaEncoder,
|
||||
_encodingHelper,
|
||||
_dlnaManager,
|
||||
_deviceManager,
|
||||
_transcodingJobHelper,
|
||||
TranscodingJobType,
|
||||
cancellationToken)
|
||||
|
@ -16,8 +16,6 @@ using MediaBrowser.Common.Api;
|
||||
using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Devices;
|
||||
using MediaBrowser.Controller.Dlna;
|
||||
using MediaBrowser.Controller.Dto;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Library;
|
||||
@ -42,11 +40,9 @@ public class VideosController : BaseJellyfinApiController
|
||||
private readonly ILibraryManager _libraryManager;
|
||||
private readonly IUserManager _userManager;
|
||||
private readonly IDtoService _dtoService;
|
||||
private readonly IDlnaManager _dlnaManager;
|
||||
private readonly IMediaSourceManager _mediaSourceManager;
|
||||
private readonly IServerConfigurationManager _serverConfigurationManager;
|
||||
private readonly IMediaEncoder _mediaEncoder;
|
||||
private readonly IDeviceManager _deviceManager;
|
||||
private readonly TranscodingJobHelper _transcodingJobHelper;
|
||||
private readonly IHttpClientFactory _httpClientFactory;
|
||||
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="userManager">Instance of the <see cref="IUserManager"/> 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="serverConfigurationManager">Instance of the <see cref="IServerConfigurationManager"/> 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="httpClientFactory">Instance of the <see cref="IHttpClientFactory"/> interface.</param>
|
||||
/// <param name="encodingHelper">Instance of <see cref="EncodingHelper"/>.</param>
|
||||
@ -71,11 +65,9 @@ public class VideosController : BaseJellyfinApiController
|
||||
ILibraryManager libraryManager,
|
||||
IUserManager userManager,
|
||||
IDtoService dtoService,
|
||||
IDlnaManager dlnaManager,
|
||||
IMediaSourceManager mediaSourceManager,
|
||||
IServerConfigurationManager serverConfigurationManager,
|
||||
IMediaEncoder mediaEncoder,
|
||||
IDeviceManager deviceManager,
|
||||
TranscodingJobHelper transcodingJobHelper,
|
||||
IHttpClientFactory httpClientFactory,
|
||||
EncodingHelper encodingHelper)
|
||||
@ -83,11 +75,9 @@ public class VideosController : BaseJellyfinApiController
|
||||
_libraryManager = libraryManager;
|
||||
_userManager = userManager;
|
||||
_dtoService = dtoService;
|
||||
_dlnaManager = dlnaManager;
|
||||
_mediaSourceManager = mediaSourceManager;
|
||||
_serverConfigurationManager = serverConfigurationManager;
|
||||
_mediaEncoder = mediaEncoder;
|
||||
_deviceManager = deviceManager;
|
||||
_transcodingJobHelper = transcodingJobHelper;
|
||||
_httpClientFactory = httpClientFactory;
|
||||
_encodingHelper = encodingHelper;
|
||||
@ -324,7 +314,7 @@ public class VideosController : BaseJellyfinApiController
|
||||
[FromQuery] bool? @static,
|
||||
[FromQuery] string? @params,
|
||||
[FromQuery] string? tag,
|
||||
[FromQuery] string? deviceProfileId,
|
||||
[FromQuery, ParameterObsolete] string? deviceProfileId,
|
||||
[FromQuery] string? playSessionId,
|
||||
[FromQuery] string? segmentContainer,
|
||||
[FromQuery] int? segmentLength,
|
||||
@ -381,7 +371,6 @@ public class VideosController : BaseJellyfinApiController
|
||||
Static = @static ?? false,
|
||||
Params = @params,
|
||||
Tag = tag,
|
||||
DeviceProfileId = deviceProfileId,
|
||||
PlaySessionId = playSessionId,
|
||||
SegmentContainer = segmentContainer,
|
||||
SegmentLength = segmentLength,
|
||||
@ -438,8 +427,6 @@ public class VideosController : BaseJellyfinApiController
|
||||
_serverConfigurationManager,
|
||||
_mediaEncoder,
|
||||
_encodingHelper,
|
||||
_dlnaManager,
|
||||
_deviceManager,
|
||||
_transcodingJobHelper,
|
||||
_transcodingJobType,
|
||||
cancellationTokenSource.Token)
|
||||
@ -447,8 +434,6 @@ public class VideosController : BaseJellyfinApiController
|
||||
|
||||
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);
|
||||
if (liveStreamInfo is null)
|
||||
{
|
||||
@ -463,8 +448,6 @@ public class VideosController : BaseJellyfinApiController
|
||||
// Static remote stream
|
||||
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);
|
||||
return await FileStreamResponseHelpers.GetStaticRemoteStreamResult(state, httpClient, HttpContext).ConfigureAwait(false);
|
||||
}
|
||||
@ -475,12 +458,6 @@ public class VideosController : BaseJellyfinApiController
|
||||
}
|
||||
|
||||
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
|
||||
if (@static.HasValue && @static.Value)
|
||||
|
@ -7,8 +7,6 @@ using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Common.Extensions;
|
||||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Devices;
|
||||
using MediaBrowser.Controller.Dlna;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.MediaEncoding;
|
||||
using MediaBrowser.Model.MediaInfo;
|
||||
@ -23,13 +21,11 @@ namespace Jellyfin.Api.Helpers;
|
||||
/// </summary>
|
||||
public class AudioHelper
|
||||
{
|
||||
private readonly IDlnaManager _dlnaManager;
|
||||
private readonly IUserManager _userManager;
|
||||
private readonly ILibraryManager _libraryManager;
|
||||
private readonly IMediaSourceManager _mediaSourceManager;
|
||||
private readonly IServerConfigurationManager _serverConfigurationManager;
|
||||
private readonly IMediaEncoder _mediaEncoder;
|
||||
private readonly IDeviceManager _deviceManager;
|
||||
private readonly TranscodingJobHelper _transcodingJobHelper;
|
||||
private readonly IHttpClientFactory _httpClientFactory;
|
||||
private readonly IHttpContextAccessor _httpContextAccessor;
|
||||
@ -38,37 +34,31 @@ public class AudioHelper
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="AudioHelper"/> class.
|
||||
/// </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="libraryManager">Instance of the <see cref="ILibraryManager"/> 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="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="httpClientFactory">Instance of the <see cref="IHttpClientFactory"/> interface.</param>
|
||||
/// <param name="httpContextAccessor">Instance of the <see cref="IHttpContextAccessor"/> interface.</param>
|
||||
/// <param name="encodingHelper">Instance of <see cref="EncodingHelper"/>.</param>
|
||||
public AudioHelper(
|
||||
IDlnaManager dlnaManager,
|
||||
IUserManager userManager,
|
||||
ILibraryManager libraryManager,
|
||||
IMediaSourceManager mediaSourceManager,
|
||||
IServerConfigurationManager serverConfigurationManager,
|
||||
IMediaEncoder mediaEncoder,
|
||||
IDeviceManager deviceManager,
|
||||
TranscodingJobHelper transcodingJobHelper,
|
||||
IHttpClientFactory httpClientFactory,
|
||||
IHttpContextAccessor httpContextAccessor,
|
||||
EncodingHelper encodingHelper)
|
||||
{
|
||||
_dlnaManager = dlnaManager;
|
||||
_userManager = userManager;
|
||||
_libraryManager = libraryManager;
|
||||
_mediaSourceManager = mediaSourceManager;
|
||||
_serverConfigurationManager = serverConfigurationManager;
|
||||
_mediaEncoder = mediaEncoder;
|
||||
_deviceManager = deviceManager;
|
||||
_transcodingJobHelper = transcodingJobHelper;
|
||||
_httpClientFactory = httpClientFactory;
|
||||
_httpContextAccessor = httpContextAccessor;
|
||||
@ -104,8 +94,6 @@ public class AudioHelper
|
||||
_serverConfigurationManager,
|
||||
_mediaEncoder,
|
||||
_encodingHelper,
|
||||
_dlnaManager,
|
||||
_deviceManager,
|
||||
_transcodingJobHelper,
|
||||
transcodingJobType,
|
||||
cancellationTokenSource.Token)
|
||||
@ -113,8 +101,6 @@ public class AudioHelper
|
||||
|
||||
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);
|
||||
if (liveStreamInfo is null)
|
||||
{
|
||||
@ -129,8 +115,6 @@ public class AudioHelper
|
||||
// Static remote stream
|
||||
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);
|
||||
return await FileStreamResponseHelpers.GetStaticRemoteStreamResult(state, httpClient, _httpContextAccessor.HttpContext).ConfigureAwait(false);
|
||||
}
|
||||
@ -141,12 +125,6 @@ public class AudioHelper
|
||||
}
|
||||
|
||||
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
|
||||
if (streamingRequest.Static)
|
||||
|
@ -16,8 +16,6 @@ using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Common.Extensions;
|
||||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Devices;
|
||||
using MediaBrowser.Controller.Dlna;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.MediaEncoding;
|
||||
using MediaBrowser.Controller.Trickplay;
|
||||
@ -38,11 +36,9 @@ public class DynamicHlsHelper
|
||||
{
|
||||
private readonly ILibraryManager _libraryManager;
|
||||
private readonly IUserManager _userManager;
|
||||
private readonly IDlnaManager _dlnaManager;
|
||||
private readonly IMediaSourceManager _mediaSourceManager;
|
||||
private readonly IServerConfigurationManager _serverConfigurationManager;
|
||||
private readonly IMediaEncoder _mediaEncoder;
|
||||
private readonly IDeviceManager _deviceManager;
|
||||
private readonly TranscodingJobHelper _transcodingJobHelper;
|
||||
private readonly INetworkManager _networkManager;
|
||||
private readonly ILogger<DynamicHlsHelper> _logger;
|
||||
@ -55,11 +51,9 @@ public class DynamicHlsHelper
|
||||
/// </summary>
|
||||
/// <param name="libraryManager">Instance of the <see cref="ILibraryManager"/> 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="serverConfigurationManager">Instance of the <see cref="IServerConfigurationManager"/> 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="networkManager">Instance of the <see cref="INetworkManager"/> interface.</param>
|
||||
/// <param name="logger">Instance of the <see cref="ILogger{DynamicHlsHelper}"/> interface.</param>
|
||||
@ -69,11 +63,9 @@ public class DynamicHlsHelper
|
||||
public DynamicHlsHelper(
|
||||
ILibraryManager libraryManager,
|
||||
IUserManager userManager,
|
||||
IDlnaManager dlnaManager,
|
||||
IMediaSourceManager mediaSourceManager,
|
||||
IServerConfigurationManager serverConfigurationManager,
|
||||
IMediaEncoder mediaEncoder,
|
||||
IDeviceManager deviceManager,
|
||||
TranscodingJobHelper transcodingJobHelper,
|
||||
INetworkManager networkManager,
|
||||
ILogger<DynamicHlsHelper> logger,
|
||||
@ -83,11 +75,9 @@ public class DynamicHlsHelper
|
||||
{
|
||||
_libraryManager = libraryManager;
|
||||
_userManager = userManager;
|
||||
_dlnaManager = dlnaManager;
|
||||
_mediaSourceManager = mediaSourceManager;
|
||||
_serverConfigurationManager = serverConfigurationManager;
|
||||
_mediaEncoder = mediaEncoder;
|
||||
_deviceManager = deviceManager;
|
||||
_transcodingJobHelper = transcodingJobHelper;
|
||||
_networkManager = networkManager;
|
||||
_logger = logger;
|
||||
@ -140,8 +130,6 @@ public class DynamicHlsHelper
|
||||
_serverConfigurationManager,
|
||||
_mediaEncoder,
|
||||
_encodingHelper,
|
||||
_dlnaManager,
|
||||
_deviceManager,
|
||||
_transcodingJobHelper,
|
||||
transcodingJobType,
|
||||
cancellationTokenSource.Token)
|
||||
|
@ -12,15 +12,12 @@ using Jellyfin.Extensions;
|
||||
using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Common.Extensions;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Devices;
|
||||
using MediaBrowser.Controller.Dlna;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.MediaEncoding;
|
||||
using MediaBrowser.Model.Dlna;
|
||||
using MediaBrowser.Model.Dto;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
using Microsoft.Net.Http.Headers;
|
||||
|
||||
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="mediaEncoder">Instance of the <see cref="IMediaEncoder"/> interface.</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="transcodingJobType">The <see cref="TranscodingJobType"/>.</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/>.</param>
|
||||
@ -56,21 +51,11 @@ public static class StreamingHelpers
|
||||
IServerConfigurationManager serverConfigurationManager,
|
||||
IMediaEncoder mediaEncoder,
|
||||
EncodingHelper encodingHelper,
|
||||
IDlnaManager dlnaManager,
|
||||
IDeviceManager deviceManager,
|
||||
TranscodingJobHelper transcodingJobHelper,
|
||||
TranscodingJobType transcodingJobType,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
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))
|
||||
{
|
||||
ParseParams(streamingRequest);
|
||||
@ -89,16 +74,11 @@ public static class StreamingHelpers
|
||||
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)
|
||||
{
|
||||
Request = streamingRequest,
|
||||
RequestedUrl = url,
|
||||
UserAgent = httpRequest.Headers[HeaderNames.UserAgent],
|
||||
EnableDlnaHeaders = enableDlnaHeaders
|
||||
UserAgent = httpRequest.Headers[HeaderNames.UserAgent]
|
||||
};
|
||||
|
||||
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)
|
||||
? GetOutputFileExtension(state, mediaSource)
|
||||
: ("." + state.OutputContainer);
|
||||
@ -254,123 +232,6 @@ public static class StreamingHelpers
|
||||
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>
|
||||
/// Parses query parameters as StreamOptions.
|
||||
/// </summary>
|
||||
@ -393,29 +254,6 @@ public static class StreamingHelpers
|
||||
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>
|
||||
/// Gets the output file extension.
|
||||
/// </summary>
|
||||
@ -519,79 +357,6 @@ public static class StreamingHelpers
|
||||
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>
|
||||
/// Parses the parameters.
|
||||
/// </summary>
|
||||
@ -619,7 +384,7 @@ public static class StreamingHelpers
|
||||
switch (i)
|
||||
{
|
||||
case 0:
|
||||
request.DeviceProfileId = val;
|
||||
// DeviceProfileId
|
||||
break;
|
||||
case 1:
|
||||
request.DeviceId = val;
|
||||
|
@ -18,7 +18,7 @@
|
||||
</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.MediaEncoding\MediaBrowser.MediaEncoding.csproj" />
|
||||
<ProjectReference Include="..\src\Jellyfin.MediaEncoding.Hls\Jellyfin.MediaEncoding.Hls.csproj" />
|
||||
|
@ -138,16 +138,6 @@ public class StreamState : EncodingJobInfo, IDisposable
|
||||
/// </summary>
|
||||
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>
|
||||
/// Gets or sets the transcoding job.
|
||||
/// </summary>
|
||||
|
@ -7,11 +7,6 @@ namespace Jellyfin.Api.Models.StreamingDtos;
|
||||
/// </summary>
|
||||
public class StreamingRequestDto : BaseEncodingJobOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the device profile.
|
||||
/// </summary>
|
||||
public string? DeviceProfileId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the params.
|
||||
/// </summary>
|
||||
|
Loading…
x
Reference in New Issue
Block a user