using System; using System.Collections.Generic; using System.Threading.Tasks; using Jellyfin.Database.Implementations.Entities; using MediaBrowser.Controller.Library; namespace Jellyfin.Plugin.WatchedTogether.Compat; /// /// Papers over the differences between Jellyfin 10.11 and 12. /// /// /// /// Jellyfin 12 turned the Users and UsersIds properties into methods and made /// ChangePassword take a user id instead of a user. The plugin is compiled once per server /// generation (see the project file), and this is the only place that needs to know which one it /// is building for, so the rest of the code reads the same either way. /// /// /// Jellyfin 12 also dropped the in-memory user cache: every lookup returns a detached copy, and /// copies every column from the instance it is given. /// Callers that mutate a user and save it must therefore work with a fresh copy, which is why /// carries the stored hash back onto the caller's instance. /// /// internal static class UserManagerCompat { /// /// Gets every user on the server. /// /// The user manager. /// All users. public static IEnumerable GetAllUsers(this IUserManager userManager) { ArgumentNullException.ThrowIfNull(userManager); #if JELLYFIN_12 return userManager.GetUsers(); #else return userManager.Users; #endif } /// /// Gets the id of every user on the server. /// /// The user manager. /// All user ids. public static IEnumerable GetAllUserIds(this IUserManager userManager) { ArgumentNullException.ThrowIfNull(userManager); #if JELLYFIN_12 return userManager.GetUsersIds(); #else return userManager.UsersIds; #endif } /// /// Changes a user's password through the provider the user is currently assigned to. /// /// The user manager. /// The user whose password to change. /// The new password. /// A task representing the change. /// /// On return carries the newly stored hash on both server generations, /// so a subsequent with the same instance keeps it. /// public static async Task ChangePasswordAsync(this IUserManager userManager, User user, string newPassword) { ArgumentNullException.ThrowIfNull(userManager); ArgumentNullException.ThrowIfNull(user); #if JELLYFIN_12 await userManager.ChangePassword(user.Id, newPassword).ConfigureAwait(false); // 12 loaded and saved its own copy; without this the caller's instance still says "no // password" and the next UpdateUserAsync would write that back over the stored hash. var stored = userManager.GetUserById(user.Id); if (stored is not null) { user.Password = stored.Password; } #else await userManager.ChangePassword(user, newPassword).ConfigureAwait(false); #endif } }