From bb6310381a7616ec4603a29ce28ca1eda93b1ec1 Mon Sep 17 00:00:00 2001 From: CodeDevMLH <145071728+CodeDevMLH@users.noreply.github.com> Date: Mon, 9 Mar 2026 04:02:17 +0100 Subject: [PATCH] Refactor overlay image handling and improve safety checks for plugin configuration --- .../Api/OverlayImageController.cs | 22 +++++++++---------- .../Helpers/TransformationPatches.cs | 2 +- .../MediaBarEnhancedPlugin.cs | 1 - 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/Jellyfin.Plugin.MediaBarEnhanced/Api/OverlayImageController.cs b/Jellyfin.Plugin.MediaBarEnhanced/Api/OverlayImageController.cs index 31a8a49..cb80d67 100644 --- a/Jellyfin.Plugin.MediaBarEnhanced/Api/OverlayImageController.cs +++ b/Jellyfin.Plugin.MediaBarEnhanced/Api/OverlayImageController.cs @@ -23,7 +23,7 @@ namespace Jellyfin.Plugin.MediaBarEnhanced.Api _applicationPaths = applicationPaths; // We use the plugin's data folder to store the image - _imageDirectory = Path.Combine(_applicationPaths.PluginConfigurationPath, "MediaBarEnhanced"); + _imageDirectory = MediaBarEnhancedPlugin.Instance?.DataFolderPath ?? Path.Combine(applicationPaths.DataPath, "plugins", "MediaBarEnhanced"); // We'll just overwrite this single file each time _imagePath = Path.Combine(_imageDirectory, "custom_overlay_image.dat"); @@ -48,13 +48,10 @@ namespace Jellyfin.Plugin.MediaBarEnhanced.Api Directory.CreateDirectory(_imageDirectory); } - // Delete the old one if it exists to ensure freshness - if (System.IO.File.Exists(_imagePath)) - { - System.IO.File.Delete(_imagePath); - } - - using (var stream = new FileStream(_imagePath, FileMode.Create)) + // Delete is not strictly necessary and can cause locking issues if someone is currently reading it. + // FileMode.Create will truncate the file if it exists, effectively overwriting it. + // We use FileShare.None to ensure we have exclusive write access, but handle potential IOExceptions gracefully. + using (var stream = new FileStream(_imagePath, FileMode.Create, FileAccess.Write, FileShare.None)) { await file.CopyToAsync(stream).ConfigureAwait(false); } @@ -80,9 +77,12 @@ namespace Jellyfin.Plugin.MediaBarEnhanced.Api return NotFound(); } - // Read the file and return as a generic octet stream, since we don't strictly track the mime type - // The browser will figure out it's an image - var stream = new FileStream(_imagePath, FileMode.Open, FileAccess.Read, FileShare.Read); + // Read the file and return as a generic octet stream. + // We use FileShare.ReadWrite so that if someone is currently overwriting the file (uploading), we don't block them, + // and we also don't get blocked by other readers. + var stream = new FileStream(_imagePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); + + // "image/*" works reliably as browsers will sniff the exact image mime type (jpeg, png, webp). return File(stream, "image/*"); } } diff --git a/Jellyfin.Plugin.MediaBarEnhanced/Helpers/TransformationPatches.cs b/Jellyfin.Plugin.MediaBarEnhanced/Helpers/TransformationPatches.cs index 03ffed8..47ba5ef 100644 --- a/Jellyfin.Plugin.MediaBarEnhanced/Helpers/TransformationPatches.cs +++ b/Jellyfin.Plugin.MediaBarEnhanced/Helpers/TransformationPatches.cs @@ -18,7 +18,7 @@ namespace Jellyfin.Plugin.MediaBarEnhanced.Helpers try { // Safety Check: If plugin is disabled, do nothing - if (!MediaBarEnhancedPlugin.Instance.Configuration.IsEnabled) + if (MediaBarEnhancedPlugin.Instance?.Configuration?.IsEnabled != true) { return originalContents; } diff --git a/Jellyfin.Plugin.MediaBarEnhanced/MediaBarEnhancedPlugin.cs b/Jellyfin.Plugin.MediaBarEnhanced/MediaBarEnhancedPlugin.cs index 96d7dd9..2104c0a 100644 --- a/Jellyfin.Plugin.MediaBarEnhanced/MediaBarEnhancedPlugin.cs +++ b/Jellyfin.Plugin.MediaBarEnhanced/MediaBarEnhancedPlugin.cs @@ -17,7 +17,6 @@ namespace Jellyfin.Plugin.MediaBarEnhanced { private readonly ScriptInjector _scriptInjector; private readonly ILoggerFactory _loggerFactory; - public IServiceProvider ServiceProvider { get; } /// /// Initializes a new instance of the class.