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)."); } }