This commit is contained in:
CodeDevMLH
2025-12-15 11:27:06 +01:00
parent c867c892de
commit d88c967023
15 changed files with 215 additions and 130 deletions

View File

@@ -1,24 +1,35 @@
using System;
using System;
using System.IO;
using System.Linq;
using System.Reflection;
using Microsoft.Extensions.Logging;
using MediaBrowser.Common.Configuration;
namespace Jellyfin.Plugin.Seasonals;
/// <summary>
/// Handles the injection of the Seasonals script into the Jellyfin web interface.
/// </summary>
public class ScriptInjector
{
private readonly IApplicationPaths _appPaths;
private readonly ILogger<ScriptInjector> _logger;
private const string ScriptTag = "<script src=\"/Seasonals/Resources/seasonals.js\"></script>";
private const string ScriptTag = "<script src=\"Seasonals/Resources/seasonals.js\"></script>";
private const string Marker = "</body>";
/// <summary>
/// Initializes a new instance of the <see cref="ScriptInjector"/> class.
/// </summary>
/// <param name="appPaths">The application paths.</param>
/// <param name="logger">The logger.</param>
public ScriptInjector(IApplicationPaths appPaths, ILogger<ScriptInjector> logger)
{
_appPaths = appPaths;
_logger = logger;
}
/// <summary>
/// Injects the script tag into index.html if it's not already present.
/// </summary>
public void Inject()
{
try
@@ -38,14 +49,15 @@ public class ScriptInjector
}
var content = File.ReadAllText(indexPath);
if (content.Contains(ScriptTag))
if (content.Contains(ScriptTag, StringComparison.Ordinal))
{
_logger.LogInformation("Seasonals script already injected.");
return;
}
var newContent = content.Replace(Marker, $"{ScriptTag}\n{Marker}");
if (newContent == content)
// Insert before the closing body tag
var newContent = content.Replace(Marker, $"{ScriptTag}\n{Marker}", StringComparison.Ordinal);
if (string.Equals(newContent, content, StringComparison.Ordinal))
{
_logger.LogWarning("Could not find closing body tag in index.html. Script injection skipped.");
return;
@@ -60,20 +72,35 @@ public class ScriptInjector
}
}
/// <summary>
/// Removes the script tag from index.html.
/// </summary>
public void Remove()
{
try
{
var webPath = GetWebPath();
if (string.IsNullOrEmpty(webPath)) return;
if (string.IsNullOrEmpty(webPath))
{
return;
}
var indexPath = Path.Combine(webPath, "index.html");
if (!File.Exists(indexPath)) return;
if (!File.Exists(indexPath))
{
return;
}
var content = File.ReadAllText(indexPath);
if (!content.Contains(ScriptTag)) return;
if (!content.Contains(ScriptTag, StringComparison.Ordinal))
{
return;
}
var newContent = content.Replace(ScriptTag, "").Replace($"{ScriptTag}\n", "");
// Try to remove with newline first, then just the tag to ensure clean removal
var newContent = content.Replace($"{ScriptTag}\n", "", StringComparison.Ordinal)
.Replace(ScriptTag, "", StringComparison.Ordinal);
File.WriteAllText(indexPath, newContent);
_logger.LogInformation("Successfully removed Seasonals script from index.html.");
}
@@ -83,37 +110,14 @@ public class ScriptInjector
}
}
/// <summary>
/// Retrieves the path to the Jellyfin web interface directory.
/// </summary>
/// <returns>The path to the web directory, or null if not found.</returns>
private string? GetWebPath()
{
// Try to find the web path using IApplicationPaths
// Note: The property name might vary depending on the Jellyfin version,
// but usually it's accessible via the configuration or standard paths.
// For this plugin context, we'll try to rely on the standard path structure if IApplicationPaths doesn't expose it directly
// or if we need to infer it.
// In many Jellyfin versions, appPaths.WebPath is the property.
// However, since we are in a plugin, we might need to use reflection if the interface doesn't expose it in the reference assembly,
// or just assume it's there.
// Let's try to use the property if it exists.
// If the compilation fails, we will adjust.
// For now, we assume 'WebPath' is available on IApplicationPaths implementation
// but it might not be on the interface in the nuget package.
// Workaround: Check known locations if property is missing or use reflection.
// Attempt 1: Reflection to get WebPath property (safest if interface varies)
var prop = _appPaths.GetType().GetProperty("WebPath");
if (prop != null)
{
return prop.GetValue(_appPaths) as string;
}
// Attempt 2: Guess based on ProgramDataPath (common in Windows)
// Usually <ProgramData>/jellyfin/web or <InstallDir>/jellyfin-web
// Let's try to look relative to the application executable if possible, but that's hard from a plugin.
return null;
// Use reflection to access WebPath property to ensure compatibility across different Jellyfin versions
var prop = _appPaths.GetType().GetProperty("WebPath", BindingFlags.Instance | BindingFlags.Public);
return prop?.GetValue(_appPaths) as string;
}
}