From ec69c1c4dc3c86e662410505e8bc877c7c8fc630 Mon Sep 17 00:00:00 2001 From: lucapolesel Date: Fri, 25 Oct 2024 15:59:48 +0200 Subject: [PATCH] Update to .net 8 and support 10.9.11 --- .gitignore | 1 + BlockTranscoding/BlockTranscoding.cs | 223 ------------------ BlockTranscoding/BlockTranscoding.csproj | 9 +- .../Configuration/PluginConfiguration.cs | 2 +- BlockTranscoding/Plugin.cs | 8 +- BlockTranscoding/PluginServiceRegistrator.cs | 17 ++ BlockTranscoding/Services/BlockTranscoding.cs | 104 ++++++++ .../Utilities/ResolutionUtility.cs | 26 +- 8 files changed, 138 insertions(+), 252 deletions(-) delete mode 100644 BlockTranscoding/BlockTranscoding.cs create mode 100644 BlockTranscoding/PluginServiceRegistrator.cs create mode 100644 BlockTranscoding/Services/BlockTranscoding.cs diff --git a/.gitignore b/.gitignore index 0b72c24..c49a489 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ obj/ .vs/ .idea/ artifacts +*.DotSettings.user \ No newline at end of file diff --git a/BlockTranscoding/BlockTranscoding.cs b/BlockTranscoding/BlockTranscoding.cs deleted file mode 100644 index 5fe39ee..0000000 --- a/BlockTranscoding/BlockTranscoding.cs +++ /dev/null @@ -1,223 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; -using System.Timers; -using BlockTranscoding.Utilities; -using MediaBrowser.Common.Extensions; -using MediaBrowser.Controller.Library; -using MediaBrowser.Controller.Plugins; -using MediaBrowser.Controller.Session; -using MediaBrowser.Model.Entities; -using MediaBrowser.Model.Session; -using Microsoft.Extensions.Logging; - -namespace BlockTranscoding; - -/// -/// Automatically block content from transcoding. -/// -public class BlockTranscoding : IServerEntryPoint, IDisposable -{ - private readonly object _playbackStoppedCommandLock = new(); - - private readonly IUserDataManager _userDataManager; - private readonly ISessionManager _sessionManager; - private readonly ILoggerFactory _loggerFactory; - private readonly ILogger _logger; - - private readonly System.Timers.Timer _playbackTimer = new(1000); - - private readonly Dictionary _playbackStoppedCommand; - - /// - /// Initializes a new instance of the class. - /// - /// User data manager. - /// Session manager. - /// Logger factory. - public BlockTranscoding( - IUserDataManager userDataManager, - ISessionManager sessionManager, - ILoggerFactory loggerFactory) - { - _userDataManager = userDataManager; - _sessionManager = sessionManager; - _loggerFactory = loggerFactory; - _logger = loggerFactory.CreateLogger(); - _playbackStoppedCommand = new Dictionary(); - } - - /// - /// Subscribe to the PlaybackStart callback. - /// - /// Task completion. - public Task RunAsync() - { - _logger.LogInformation("Setting up BlockTranscoding"); - - _userDataManager.UserDataSaved += UserDataManager_UserDataSaved; - Plugin.Instance!.BlockTranscodingChanged += BlockTranscodingChanged; - - _playbackTimer.AutoReset = true; - _playbackTimer.Elapsed += PlaybackTimer_Elapsed; - - BlockTranscodingChanged(null, EventArgs.Empty); - - return Task.CompletedTask; - } - - private void BlockTranscodingChanged(object? sender, EventArgs e) - { - var newState = Plugin.Instance!.Configuration.BlockTranscoding; - - _logger.LogDebug("Setting playback timer enabled to {NewState}.", newState); - - _playbackTimer.Enabled = newState; - } - - private void UserDataManager_UserDataSaved(object? sender, UserDataSaveEventArgs e) - { - var itemId = e.Item.Id; - - if (e.SaveReason != UserDataSaveReason.PlaybackStart && e.SaveReason != UserDataSaveReason.PlaybackFinished) - { - return; - } - - // Lookup the session for this item. - SessionInfo? session = null; - - try - { - foreach (var needle in _sessionManager.Sessions) - { - if (needle.UserId == e.UserId && needle.NowPlayingItem?.Id == itemId) - { - session = needle; - break; - } - } - - if (session == null) - { - _logger.LogInformation("Unable to find session for {Item}", itemId); - return; - } - } - catch (Exception ex) when (ex is NullReferenceException || ex is ResourceNotFoundException) - { - return; - } - - // Reset the stop command state for this device. - lock (_playbackStoppedCommandLock) - { - var device = session.DeviceId; - - _logger.LogDebug("Resetting seek command state for session {Session}", device); - _playbackStoppedCommand[device] = false; - } - } - - private void PlaybackTimer_Elapsed(object? sender, ElapsedEventArgs e) - { - foreach (var session in _sessionManager.Sessions) - { - var deviceId = session.DeviceId; - var playingItem = session.NowPlayingItem; - - lock (_playbackStoppedCommandLock) - { - if (_playbackStoppedCommand.TryGetValue(deviceId, out var stopped) && stopped) - { - _logger.LogTrace("Already sent stop command for session {Session}", deviceId); - continue; - } - } - - // Check if it is actually a video - if (playingItem?.MediaType == "Video") - { - // Check if it is transcoding - if (session.PlayState.PlayMethod == PlayMethod.Transcode) - { - // Ignore if the video is not being transcoded - if (session.TranscodingInfo.IsVideoDirect) - { - continue; - } - - // Check if the video that is being transcoded is over the max allowed resolution - var maxRes = Plugin.Instance!.Configuration.MaxResolution; - var maxResSize = ResolutionUtility.GetSize(maxRes); - - if (playingItem.Width > maxResSize.Width || playingItem.Height > maxResSize.Height) - { - _sessionManager.SendPlaystateCommand( - session.Id, - session.Id, - new PlaystateRequest - { - Command = PlaystateCommand.Stop, - ControllingUserId = session.UserId.ToString("N"), - }, - CancellationToken.None); - - lock (_playbackStoppedCommandLock) - { - _logger.LogTrace("Setting stop command state for session {Session}", deviceId); - _playbackStoppedCommand[deviceId] = true; - } - - var customMessage = Plugin.Instance!.Configuration.CustomMessage; - - if (string.IsNullOrEmpty(customMessage)) - { - continue; - } - - // TODO: Maybe allow the admin to tell the user which resolution has been blocked. - - _sessionManager.SendMessageCommand( - session.Id, - session.Id, - new MessageCommand() - { - Header = string.Empty, - Text = customMessage, - TimeoutMs = 2000, - }, - CancellationToken.None); - } - } - } - } - } - - /// - /// Dispose. - /// - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - /// - /// Protected dispose. - /// - /// Dispose. - protected virtual void Dispose(bool disposing) - { - if (!disposing) - { - return; - } - - _userDataManager.UserDataSaved -= UserDataManager_UserDataSaved; - - _playbackTimer?.Stop(); - _playbackTimer?.Dispose(); - } -} diff --git a/BlockTranscoding/BlockTranscoding.csproj b/BlockTranscoding/BlockTranscoding.csproj index d7e8f9b..e39468c 100644 --- a/BlockTranscoding/BlockTranscoding.csproj +++ b/BlockTranscoding/BlockTranscoding.csproj @@ -1,7 +1,7 @@ - net6.0 + net8.0 BlockTranscoding true true @@ -11,11 +11,8 @@ - - - - - + + diff --git a/BlockTranscoding/Configuration/PluginConfiguration.cs b/BlockTranscoding/Configuration/PluginConfiguration.cs index 373d614..0b54f85 100644 --- a/BlockTranscoding/Configuration/PluginConfiguration.cs +++ b/BlockTranscoding/Configuration/PluginConfiguration.cs @@ -54,7 +54,7 @@ public PluginConfiguration() /// /// Gets or sets a value indicating whether the plugin should start blocking the playback. /// - public bool BlockTranscoding { get; set; } = false; + public bool BlockTranscoding { get; set; } /// /// Gets or sets a custom message when the playback gets stopped. diff --git a/BlockTranscoding/Plugin.cs b/BlockTranscoding/Plugin.cs index 8869357..ccf3723 100644 --- a/BlockTranscoding/Plugin.cs +++ b/BlockTranscoding/Plugin.cs @@ -46,14 +46,14 @@ public Plugin(IApplicationPaths applicationPaths, IXmlSerializer xmlSerializer) /// public IEnumerable GetPages() { - return new[] - { + return + [ new PluginPageInfo { Name = this.Name, EmbeddedResourcePath = string.Format(CultureInfo.InvariantCulture, "{0}.Configuration.configPage.html", GetType().Namespace) - } - }; + }, + ]; } private void OnConfigurationChanged(object? sender, BasePluginConfiguration e) diff --git a/BlockTranscoding/PluginServiceRegistrator.cs b/BlockTranscoding/PluginServiceRegistrator.cs new file mode 100644 index 0000000..ea8f038 --- /dev/null +++ b/BlockTranscoding/PluginServiceRegistrator.cs @@ -0,0 +1,17 @@ +using MediaBrowser.Controller; +using MediaBrowser.Controller.Plugins; +using Microsoft.Extensions.DependencyInjection; + +namespace BlockTranscoding; + +/// +/// Register BlockTranscoding services. +/// +public class PluginServiceRegistrator : IPluginServiceRegistrator +{ + /// + public void RegisterServices(IServiceCollection serviceCollection, IServerApplicationHost applicationHost) + { + serviceCollection.AddHostedService(); + } +} diff --git a/BlockTranscoding/Services/BlockTranscoding.cs b/BlockTranscoding/Services/BlockTranscoding.cs new file mode 100644 index 0000000..7acea17 --- /dev/null +++ b/BlockTranscoding/Services/BlockTranscoding.cs @@ -0,0 +1,104 @@ +using System.Threading; +using System.Threading.Tasks; +using BlockTranscoding.Utilities; +using Jellyfin.Data.Enums; +using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Session; +using MediaBrowser.Model.Session; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; + +namespace BlockTranscoding.Services; + +/// +/// Automatically block content from transcoding. +/// +public sealed class BlockTranscoding( + ILogger logger, + ISessionManager sessionManager) : IHostedService +{ + /// + /// Subscribe to the PlaybackProgress callback. + /// + /// The cancellation token. + /// Task completion. + public Task StartAsync(CancellationToken cancellationToken) + { + logger.LogInformation($"Setting up {nameof(BlockTranscoding)}.."); + + sessionManager.PlaybackProgress += OnPlaybackProgress; + + return Task.CompletedTask; + } + + /// + /// Unsubscribes from the PlaybackProgress callback. + /// + /// The cancellation token. + /// Task completion. + public Task StopAsync(CancellationToken cancellationToken) + { + sessionManager.PlaybackProgress -= OnPlaybackProgress; + + return Task.CompletedTask; + } + + private void OnPlaybackProgress(object? sender, PlaybackProgressEventArgs e) + { + // Check if we actually have to block any transcoding + if (!Plugin.Instance!.Configuration.BlockTranscoding) + { + return; + } + + var sessionId = e.Session.Id; + var sessionUserId = e.Session.UserId; + var playingItem = e.Session.NowPlayingItem; + var playState = e.Session.PlayState; + + // We only want to block video type + if (playingItem?.MediaType is not MediaType.Video) + { + return; + } + + // Check if it is actually transcoding + if (playState?.PlayMethod is not PlayMethod.Transcode) + { + return; + } + + // Check if the video that is being transcoded is over the max allowed resolution + var maxRes = Plugin.Instance.Configuration.MaxResolution; + var maxResSize = ResolutionUtility.GetSize(maxRes); + + // Make sure that the resolution does match + if (!(playingItem.Width > maxResSize.Width) && !(playingItem.Height > maxResSize.Height)) + { + return; + } + + // Send the stop command + sessionManager.SendPlaystateCommand( + sessionId, + sessionId, + new PlaystateRequest { Command = PlaystateCommand.Stop, ControllingUserId = sessionUserId.ToString("N") }, + CancellationToken.None); + + var customMessage = Plugin.Instance.Configuration.CustomMessage; + + if (string.IsNullOrEmpty(customMessage)) + { + return; + } + + // TODO: Maybe allow the admin to tell the user which resolution has been blocked. + + // Display a custom message after the video has been stopped + sessionManager.SendMessageCommand( + sessionId, + sessionId, + new MessageCommand { Header = string.Empty, Text = customMessage, TimeoutMs = 2000 }, + CancellationToken.None); + } +} diff --git a/BlockTranscoding/Utilities/ResolutionUtility.cs b/BlockTranscoding/Utilities/ResolutionUtility.cs index 43d90c6..0968aea 100644 --- a/BlockTranscoding/Utilities/ResolutionUtility.cs +++ b/BlockTranscoding/Utilities/ResolutionUtility.cs @@ -15,25 +15,15 @@ public static class ResolutionUtility /// Screen size. public static Size GetSize(Resolutions resolution) { - switch (resolution) + return resolution switch { - case Resolutions.StandardDefinition: - return new Size(640, 480); - - case Resolutions.HighDefinition: - return new Size(1280, 720); - - case Resolutions.FullHD: - return new Size(1920, 1080); - - case Resolutions.QuadHD: - return new Size(2560, 1440); - - case Resolutions.UltraHD: - return new Size(3840, 2160); - } - - return Size.Empty; + Resolutions.StandardDefinition => new Size(640, 480), + Resolutions.HighDefinition => new Size(1280, 720), + Resolutions.FullHD => new Size(1920, 1080), + Resolutions.QuadHD => new Size(2560, 1440), + Resolutions.UltraHD => new Size(3840, 2160), + _ => Size.Empty + }; } } }