Remove DLNA API code

pull/10558/head
Patrick Barron 6 months ago
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…
Cancel
Save