From 7a0c1e44882d3796f2e4c91d992a6a092c340b5c Mon Sep 17 00:00:00 2001 From: CodeDevMLH <145071728+CodeDevMLH@users.noreply.github.com> Date: Thu, 19 Feb 2026 18:20:17 +0100 Subject: [PATCH] Enhance script injection by removing legacy tags and improving logging --- Injector_new.cs | 246 ++++++++++++++++++ .../ScriptInjector.cs | 65 ++++- 2 files changed, 300 insertions(+), 11 deletions(-) create mode 100644 Injector_new.cs diff --git a/Injector_new.cs b/Injector_new.cs new file mode 100644 index 0000000..0d5003c --- /dev/null +++ b/Injector_new.cs @@ -0,0 +1,246 @@ +using System; +using System.Reflection; +using System.IO; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.Loader; +using Microsoft.Extensions.Logging; +using Newtonsoft.Json.Linq; +using MediaBrowser.Common.Configuration; +using Jellyfin.Plugin.MediaBarEnhanced.Helpers; + +namespace Jellyfin.Plugin.MediaBarEnhanced +{ + /// + /// Handles the injection of the MediaBarEnhanced script into the Jellyfin web interface. + /// + public class ScriptInjector + { + private readonly IApplicationPaths _appPaths; + private readonly ILogger _logger; + public const string ScriptTag = ""; + public const string CssTag = ""; + public const string ScriptMarker = ""; + public const string CssMarker = ""; + + /// + /// Initializes a new instance of the class. + /// + /// The application paths. + /// The logger. + public ScriptInjector(IApplicationPaths appPaths, ILogger logger) + { + _appPaths = appPaths; + _logger = logger; + } + + /// + /// Injects the script tag into index.html if it's not already present. + /// + public void Inject() + { + try + { + var webPath = GetWebPath(); + if (string.IsNullOrEmpty(webPath)) + { + _logger.LogWarning("Could not find Jellyfin web path. Script injection skipped. Attempting fallback."); + RegisterFileTransformation(); + return; + } + + var indexPath = Path.Combine(webPath, "index.html"); + if (!File.Exists(indexPath)) + { + _logger.LogWarning("index.html not found at {Path}. Script injection skipped. Attempting fallback.", indexPath); + RegisterFileTransformation(); + return; + } + + var content = File.ReadAllText(indexPath); + var injectedJS = false; + var injectedCSS = false; + + if (!content.Contains(ScriptTag)) + { + var index = content.IndexOf(ScriptMarker, StringComparison.OrdinalIgnoreCase); + if (index != -1) + { + content = content.Insert(index, ScriptTag + Environment.NewLine); + injectedJS = true; + } + } + + if (!content.Contains(CssTag)) + { + var index = content.IndexOf(CssMarker, StringComparison.OrdinalIgnoreCase); + if (index != -1) + { + content = content.Insert(index, CssTag + Environment.NewLine); + injectedCSS = true; + } + } + + if (injectedJS && injectedCSS) + { + File.WriteAllText(indexPath, content); + _logger.LogInformation("MediaBarEnhanced script injected into index.html."); + } else if (injectedJS) + { + File.WriteAllText(indexPath, content); + _logger.LogInformation("MediaBarEnhanced JS script injected into index.html. But CSS was already present or could not be injected."); + } + else if (injectedCSS) + { + File.WriteAllText(indexPath, content); + _logger.LogInformation("MediaBarEnhanced CSS injected into index.html. But JS script was already present or could not be injected."); + } + else + { + _logger.LogInformation("MediaBarEnhanced script and CSS already present in index.html. Or could not be injected."); + } + } + catch (UnauthorizedAccessException) + { + _logger.LogWarning("Unauthorized access when attempting to inject script into index.html. Automatic injection failed. Attempting fallback now..."); + RegisterFileTransformation(); + } + catch (Exception ex) + { + _logger.LogError(ex, "Error injecting MediaBarEnhanced resources. Attempting fallback."); + RegisterFileTransformation(); + } + } + + /// + /// Removes the script tag from index.html. + /// + public void Remove() + { + UnregisterFileTransformation(); + + try + { + var webPath = GetWebPath(); + if (string.IsNullOrEmpty(webPath)) + { + return; + } + + var indexPath = Path.Combine(webPath, "index.html"); + if (!File.Exists(indexPath)) + { + return; + } + + var content = File.ReadAllText(indexPath); + var modified = false; + + if (content.Contains(ScriptTag)) + { + content = content.Replace(ScriptTag + Environment.NewLine, "").Replace(ScriptTag, ""); + modified = true; + } + + if (content.Contains(CssTag)) + { + content = content.Replace(CssTag + Environment.NewLine, "").Replace(CssTag, ""); + modified = true; + } + + if (modified) + { + File.WriteAllText(indexPath, content); + _logger.LogInformation("MediaBarEnhanced script removed from index.html."); + } else + { + _logger.LogInformation("MediaBarEnhanced script not found in index.html. No removal necessary."); + } + } + catch (UnauthorizedAccessException uaEx) + { + _logger.LogError(uaEx, "Unauthorized access when trying to remove MediaBarEnhanced script. Check file permissions."); + } + catch (Exception ex) + { + _logger.LogError(ex, "Error removing MediaBarEnhanced script."); + } + } + + private string? GetWebPath() + { + var prop = _appPaths.GetType().GetProperty("WebPath", BindingFlags.Instance | BindingFlags.Public); + return prop?.GetValue(_appPaths) as string; + } + + private void RegisterFileTransformation() + { + _logger.LogInformation("MediaBarEnhanced Fallback. Registering file transformations."); + + List payloads = new List(); + + { + JObject payload = new JObject(); + payload.Add("id", "0dfac9d7-d898-4944-900b-1c1837707279"); + payload.Add("fileNamePattern", "index.html"); + payload.Add("callbackAssembly", GetType().Assembly.FullName); + payload.Add("callbackClass", typeof(TransformationPatches).FullName); + payload.Add("callbackMethod", nameof(TransformationPatches.IndexHtml)); + + payloads.Add(payload); + } + + Assembly? fileTransformationAssembly = + AssemblyLoadContext.All.SelectMany(x => x.Assemblies).FirstOrDefault(x => + x.FullName?.Contains(".FileTransformation") ?? false); + + if (fileTransformationAssembly != null) + { + Type? pluginInterfaceType = fileTransformationAssembly.GetType("Jellyfin.Plugin.FileTransformation.PluginInterface"); + + if (pluginInterfaceType != null) + { + foreach (JObject payload in payloads) + { + pluginInterfaceType.GetMethod("RegisterTransformation")?.Invoke(null, new object?[] { payload }); + } + _logger.LogInformation("File transformations registered successfully."); + } + else + { + _logger.LogWarning("FileTransformation plugin found but PluginInterface type missing."); + } + } + else + { + _logger.LogWarning("FileTransformation plugin assembly not found. Fallback failed."); + } + } + + private void UnregisterFileTransformation() + { + try + { + Assembly? fileTransformationAssembly = + AssemblyLoadContext.All.SelectMany(x => x.Assemblies).FirstOrDefault(x => + x.FullName?.Contains(".FileTransformation") ?? false); + + if (fileTransformationAssembly != null) + { + Type? pluginInterfaceType = fileTransformationAssembly.GetType("Jellyfin.Plugin.FileTransformation.PluginInterface"); + + if (pluginInterfaceType != null) + { + Guid id = Guid.Parse("0dfac9d7-d898-4944-900b-1c1837707279"); + pluginInterfaceType.GetMethod("RemoveTransformation")?.Invoke(null, new object?[] { id }); + _logger.LogInformation("File transformation unregistered successfully."); + } + } + } + catch (Exception ex) + { + _logger.LogWarning(ex, "Error attempting to unregister file transformation. It might not have been registered."); + } + } + } +} \ No newline at end of file diff --git a/Jellyfin.Plugin.MediaBarEnhanced/ScriptInjector.cs b/Jellyfin.Plugin.MediaBarEnhanced/ScriptInjector.cs index f01ff58..1b3bdd6 100644 --- a/Jellyfin.Plugin.MediaBarEnhanced/ScriptInjector.cs +++ b/Jellyfin.Plugin.MediaBarEnhanced/ScriptInjector.cs @@ -60,6 +60,11 @@ namespace Jellyfin.Plugin.MediaBarEnhanced var content = File.ReadAllText(indexPath); var injectedJS = false; var injectedCSS = false; + var modified = false; + + // Cleanup legacy tags first to avoid duplicates or conflicts + content = RemoveLegacyTags(content, ref modified); + if (!content.Contains(ScriptTag)) { @@ -81,19 +86,26 @@ namespace Jellyfin.Plugin.MediaBarEnhanced } } - if (injectedJS && injectedCSS) + if (injectedJS || injectedCSS || modified) { File.WriteAllText(indexPath, content); - _logger.LogInformation("MediaBarEnhanced script injected into index.html."); - } else if (injectedJS) - { - File.WriteAllText(indexPath, content); - _logger.LogInformation("MediaBarEnhanced JS script injected into index.html. But CSS was already present or could not be injected."); - } - else if (injectedCSS) - { - File.WriteAllText(indexPath, content); - _logger.LogInformation("MediaBarEnhanced CSS injected into index.html. But JS script was already present or could not be injected."); + + if (injectedJS && injectedCSS) + { + _logger.LogInformation("MediaBarEnhanced script injected into index.html."); + } + else if (injectedJS) + { + _logger.LogInformation("MediaBarEnhanced JS script injected into index.html. But CSS was already present or could not be injected."); + } + else if (injectedCSS) + { + _logger.LogInformation("MediaBarEnhanced CSS injected into index.html. But JS script was already present or could not be injected."); + } + else + { + _logger.LogInformation("MediaBarEnhanced script and CSS already present. Legacy tags removed if found."); + } } else { @@ -148,6 +160,9 @@ namespace Jellyfin.Plugin.MediaBarEnhanced modified = true; } + // Remove legacy tags + content = RemoveLegacyTags(content, ref modified); + if (modified) { File.WriteAllText(indexPath, content); @@ -242,5 +257,33 @@ namespace Jellyfin.Plugin.MediaBarEnhanced _logger.LogWarning(ex, "Error attempting to unregister file transformation. It might not have been registered."); } } + /// + /// Removes legacy script and css tags from the content. + /// + /// The file content. + /// Ref bool to track if changes were made. + /// The modified content. + private string RemoveLegacyTags(string content, ref bool modified) + { + // Legacy tags (used in versions prior to 1.6.3.0 where paths started with / instead of ../) + const string LegacyScriptTag = ""; + const string LegacyCssTag = ""; + + if (content.Contains(LegacyScriptTag)) + { + content = content.Replace(LegacyScriptTag + Environment.NewLine, "").Replace(LegacyScriptTag, ""); + modified = true; + _logger.LogInformation("Legacy MediaBarEnhanced script tag removed."); + } + + if (content.Contains(LegacyCssTag)) + { + content = content.Replace(LegacyCssTag + Environment.NewLine, "").Replace(LegacyCssTag, ""); + modified = true; + _logger.LogInformation("Legacy MediaBarEnhanced CSS tag removed."); + } + + return content; + } } }