Merge pull request #3775 from crobibero/api-dynamic-hls
Move DynamicHlsService to Jellyfin.Api
This commit is contained in:
commit
d50a022036
|
@ -70,7 +70,7 @@ namespace Jellyfin.Api.Auth
|
|||
return false;
|
||||
}
|
||||
|
||||
var ip = NormalizeIp(_httpContextAccessor.HttpContext.Connection.RemoteIpAddress).ToString();
|
||||
var ip = RequestHelpers.NormalizeIp(_httpContextAccessor.HttpContext.Connection.RemoteIpAddress).ToString();
|
||||
var isInLocalNetwork = _networkManager.IsInLocalNetwork(ip);
|
||||
// User cannot access remotely and user is remote
|
||||
if (!user.HasPermission(PermissionKind.EnableRemoteAccess) && !isInLocalNetwork)
|
||||
|
@ -100,10 +100,5 @@ namespace Jellyfin.Api.Auth
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static IPAddress NormalizeIp(IPAddress ip)
|
||||
{
|
||||
return ip.IsIPv4MappedToIPv6 ? ip.MapToIPv4() : ip;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
2215
Jellyfin.Api/Controllers/DynamicHlsController.cs
Normal file
2215
Jellyfin.Api/Controllers/DynamicHlsController.cs
Normal file
File diff suppressed because it is too large
Load Diff
125
Jellyfin.Api/Helpers/HlsCodecStringHelpers.cs
Normal file
125
Jellyfin.Api/Helpers/HlsCodecStringHelpers.cs
Normal file
|
@ -0,0 +1,125 @@
|
|||
using System;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
|
||||
namespace Jellyfin.Api.Helpers
|
||||
{
|
||||
/// <summary>
|
||||
/// Hls Codec string helpers.
|
||||
/// </summary>
|
||||
public static class HlsCodecStringHelpers
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets a MP3 codec string.
|
||||
/// </summary>
|
||||
/// <returns>MP3 codec string.</returns>
|
||||
public static string GetMP3String()
|
||||
{
|
||||
return "mp4a.40.34";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets an AAC codec string.
|
||||
/// </summary>
|
||||
/// <param name="profile">AAC profile.</param>
|
||||
/// <returns>AAC codec string.</returns>
|
||||
public static string GetAACString(string profile)
|
||||
{
|
||||
StringBuilder result = new StringBuilder("mp4a", 9);
|
||||
|
||||
if (string.Equals(profile, "HE", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
result.Append(".40.5");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Default to LC if profile is invalid
|
||||
result.Append(".40.2");
|
||||
}
|
||||
|
||||
return result.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a H.264 codec string.
|
||||
/// </summary>
|
||||
/// <param name="profile">H.264 profile.</param>
|
||||
/// <param name="level">H.264 level.</param>
|
||||
/// <returns>H.264 string.</returns>
|
||||
public static string GetH264String(string profile, int level)
|
||||
{
|
||||
StringBuilder result = new StringBuilder("avc1", 11);
|
||||
|
||||
if (string.Equals(profile, "high", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
result.Append(".6400");
|
||||
}
|
||||
else if (string.Equals(profile, "main", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
result.Append(".4D40");
|
||||
}
|
||||
else if (string.Equals(profile, "baseline", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
result.Append(".42E0");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Default to constrained baseline if profile is invalid
|
||||
result.Append(".4240");
|
||||
}
|
||||
|
||||
string levelHex = level.ToString("X2", CultureInfo.InvariantCulture);
|
||||
result.Append(levelHex);
|
||||
|
||||
return result.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a H.265 codec string.
|
||||
/// </summary>
|
||||
/// <param name="profile">H.265 profile.</param>
|
||||
/// <param name="level">H.265 level.</param>
|
||||
/// <returns>H.265 string.</returns>
|
||||
public static string GetH265String(string profile, int level)
|
||||
{
|
||||
// The h265 syntax is a bit of a mystery at the time this comment was written.
|
||||
// This is what I've found through various sources:
|
||||
// FORMAT: [codecTag].[profile].[constraint?].L[level * 30].[UNKNOWN]
|
||||
StringBuilder result = new StringBuilder("hev1", 16);
|
||||
|
||||
if (string.Equals(profile, "main10", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
result.Append(".2.6");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Default to main if profile is invalid
|
||||
result.Append(".1.6");
|
||||
}
|
||||
|
||||
result.Append(".L")
|
||||
.Append(level * 3)
|
||||
.Append(".B0");
|
||||
|
||||
return result.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets an AC-3 codec string.
|
||||
/// </summary>
|
||||
/// <returns>AC-3 codec string.</returns>
|
||||
public static string GetAC3String()
|
||||
{
|
||||
return "mp4a.a5";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets an E-AC-3 codec string.
|
||||
/// </summary>
|
||||
/// <returns>E-AC-3 codec string.</returns>
|
||||
public static string GetEAC3String()
|
||||
{
|
||||
return "mp4a.a6";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using Jellyfin.Data.Enums;
|
||||
using MediaBrowser.Controller.Net;
|
||||
using MediaBrowser.Controller.Session;
|
||||
|
@ -172,5 +173,10 @@ namespace Jellyfin.Api.Helpers
|
|||
.Select(i => i!.Value)
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
internal static IPAddress NormalizeIp(IPAddress ip)
|
||||
{
|
||||
return ip.IsIPv4MappedToIPv6 ? ip.MapToIPv4() : ip;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -219,7 +219,7 @@ namespace Jellyfin.Api.Helpers
|
|||
/// <param name="playSessionId">The play session identifier.</param>
|
||||
/// <param name="deleteFiles">The delete files.</param>
|
||||
/// <returns>Task.</returns>
|
||||
public Task KillTranscodingJobs(string deviceId, string playSessionId, Func<string, bool> deleteFiles)
|
||||
public Task KillTranscodingJobs(string deviceId, string? playSessionId, Func<string, bool> deleteFiles)
|
||||
{
|
||||
return KillTranscodingJobs(
|
||||
j => string.IsNullOrWhiteSpace(playSessionId)
|
||||
|
@ -503,9 +503,9 @@ namespace Jellyfin.Api.Helpers
|
|||
}
|
||||
}
|
||||
|
||||
var process = new Process()
|
||||
var process = new Process
|
||||
{
|
||||
StartInfo = new ProcessStartInfo()
|
||||
StartInfo = new ProcessStartInfo
|
||||
{
|
||||
WindowStyle = ProcessWindowStyle.Hidden,
|
||||
CreateNoWindow = true,
|
||||
|
|
13
Jellyfin.Api/Models/StreamingDtos/HlsAudioRequestDto.cs
Normal file
13
Jellyfin.Api/Models/StreamingDtos/HlsAudioRequestDto.cs
Normal file
|
@ -0,0 +1,13 @@
|
|||
namespace Jellyfin.Api.Models.StreamingDtos
|
||||
{
|
||||
/// <summary>
|
||||
/// The hls video request dto.
|
||||
/// </summary>
|
||||
public class HlsAudioRequestDto : StreamingRequestDto
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether enable adaptive bitrate streaming.
|
||||
/// </summary>
|
||||
public bool EnableAdaptiveBitrateStreaming { get; set; }
|
||||
}
|
||||
}
|
13
Jellyfin.Api/Models/StreamingDtos/HlsVideoRequestDto.cs
Normal file
13
Jellyfin.Api/Models/StreamingDtos/HlsVideoRequestDto.cs
Normal file
|
@ -0,0 +1,13 @@
|
|||
namespace Jellyfin.Api.Models.StreamingDtos
|
||||
{
|
||||
/// <summary>
|
||||
/// The hls video request dto.
|
||||
/// </summary>
|
||||
public class HlsVideoRequestDto : VideoRequestDto
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether enable adaptive bitrate streaming.
|
||||
/// </summary>
|
||||
public bool EnableAdaptiveBitrateStreaming { get; set; }
|
||||
}
|
||||
}
|
|
@ -27,8 +27,6 @@ namespace MediaBrowser.Api.Playback.Hls
|
|||
/// <summary>
|
||||
/// Options is needed for chromecast. Threw Head in there since it's related
|
||||
/// </summary>
|
||||
[Route("/Videos/{Id}/master.m3u8", "GET", Summary = "Gets a video stream using HTTP live streaming.")]
|
||||
[Route("/Videos/{Id}/master.m3u8", "HEAD", Summary = "Gets a video stream using HTTP live streaming.")]
|
||||
public class GetMasterHlsVideoPlaylist : VideoStreamRequest, IMasterHlsRequest
|
||||
{
|
||||
public bool EnableAdaptiveBitrateStreaming { get; set; }
|
||||
|
@ -39,8 +37,6 @@ namespace MediaBrowser.Api.Playback.Hls
|
|||
}
|
||||
}
|
||||
|
||||
[Route("/Audio/{Id}/master.m3u8", "GET", Summary = "Gets an audio stream using HTTP live streaming.")]
|
||||
[Route("/Audio/{Id}/master.m3u8", "HEAD", Summary = "Gets an audio stream using HTTP live streaming.")]
|
||||
public class GetMasterHlsAudioPlaylist : StreamRequest, IMasterHlsRequest
|
||||
{
|
||||
public bool EnableAdaptiveBitrateStreaming { get; set; }
|
||||
|
@ -56,17 +52,14 @@ namespace MediaBrowser.Api.Playback.Hls
|
|||
bool EnableAdaptiveBitrateStreaming { get; set; }
|
||||
}
|
||||
|
||||
[Route("/Videos/{Id}/main.m3u8", "GET", Summary = "Gets a video stream using HTTP live streaming.")]
|
||||
public class GetVariantHlsVideoPlaylist : VideoStreamRequest
|
||||
{
|
||||
}
|
||||
|
||||
[Route("/Audio/{Id}/main.m3u8", "GET", Summary = "Gets an audio stream using HTTP live streaming.")]
|
||||
public class GetVariantHlsAudioPlaylist : StreamRequest
|
||||
{
|
||||
}
|
||||
|
||||
[Route("/Videos/{Id}/hls1/{PlaylistId}/{SegmentId}.{SegmentContainer}", "GET")]
|
||||
public class GetHlsVideoSegment : VideoStreamRequest
|
||||
{
|
||||
public string PlaylistId { get; set; }
|
||||
|
@ -78,7 +71,6 @@ namespace MediaBrowser.Api.Playback.Hls
|
|||
public string SegmentId { get; set; }
|
||||
}
|
||||
|
||||
[Route("/Audio/{Id}/hls1/{PlaylistId}/{SegmentId}.{SegmentContainer}", "GET")]
|
||||
public class GetHlsAudioSegment : StreamRequest
|
||||
{
|
||||
public string PlaylistId { get; set; }
|
||||
|
|
Loading…
Reference in New Issue
Block a user