Deletes the on-disk index.html injection rather than leaving it switched off. Plugin.cs had already stopped calling it, but an unreachable write path with a live signature is the one a later refactor re-enables by accident, and it was still the behaviour the README and the release changelog advertised. Patching index.html on disk is destructive in ways a plugin cannot clean up after: the patch outlives an uninstall, a web-client upgrade discards it silently, and it races any other plugin touching the same file. It is also a second code path, and the one nobody runs is the one that rots. WebClientPatchService is now removal-only. The strip is factored out as RemoveInjection so it is testable without a filesystem. Removal is the one write JR-021 permits -- an earlier JRay did patch the file, and those users must not be left with a stale injection pointing at endpoints that have since changed. It keys on JRay's own marker, so it touches nothing another plugin added. JR-021 is a requirement to *not do* something, which no unit test can demonstrate, so scripts/checks/no-index-injection.sh verifies it by absence. The check was confirmed to fail on a reintroduced Apply() and on reintroduced ReplaceLast injection -- a check that has only ever passed is not evidence. Jellyfin has no plugin dependency mechanism, so nothing installs File Transformation for the user and a log warning alone is one nobody reads. GET /Plugins/JRay/Status/Dependencies reports whether the dependency is satisfied, and the configuration page renders it with the repository URL and what to do with it. Absent the plugin only the overlay is disabled; every other feature works. JR-022 and JR-023 stay In Progress rather than Done: neither has a test that executes, and this repo has no test project yet. TRACES: JR-021, JR-022, JR-023 | PR-004 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
89 lines
3.6 KiB
C#
89 lines
3.6 KiB
C#
using System;
|
|
using System.IO;
|
|
using MediaBrowser.Common.Configuration;
|
|
using Microsoft.Extensions.Logging;
|
|
|
|
namespace Jellyfin.Plugin.JRay.Services;
|
|
|
|
/// <summary>
|
|
/// Removes the pause-overlay script tag that an earlier version of JRay
|
|
/// injected into the web client's <c>index.html</c> on disk.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <b>This class cannot inject.</b> JRay reaches the web client only through
|
|
/// <see cref="FileTransformationRegistration"/>, which rewrites
|
|
/// <c>index.html</c> as it is served. Patching the file on disk was removed
|
|
/// rather than left switched off: the patch outlives an uninstall, a web-client
|
|
/// upgrade discards it silently, and it races any other plugin patching the same
|
|
/// file. An unreachable write path is also the one nobody runs, which is the one
|
|
/// a later refactor re-enables by accident.
|
|
///
|
|
/// Removal remains because users upgrading from a version that did patch the
|
|
/// file must not be left with a stale injection pointing at endpoints that have
|
|
/// since changed. It keys on JRay's own <c><!-- jray-overlay --></c>
|
|
/// marker, so it is unambiguous and touches nothing another plugin added.
|
|
/// </remarks>
|
|
// TRACES: JR-021, JR-022 | PR-004
|
|
public static class WebClientPatchService
|
|
{
|
|
private const string Marker = "<!-- jray-overlay -->";
|
|
private const string ScriptTag = "<script defer src=\"/Plugins/JRay/ClientScript\"></script>";
|
|
|
|
/// <summary>
|
|
/// Removes a legacy on-disk overlay injection, if one is present. Safe to
|
|
/// call on every startup: it is a no-op once the marker is gone.
|
|
/// </summary>
|
|
/// <param name="applicationPaths">The Jellyfin application paths.</param>
|
|
/// <param name="logger">The logger.</param>
|
|
public static void RemoveLegacyPatch(IApplicationPaths applicationPaths, ILogger logger)
|
|
{
|
|
ArgumentNullException.ThrowIfNull(applicationPaths);
|
|
ArgumentNullException.ThrowIfNull(logger);
|
|
|
|
var indexPath = Path.Combine(applicationPaths.WebPath, "index.html");
|
|
|
|
try
|
|
{
|
|
if (!File.Exists(indexPath))
|
|
{
|
|
logger.LogDebug("JRay: web client index.html not found at {Path}", indexPath);
|
|
return;
|
|
}
|
|
|
|
var html = File.ReadAllText(indexPath);
|
|
if (!html.Contains(Marker, StringComparison.Ordinal))
|
|
{
|
|
return;
|
|
}
|
|
|
|
var cleaned = RemoveInjection(html);
|
|
File.WriteAllText(indexPath, cleaned);
|
|
logger.LogInformation(
|
|
"JRay: removed a pause-overlay script left in {Path} by an earlier version. "
|
|
+ "JRay no longer modifies this file; the overlay is served through File Transformation.",
|
|
indexPath);
|
|
}
|
|
catch (Exception ex) when (ex is IOException or UnauthorizedAccessException)
|
|
{
|
|
logger.LogWarning(ex, "JRay: failed to remove the legacy overlay patch from {Path}", indexPath);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Strips the marked script tag from the document.
|
|
/// </summary>
|
|
/// <param name="html">The document contents.</param>
|
|
/// <returns>The contents with JRay's injection removed.</returns>
|
|
internal static string RemoveInjection(string html)
|
|
{
|
|
ArgumentNullException.ThrowIfNull(html);
|
|
|
|
// The trailing newline is stripped with the tag when present, so removing
|
|
// a patch restores the document byte-for-byte rather than leaving a blank
|
|
// line that accumulates across upgrades.
|
|
return html
|
|
.Replace(ScriptTag + Marker + "\n", string.Empty, StringComparison.Ordinal)
|
|
.Replace(ScriptTag + Marker, string.Empty, StringComparison.Ordinal);
|
|
}
|
|
}
|