Add stream limit check to VideosController direct video streaming

This commit is contained in:
Mahmoud Almontasser 2025-08-03 21:14:44 +02:00
parent 646ced7fbe
commit 944a17137e

View File

@ -10,6 +10,7 @@ using Jellyfin.Api.Attributes;
using Jellyfin.Api.Extensions; using Jellyfin.Api.Extensions;
using Jellyfin.Api.Helpers; using Jellyfin.Api.Helpers;
using Jellyfin.Api.ModelBinders; using Jellyfin.Api.ModelBinders;
using Jellyfin.Data.Enums;
using Jellyfin.Extensions; using Jellyfin.Extensions;
using MediaBrowser.Common.Api; using MediaBrowser.Common.Api;
using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Configuration;
@ -19,6 +20,7 @@ using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.Controller.Session;
using MediaBrowser.Controller.Streaming; using MediaBrowser.Controller.Streaming;
using MediaBrowser.Model.Dlna; using MediaBrowser.Model.Dlna;
using MediaBrowser.Model.Dto; using MediaBrowser.Model.Dto;
@ -46,6 +48,7 @@ public class VideosController : BaseJellyfinApiController
private readonly ITranscodeManager _transcodeManager; private readonly ITranscodeManager _transcodeManager;
private readonly IHttpClientFactory _httpClientFactory; private readonly IHttpClientFactory _httpClientFactory;
private readonly EncodingHelper _encodingHelper; private readonly EncodingHelper _encodingHelper;
private readonly ISessionManager _sessionManager;
private readonly TranscodingJobType _transcodingJobType = TranscodingJobType.Progressive; private readonly TranscodingJobType _transcodingJobType = TranscodingJobType.Progressive;
@ -61,6 +64,7 @@ public class VideosController : BaseJellyfinApiController
/// <param name="transcodeManager">Instance of the <see cref="ITranscodeManager"/> interface.</param> /// <param name="transcodeManager">Instance of the <see cref="ITranscodeManager"/> interface.</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>
/// <param name="sessionManager">Instance of the <see cref="ISessionManager"/> interface.</param>
public VideosController( public VideosController(
ILibraryManager libraryManager, ILibraryManager libraryManager,
IUserManager userManager, IUserManager userManager,
@ -70,7 +74,8 @@ public class VideosController : BaseJellyfinApiController
IMediaEncoder mediaEncoder, IMediaEncoder mediaEncoder,
ITranscodeManager transcodeManager, ITranscodeManager transcodeManager,
IHttpClientFactory httpClientFactory, IHttpClientFactory httpClientFactory,
EncodingHelper encodingHelper) EncodingHelper encodingHelper,
ISessionManager sessionManager)
{ {
_libraryManager = libraryManager; _libraryManager = libraryManager;
_userManager = userManager; _userManager = userManager;
@ -81,6 +86,7 @@ public class VideosController : BaseJellyfinApiController
_transcodeManager = transcodeManager; _transcodeManager = transcodeManager;
_httpClientFactory = httpClientFactory; _httpClientFactory = httpClientFactory;
_encodingHelper = encodingHelper; _encodingHelper = encodingHelper;
_sessionManager = sessionManager;
} }
/// <summary> /// <summary>
@ -439,6 +445,27 @@ public class VideosController : BaseJellyfinApiController
cancellationTokenSource.Token) cancellationTokenSource.Token)
.ConfigureAwait(false); .ConfigureAwait(false);
// Check video stream limits before starting transcoding
if (state.IsOutputVideo)
{
var userId = HttpContext.User.GetUserId();
if (!userId.IsEmpty())
{
var user = _userManager.GetUserById(userId);
if (user is not null && user.MaxActiveVideoStreams > 0)
{
var activeVideoStreams = _sessionManager.Sessions.Count(s =>
s.UserId.Equals(user.Id) &&
s.NowPlayingItem?.MediaType == MediaType.Video);
if (activeVideoStreams >= user.MaxActiveVideoStreams)
{
throw new MediaBrowser.Controller.Net.SecurityException($"User '{user.Username}' has reached their maximum number of concurrent video streams ({user.MaxActiveVideoStreams}).");
}
}
}
}
if (@static.HasValue && @static.Value && state.DirectStreamProvider is not null) if (@static.HasValue && @static.Value && state.DirectStreamProvider is not null)
{ {
var liveStreamInfo = _mediaSourceManager.GetLiveStreamInfo(streamingRequest.LiveStreamId); var liveStreamInfo = _mediaSourceManager.GetLiveStreamInfo(streamingRequest.LiveStreamId);