using System; using System.IO; using System.Linq; using Microsoft.Extensions.Logging; using MediaBrowser.Common.Configuration; namespace Jellyfin.Plugin.Seasonals; public class ScriptInjector { private readonly IApplicationPaths _appPaths; private readonly ILogger _logger; private const string ScriptTag = ""; private const string Marker = ""; public ScriptInjector(IApplicationPaths appPaths, ILogger logger) { _appPaths = appPaths; _logger = logger; } public void Inject() { try { var webPath = GetWebPath(); if (string.IsNullOrEmpty(webPath)) { _logger.LogWarning("Could not find Jellyfin web path. Script injection skipped."); return; } var indexPath = Path.Combine(webPath, "index.html"); if (!File.Exists(indexPath)) { _logger.LogWarning("index.html not found at {Path}. Script injection skipped.", indexPath); return; } var content = File.ReadAllText(indexPath); if (content.Contains(ScriptTag)) { _logger.LogInformation("Seasonals script already injected."); return; } var newContent = content.Replace(Marker, $"{ScriptTag}\n{Marker}"); if (newContent == content) { _logger.LogWarning("Could not find closing body tag in index.html. Script injection skipped."); return; } File.WriteAllText(indexPath, newContent); _logger.LogInformation("Successfully injected Seasonals script into index.html."); } catch (Exception ex) { _logger.LogError(ex, "Error injecting Seasonals script."); } } public void Remove() { 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); if (!content.Contains(ScriptTag)) return; var newContent = content.Replace(ScriptTag, "").Replace($"{ScriptTag}\n", ""); File.WriteAllText(indexPath, newContent); _logger.LogInformation("Successfully removed Seasonals script from index.html."); } catch (Exception ex) { _logger.LogError(ex, "Error removing Seasonals script."); } } 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 /jellyfin/web or /jellyfin-web // Let's try to look relative to the application executable if possible, but that's hard from a plugin. return null; } }