using System;
using System.Reflection;
using System.Threading.Tasks;
using Jellyfin.Database.Implementations.Entities;
using MediaBrowser.Controller.Library;
namespace Jellyfin.Plugin.ShareLinks.Services;
///
/// Binds IUserManager.ChangePassword at runtime instead of at compile time.
///
internal static class UserManagerCompat
{
// Jellyfin 10.11.9 changed ChangePassword's parameter from the User itself to its Guid id.
// The plugin compiles against 10.11.0 but has to load on servers both before and after that
// change, and a call compiled against either signature throws MissingMethodException on a
// server that only has the other one. Resolving the method once with reflection and calling
// it through a delegate lets the plugin bind to whichever overload the running server has.
private static readonly Lazy> ChangePasswordInvoker =
new(ResolveChangePassword);
///
/// Changes a user's password, binding to whichever IUserManager.ChangePassword
/// overload the running Jellyfin server exposes.
///
/// The user manager to invoke.
/// The user whose password is being changed.
/// The new password.
/// A task that completes when the password has been changed.
public static Task ChangePasswordAsync(this IUserManager userManager, User user, string newPassword)
{
ArgumentNullException.ThrowIfNull(userManager);
ArgumentNullException.ThrowIfNull(user);
return ChangePasswordInvoker.Value(userManager, user, newPassword);
}
/// Resolves the available ChangePassword overload into a single callable shape.
private static Func ResolveChangePassword()
{
// Prefer the current (10.11.9+) overload first.
var guidOverload = typeof(IUserManager).GetMethod(
nameof(IUserManager.ChangePassword),
new[] { typeof(Guid), typeof(string) });
if (guidOverload is not null)
{
var call = guidOverload.CreateDelegate>();
return (manager, user, password) => call(manager, user.Id, password);
}
// Fall back to the older (10.11.0 - 10.11.8) overload.
var userOverload = typeof(IUserManager).GetMethod(
nameof(IUserManager.ChangePassword),
new[] { typeof(User), typeof(string) });
if (userOverload is not null)
{
return userOverload.CreateDelegate>();
}
return (_, _, _) => throw new InvalidOperationException(
"This Jellyfin version has neither IUserManager.ChangePassword(Guid, string) nor ChangePassword(User, string).");
}
}