diff options
| -rw-r--r-- | Emby.Server.Implementations/ApplicationHost.cs | 2 | ||||
| -rw-r--r-- | Emby.Server.Implementations/Security/AuthenticationRepository.cs | 4 | ||||
| -rw-r--r-- | Emby.Server.Implementations/Session/SessionManager.cs | 2 | ||||
| -rw-r--r-- | Jellyfin.Api/Controllers/DevicesController.cs | 14 | ||||
| -rw-r--r-- | Jellyfin.Server.Implementations/Devices/DeviceManager.cs (renamed from Emby.Server.Implementations/Devices/DeviceManager.cs) | 126 | ||||
| -rw-r--r-- | Jellyfin.Server/CoreAppHost.cs | 3 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Devices/IDeviceManager.cs | 9 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Security/IAuthenticationRepository.cs | 2 | ||||
| -rw-r--r-- | MediaBrowser.Model/Devices/DeviceOptions.cs | 9 |
9 files changed, 90 insertions, 81 deletions
diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index 3846de5fd..f2ed20fbc 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -644,8 +644,6 @@ namespace Emby.Server.Implementations ServiceCollection.AddSingleton<ITVSeriesManager, TVSeriesManager>(); - ServiceCollection.AddSingleton<IDeviceManager, DeviceManager>(); - ServiceCollection.AddSingleton<IMediaSourceManager, MediaSourceManager>(); ServiceCollection.AddSingleton<ISubtitleManager, SubtitleManager>(); diff --git a/Emby.Server.Implementations/Security/AuthenticationRepository.cs b/Emby.Server.Implementations/Security/AuthenticationRepository.cs index 4bc12f44a..0d0a2b1df 100644 --- a/Emby.Server.Implementations/Security/AuthenticationRepository.cs +++ b/Emby.Server.Implementations/Security/AuthenticationRepository.cs @@ -6,9 +6,9 @@ using System.Globalization; using System.IO; using System.Linq; using Emby.Server.Implementations.Data; +using Jellyfin.Data.Entities.Security; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Security; -using MediaBrowser.Model.Devices; using MediaBrowser.Model.Querying; using Microsoft.Extensions.Logging; using SQLitePCL.pretty; @@ -357,7 +357,7 @@ namespace Emby.Server.Implementations.Security { statement.TryBind("@DeviceId", deviceId); - var result = new DeviceOptions(); + var result = new DeviceOptions(deviceId); foreach (var row in statement.ExecuteQuery()) { diff --git a/Emby.Server.Implementations/Session/SessionManager.cs b/Emby.Server.Implementations/Session/SessionManager.cs index e06e48ca6..a47a1f56f 100644 --- a/Emby.Server.Implementations/Session/SessionManager.cs +++ b/Emby.Server.Implementations/Session/SessionManager.cs @@ -8,6 +8,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using Jellyfin.Data.Entities; +using Jellyfin.Data.Entities.Security; using Jellyfin.Data.Enums; using Jellyfin.Data.Events; using MediaBrowser.Common.Events; @@ -24,7 +25,6 @@ using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Net; using MediaBrowser.Controller.Security; using MediaBrowser.Controller.Session; -using MediaBrowser.Model.Devices; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Library; diff --git a/Jellyfin.Api/Controllers/DevicesController.cs b/Jellyfin.Api/Controllers/DevicesController.cs index b3e3490c2..3ca6488d9 100644 --- a/Jellyfin.Api/Controllers/DevicesController.cs +++ b/Jellyfin.Api/Controllers/DevicesController.cs @@ -1,6 +1,8 @@ using System; using System.ComponentModel.DataAnnotations; +using System.Threading.Tasks; using Jellyfin.Api.Constants; +using Jellyfin.Data.Entities.Security; using MediaBrowser.Controller.Devices; using MediaBrowser.Controller.Security; using MediaBrowser.Controller.Session; @@ -47,10 +49,10 @@ namespace Jellyfin.Api.Controllers /// <returns>An <see cref="OkResult"/> containing the list of devices.</returns> [HttpGet] [ProducesResponseType(StatusCodes.Status200OK)] - public ActionResult<QueryResult<DeviceInfo>> GetDevices([FromQuery] bool? supportsSync, [FromQuery] Guid? userId) + public async Task<ActionResult<QueryResult<DeviceInfo>>> GetDevices([FromQuery] bool? supportsSync, [FromQuery] Guid? userId) { var deviceQuery = new DeviceQuery { SupportsSync = supportsSync, UserId = userId ?? Guid.Empty }; - return _deviceManager.GetDevices(deviceQuery); + return await _deviceManager.GetDevices(deviceQuery); } /// <summary> @@ -63,9 +65,9 @@ namespace Jellyfin.Api.Controllers [HttpGet("Info")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] - public ActionResult<DeviceInfo> GetDeviceInfo([FromQuery, Required] string id) + public async Task<ActionResult<DeviceInfo>> GetDeviceInfo([FromQuery, Required] string id) { - var deviceInfo = _deviceManager.GetDevice(id); + var deviceInfo = await _deviceManager.GetDevice(id).ConfigureAwait(false); if (deviceInfo == null) { return NotFound(); @@ -106,7 +108,7 @@ namespace Jellyfin.Api.Controllers [HttpPost("Options")] [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status404NotFound)] - public ActionResult UpdateDeviceOptions( + public async Task<ActionResult> UpdateDeviceOptions( [FromQuery, Required] string id, [FromBody, Required] DeviceOptions deviceOptions) { @@ -116,7 +118,7 @@ namespace Jellyfin.Api.Controllers return NotFound(); } - _deviceManager.UpdateDeviceOptions(id, deviceOptions); + await _deviceManager.UpdateDeviceOptions(id, deviceOptions).ConfigureAwait(false); return NoContent(); } diff --git a/Emby.Server.Implementations/Devices/DeviceManager.cs b/Jellyfin.Server.Implementations/Devices/DeviceManager.cs index da5047d24..c942678d9 100644 --- a/Emby.Server.Implementations/Devices/DeviceManager.cs +++ b/Jellyfin.Server.Implementations/Devices/DeviceManager.cs @@ -1,78 +1,100 @@ -#pragma warning disable CS1591 - using System; using System.Collections.Concurrent; -using System.Collections.Generic; using System.Linq; +using System.Threading.Tasks; using Jellyfin.Data.Entities; +using Jellyfin.Data.Entities.Security; using Jellyfin.Data.Enums; using Jellyfin.Data.Events; using MediaBrowser.Controller.Devices; using MediaBrowser.Controller.Library; -using MediaBrowser.Controller.Security; using MediaBrowser.Model.Devices; using MediaBrowser.Model.Querying; using MediaBrowser.Model.Session; +using Microsoft.EntityFrameworkCore; -namespace Emby.Server.Implementations.Devices +namespace Jellyfin.Server.Implementations.Devices { public class DeviceManager : IDeviceManager { + private readonly JellyfinDbProvider _dbProvider; private readonly IUserManager _userManager; - private readonly IAuthenticationRepository _authRepo; private readonly ConcurrentDictionary<string, ClientCapabilities> _capabilitiesMap = new (); - public DeviceManager(IAuthenticationRepository authRepo, IUserManager userManager) + /// <summary> + /// Initializes a new instance of the <see cref="DeviceManager"/> class. + /// </summary> + /// <param name="dbProvider">The database provider.</param> + /// <param name="userManager">The user manager.</param> + public DeviceManager(JellyfinDbProvider dbProvider, IUserManager userManager) { + _dbProvider = dbProvider; _userManager = userManager; - _authRepo = authRepo; } - public event EventHandler<GenericEventArgs<Tuple<string, DeviceOptions>>> DeviceOptionsUpdated; + /// <inheritdoc /> + public event EventHandler<GenericEventArgs<Tuple<string, DeviceOptions>>>? DeviceOptionsUpdated; + /// <inheritdoc /> public void SaveCapabilities(string deviceId, ClientCapabilities capabilities) { _capabilitiesMap[deviceId] = capabilities; } - public void UpdateDeviceOptions(string deviceId, DeviceOptions options) + /// <inheritdoc /> + public async Task UpdateDeviceOptions(string deviceId, DeviceOptions options) { - _authRepo.UpdateDeviceOptions(deviceId, options); + await using var dbContext = _dbProvider.CreateContext(); + await dbContext.Database + .ExecuteSqlRawAsync($"UPDATE [DeviceOptions] SET [CustomName] = ${options.CustomName}") + .ConfigureAwait(false); DeviceOptionsUpdated?.Invoke(this, new GenericEventArgs<Tuple<string, DeviceOptions>>(new Tuple<string, DeviceOptions>(deviceId, options))); } - public DeviceOptions GetDeviceOptions(string deviceId) + /// <inheritdoc /> + public DeviceOptions? GetDeviceOptions(string deviceId) { - return _authRepo.GetDeviceOptions(deviceId); + using var dbContext = _dbProvider.CreateContext(); + return dbContext.DeviceOptions + .AsQueryable() + .FirstOrDefault(d => d.DeviceId == deviceId); } + /// <inheritdoc /> public ClientCapabilities GetCapabilities(string id) { - return _capabilitiesMap.TryGetValue(id, out ClientCapabilities result) + return _capabilitiesMap.TryGetValue(id, out ClientCapabilities? result) ? result : new ClientCapabilities(); } - public DeviceInfo GetDevice(string id) + /// <inheritdoc /> + public async Task<DeviceInfo?> GetDevice(string id) { - var session = _authRepo.Get(new AuthenticationInfoQuery - { - DeviceId = id - }).Items.FirstOrDefault(); - - var device = session == null ? null : ToDeviceInfo(session); - - return device; + await using var dbContext = _dbProvider.CreateContext(); + var device = await dbContext.Devices + .AsQueryable() + .Where(d => d.DeviceId == id) + .OrderByDescending(d => d.DateLastActivity) + .Include(d => d.User) + .FirstOrDefaultAsync() + .ConfigureAwait(false); + + var deviceInfo = device == null ? null : ToDeviceInfo(device); + + return deviceInfo; } - public QueryResult<DeviceInfo> GetDevices(DeviceQuery query) + /// <inheritdoc /> + public async Task<QueryResult<DeviceInfo>> GetDevices(DeviceQuery query) { - IEnumerable<AuthenticationInfo> sessions = _authRepo.Get(new AuthenticationInfoQuery - { - // UserId = query.UserId - HasUser = true - }).Items; + await using var dbContext = _dbProvider.CreateContext(); + var sessions = dbContext.Devices + .AsQueryable() + .OrderBy(d => d.DeviceId) + .ThenByDescending(d => d.DateLastActivity) + .AsAsyncEnumerable(); // TODO: DeviceQuery doesn't seem to be used from client. Not even Swagger. if (query.SupportsSync.HasValue) @@ -89,28 +111,12 @@ namespace Emby.Server.Implementations.Devices sessions = sessions.Where(i => CanAccessDevice(user, i.DeviceId)); } - var array = sessions.Select(ToDeviceInfo).ToArray(); + var array = await sessions.Select(ToDeviceInfo).ToArrayAsync(); return new QueryResult<DeviceInfo>(array); } - private DeviceInfo ToDeviceInfo(AuthenticationInfo authInfo) - { - var caps = GetCapabilities(authInfo.DeviceId); - - return new DeviceInfo - { - AppName = authInfo.AppName, - AppVersion = authInfo.AppVersion, - Id = authInfo.DeviceId, - LastUserId = authInfo.UserId, - LastUserName = authInfo.UserName, - Name = authInfo.DeviceName, - DateLastActivity = authInfo.DateLastActivity, - IconUrl = caps?.IconUrl - }; - } - + /// <inheritdoc /> public bool CanAccessDevice(User user, string deviceId) { if (user == null) @@ -128,17 +134,25 @@ namespace Emby.Server.Implementations.Devices return true; } - if (!user.GetPreference(PreferenceKind.EnabledDevices).Contains(deviceId, StringComparer.OrdinalIgnoreCase)) - { - var capabilities = GetCapabilities(deviceId); + return user.GetPreference(PreferenceKind.EnabledDevices).Contains(deviceId, StringComparer.OrdinalIgnoreCase) + || !GetCapabilities(deviceId).SupportsPersistentIdentifier; + } - if (capabilities != null && capabilities.SupportsPersistentIdentifier) - { - return false; - } - } + private DeviceInfo ToDeviceInfo(Device authInfo) + { + var caps = GetCapabilities(authInfo.DeviceId); - return true; + return new DeviceInfo + { + AppName = authInfo.AppName, + AppVersion = authInfo.AppVersion, + Id = authInfo.DeviceId, + LastUserId = authInfo.UserId, + LastUserName = authInfo.User.Username, + Name = authInfo.DeviceName, + DateLastActivity = authInfo.DateLastActivity, + IconUrl = caps.IconUrl + }; } } } diff --git a/Jellyfin.Server/CoreAppHost.cs b/Jellyfin.Server/CoreAppHost.cs index 94c3ca4a9..b20acae32 100644 --- a/Jellyfin.Server/CoreAppHost.cs +++ b/Jellyfin.Server/CoreAppHost.cs @@ -9,10 +9,12 @@ using Jellyfin.Api.WebSocketListeners; using Jellyfin.Drawing.Skia; using Jellyfin.Server.Implementations; using Jellyfin.Server.Implementations.Activity; +using Jellyfin.Server.Implementations.Devices; using Jellyfin.Server.Implementations.Events; using Jellyfin.Server.Implementations.Users; using MediaBrowser.Controller; using MediaBrowser.Controller.BaseItemManager; +using MediaBrowser.Controller.Devices; using MediaBrowser.Controller.Drawing; using MediaBrowser.Controller.Events; using MediaBrowser.Controller.Library; @@ -84,6 +86,7 @@ namespace Jellyfin.Server ServiceCollection.AddSingleton<IActivityManager, ActivityManager>(); ServiceCollection.AddSingleton<IUserManager, UserManager>(); ServiceCollection.AddSingleton<IDisplayPreferencesManager, DisplayPreferencesManager>(); + ServiceCollection.AddSingleton<IDeviceManager, DeviceManager>(); // TODO search the assemblies instead of adding them manually? ServiceCollection.AddSingleton<IWebSocketListener, SessionWebSocketListener>(); diff --git a/MediaBrowser.Controller/Devices/IDeviceManager.cs b/MediaBrowser.Controller/Devices/IDeviceManager.cs index 8f0872dba..aa05ead8f 100644 --- a/MediaBrowser.Controller/Devices/IDeviceManager.cs +++ b/MediaBrowser.Controller/Devices/IDeviceManager.cs @@ -1,7 +1,9 @@ #pragma warning disable CS1591 using System; +using System.Threading.Tasks; using Jellyfin.Data.Entities; +using Jellyfin.Data.Entities.Security; using Jellyfin.Data.Events; using MediaBrowser.Model.Devices; using MediaBrowser.Model.Querying; @@ -18,7 +20,6 @@ namespace MediaBrowser.Controller.Devices /// </summary> /// <param name="reportedId">The reported identifier.</param> /// <param name="capabilities">The capabilities.</param> - /// <returns>Task.</returns> void SaveCapabilities(string reportedId, ClientCapabilities capabilities); /// <summary> @@ -33,21 +34,21 @@ namespace MediaBrowser.Controller.Devices /// </summary> /// <param name="id">The identifier.</param> /// <returns>DeviceInfo.</returns> - DeviceInfo GetDevice(string id); + Task<DeviceInfo> GetDevice(string id); /// <summary> /// Gets the devices. /// </summary> /// <param name="query">The query.</param> /// <returns>IEnumerable<DeviceInfo>.</returns> - QueryResult<DeviceInfo> GetDevices(DeviceQuery query); + Task<QueryResult<DeviceInfo>> GetDevices(DeviceQuery query); /// <summary> /// Determines whether this instance [can access device] the specified user identifier. /// </summary> bool CanAccessDevice(User user, string deviceId); - void UpdateDeviceOptions(string deviceId, DeviceOptions options); + Task UpdateDeviceOptions(string deviceId, DeviceOptions options); DeviceOptions GetDeviceOptions(string deviceId); } diff --git a/MediaBrowser.Controller/Security/IAuthenticationRepository.cs b/MediaBrowser.Controller/Security/IAuthenticationRepository.cs index 883b74165..27f281b71 100644 --- a/MediaBrowser.Controller/Security/IAuthenticationRepository.cs +++ b/MediaBrowser.Controller/Security/IAuthenticationRepository.cs @@ -1,6 +1,6 @@ #pragma warning disable CS1591 -using MediaBrowser.Model.Devices; +using Jellyfin.Data.Entities.Security; using MediaBrowser.Model.Querying; namespace MediaBrowser.Controller.Security diff --git a/MediaBrowser.Model/Devices/DeviceOptions.cs b/MediaBrowser.Model/Devices/DeviceOptions.cs deleted file mode 100644 index 037ffeb5e..000000000 --- a/MediaBrowser.Model/Devices/DeviceOptions.cs +++ /dev/null @@ -1,9 +0,0 @@ -#pragma warning disable CS1591 - -namespace MediaBrowser.Model.Devices -{ - public class DeviceOptions - { - public string? CustomName { get; set; } - } -} |
