From c601def4847cb0ada323a9da8d152c8c8d7b834b Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Fri, 17 Jan 2020 00:19:58 +0100 Subject: Fix warnings in SessionManager --- Emby.Server.Implementations/ApplicationHost.cs | 13 +- .../Session/SessionManager.cs | 274 +++++++++++---------- 2 files changed, 156 insertions(+), 131 deletions(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index 0bb1d832f..e93337c2f 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -808,7 +808,18 @@ namespace Emby.Server.Implementations ChannelManager = new ChannelManager(UserManager, DtoService, LibraryManager, LoggerFactory, ServerConfigurationManager, FileSystemManager, UserDataManager, JsonSerializer, ProviderManager); serviceCollection.AddSingleton(ChannelManager); - SessionManager = new SessionManager(UserDataManager, LoggerFactory, LibraryManager, UserManager, musicManager, DtoService, ImageProcessor, this, AuthenticationRepository, DeviceManager, MediaSourceManager); + SessionManager = new SessionManager( + LoggerFactory.CreateLogger(), + UserDataManager, + LibraryManager, + UserManager, + musicManager, + DtoService, + ImageProcessor, + this, + AuthenticationRepository, + DeviceManager, + MediaSourceManager); serviceCollection.AddSingleton(SessionManager); serviceCollection.AddSingleton( diff --git a/Emby.Server.Implementations/Session/SessionManager.cs b/Emby.Server.Implementations/Session/SessionManager.cs index b1d513dd4..bb0836614 100644 --- a/Emby.Server.Implementations/Session/SessionManager.cs +++ b/Emby.Server.Implementations/Session/SessionManager.cs @@ -30,17 +30,17 @@ using Microsoft.Extensions.Logging; namespace Emby.Server.Implementations.Session { /// - /// Class SessionManager + /// Class SessionManager. /// public class SessionManager : ISessionManager, IDisposable { /// - /// The _user data repository + /// The _user data repository. /// private readonly IUserDataManager _userDataManager; /// - /// The _logger + /// The _logger. /// private readonly ILogger _logger; @@ -57,36 +57,19 @@ namespace Emby.Server.Implementations.Session private readonly IDeviceManager _deviceManager; /// - /// The _active connections + /// The _active connections. /// private readonly ConcurrentDictionary _activeConnections = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); - public event EventHandler> AuthenticationFailed; - - public event EventHandler> AuthenticationSucceeded; - - /// - /// Occurs when [playback start]. - /// - public event EventHandler PlaybackStart; - /// - /// Occurs when [playback progress]. - /// - public event EventHandler PlaybackProgress; - /// - /// Occurs when [playback stopped]. - /// - public event EventHandler PlaybackStopped; + private Timer _idleTimer; - public event EventHandler SessionStarted; - public event EventHandler CapabilitiesChanged; - public event EventHandler SessionEnded; - public event EventHandler SessionActivity; + private DtoOptions _itemInfoDtoOptions; + private bool _disposed = false; public SessionManager( + ILogger logger, IUserDataManager userDataManager, - ILoggerFactory loggerFactory, ILibraryManager libraryManager, IUserManager userManager, IMusicManager musicManager, @@ -97,8 +80,8 @@ namespace Emby.Server.Implementations.Session IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager) { + _logger = logger; _userDataManager = userDataManager; - _logger = loggerFactory.CreateLogger(nameof(SessionManager)); _libraryManager = libraryManager; _userManager = userManager; _musicManager = musicManager; @@ -108,9 +91,49 @@ namespace Emby.Server.Implementations.Session _authRepo = authRepo; _deviceManager = deviceManager; _mediaSourceManager = mediaSourceManager; + _deviceManager.DeviceOptionsUpdated += OnDeviceManagerDeviceOptionsUpdated; } + /// + public event EventHandler> AuthenticationFailed; + + /// + public event EventHandler> AuthenticationSucceeded; + + /// + /// Occurs when [playback start]. + /// + public event EventHandler PlaybackStart; + + /// + /// Occurs when [playback progress]. + /// + public event EventHandler PlaybackProgress; + + /// + /// Occurs when [playback stopped]. + /// + public event EventHandler PlaybackStopped; + + /// + public event EventHandler SessionStarted; + + /// + public event EventHandler CapabilitiesChanged; + + /// + public event EventHandler SessionEnded; + + /// + public event EventHandler SessionActivity; + + /// + /// Gets all connections. + /// + /// All connections. + public IEnumerable Sessions => _activeConnections.Values.OrderByDescending(c => c.LastActivityDate); + private void OnDeviceManagerDeviceOptionsUpdated(object sender, GenericEventArgs> e) { foreach (var session in Sessions) @@ -130,14 +153,17 @@ namespace Emby.Server.Implementations.Session } } - private bool _disposed = false; - + /// public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } + /// + /// Releases unmanaged and - optionally - managed resources. + /// + /// true to release both managed and unmanaged resources; false to release only unmanaged resources. protected virtual void Dispose(bool disposing) { if (_disposed) @@ -147,15 +173,17 @@ namespace Emby.Server.Implementations.Session if (disposing) { - // TODO: dispose stuff + _idleTimer?.Dispose(); } + _idleTimer = null; + _deviceManager.DeviceOptionsUpdated -= OnDeviceManagerDeviceOptionsUpdated; _disposed = true; } - public void CheckDisposed() + private void CheckDisposed() { if (_disposed) { @@ -163,12 +191,6 @@ namespace Emby.Server.Implementations.Session } } - /// - /// Gets all connections. - /// - /// All connections. - public IEnumerable Sessions => _activeConnections.Values.OrderByDescending(c => c.LastActivityDate); - private void OnSessionStarted(SessionInfo info) { if (!string.IsNullOrEmpty(info.DeviceId)) @@ -199,13 +221,13 @@ namespace Emby.Server.Implementations.Session new SessionEventArgs { SessionInfo = info - }, _logger); info.Dispose(); } + /// public void UpdateDeviceName(string sessionId, string deviceName) { var session = GetSession(sessionId); @@ -225,7 +247,6 @@ namespace Emby.Server.Implementations.Session /// The remote end point. /// The user. /// SessionInfo. - /// user public SessionInfo LogSessionActivity( string appName, string appVersion, @@ -263,14 +284,7 @@ namespace Emby.Server.Implementations.Session if ((activityDate - userLastActivityDate).TotalSeconds > 60) { - try - { - _userManager.UpdateUser(user); - } - catch (Exception ex) - { - _logger.LogError("Error updating user", ex); - } + _userManager.UpdateUser(user); } } @@ -287,18 +301,20 @@ namespace Emby.Server.Implementations.Session return session; } + /// public void CloseIfNeeded(SessionInfo session) { if (!session.SessionControllers.Any(i => i.IsSessionActive)) { var key = GetSessionKey(session.Client, session.DeviceId); - _activeConnections.TryRemove(key, out var removed); + _activeConnections.TryRemove(key, out _); OnSessionEnded(session); } } + /// public void ReportSessionEnded(string sessionId) { CheckDisposed(); @@ -308,7 +324,7 @@ namespace Emby.Server.Implementations.Session { var key = GetSessionKey(session.Client, session.DeviceId); - _activeConnections.TryRemove(key, out var removed); + _activeConnections.TryRemove(key, out _); OnSessionEnded(session); } @@ -339,7 +355,7 @@ namespace Emby.Server.Implementations.Session var runtimeTicks = libraryItem.RunTimeTicks; MediaSourceInfo mediaSource = null; - if (libraryItem is IHasMediaSources hasMediaSources) + if (libraryItem is IHasMediaSources) { mediaSource = await GetMediaSource(libraryItem, info.MediaSourceId, info.LiveStreamId).ConfigureAwait(false); @@ -391,7 +407,6 @@ namespace Emby.Server.Implementations.Session /// Removes the now playing item id. /// /// The session. - /// item private void RemoveNowPlayingItem(SessionInfo session) { session.NowPlayingItem = null; @@ -404,9 +419,7 @@ namespace Emby.Server.Implementations.Session } private static string GetSessionKey(string appName, string deviceId) - { - return appName + deviceId; - } + => appName + deviceId; /// /// Gets the connection. @@ -426,6 +439,7 @@ namespace Emby.Server.Implementations.Session { throw new ArgumentNullException(nameof(deviceId)); } + var key = GetSessionKey(appName, deviceId); CheckDisposed(); @@ -498,7 +512,7 @@ namespace Emby.Server.Implementations.Session { var users = new List(); - if (!session.UserId.Equals(Guid.Empty)) + if (session.UserId != Guid.Empty) { var user = _userManager.GetUserById(session.UserId); @@ -517,8 +531,6 @@ namespace Emby.Server.Implementations.Session return users; } - private Timer _idleTimer; - private void StartIdleCheckTimer() { if (_idleTimer == null) @@ -594,11 +606,11 @@ namespace Emby.Server.Implementations.Session } /// - /// Used to report that playback has started for an item + /// Used to report that playback has started for an item. /// /// The info. /// Task. - /// info + /// info is null. public async Task OnPlaybackStart(PlaybackStartInfo info) { CheckDisposed(); @@ -610,7 +622,7 @@ namespace Emby.Server.Implementations.Session var session = GetSession(info.SessionId); - var libraryItem = info.ItemId.Equals(Guid.Empty) + var libraryItem = info.ItemId == Guid.Empty ? null : GetNowPlayingItem(session, info.ItemId); @@ -648,7 +660,6 @@ namespace Emby.Server.Implementations.Session ClientName = session.Client, DeviceId = session.DeviceId, Session = session - }, _logger); @@ -679,13 +690,14 @@ namespace Emby.Server.Implementations.Session _userDataManager.SaveUserData(user, item, data, UserDataSaveReason.PlaybackStart, CancellationToken.None); } + /// public Task OnPlaybackProgress(PlaybackProgressInfo info) { return OnPlaybackProgress(info, false); } /// - /// Used to report playback progress for an item + /// Used to report playback progress for an item. /// /// Task. public async Task OnPlaybackProgress(PlaybackProgressInfo info, bool isAutomated) @@ -852,7 +864,7 @@ namespace Emby.Server.Implementations.Session { MediaSourceInfo mediaSource = null; - if (libraryItem is IHasMediaSources hasMediaSources) + if (libraryItem is IHasMediaSources) { mediaSource = await GetMediaSource(libraryItem, info.MediaSourceId, info.LiveStreamId).ConfigureAwait(false); } @@ -924,7 +936,6 @@ namespace Emby.Server.Implementations.Session ClientName = session.Client, DeviceId = session.DeviceId, Session = session - }, _logger); } @@ -962,13 +973,17 @@ namespace Emby.Server.Implementations.Session /// The session identifier. /// if set to true [throw on missing]. /// SessionInfo. - /// sessionId + /// + /// No session with an Id equal to sessionId was found + /// and throwOnMissing is true. + /// private SessionInfo GetSession(string sessionId, bool throwOnMissing = true) { var session = Sessions.FirstOrDefault(i => string.Equals(i.Id, sessionId, StringComparison.Ordinal)); if (session == null && throwOnMissing) { - throw new ResourceNotFoundException(string.Format("Session {0} not found.", sessionId)); + throw new ResourceNotFoundException( + string.Format(CultureInfo.InvariantCulture, "Session {0} not found.", sessionId)); } return session; @@ -981,12 +996,14 @@ namespace Emby.Server.Implementations.Session if (session == null) { - throw new ResourceNotFoundException(string.Format("Session {0} not found.", sessionId)); + throw new ResourceNotFoundException( + string.Format(CultureInfo.InvariantCulture, "Session {0} not found.", sessionId)); } return session; } + /// public Task SendMessageCommand(string controllingSessionId, string sessionId, MessageCommand command, CancellationToken cancellationToken) { CheckDisposed(); @@ -1007,6 +1024,7 @@ namespace Emby.Server.Implementations.Session return SendGeneralCommand(controllingSessionId, sessionId, generalCommand, cancellationToken); } + /// public Task SendGeneralCommand(string controllingSessionId, string sessionId, GeneralCommand command, CancellationToken cancellationToken) { CheckDisposed(); @@ -1051,6 +1069,7 @@ namespace Emby.Server.Implementations.Session return Task.WhenAll(GetTasks()); } + /// public async Task SendPlayCommand(string controllingSessionId, string sessionId, PlayRequest command, CancellationToken cancellationToken) { CheckDisposed(); @@ -1092,7 +1111,8 @@ namespace Emby.Server.Implementations.Session { if (items.Any(i => i.GetPlayAccess(user) != PlayAccess.Full)) { - throw new ArgumentException(string.Format("{0} is not allowed to play media.", user.Name)); + throw new ArgumentException( + string.Format(CultureInfo.InvariantCulture, "{0} is not allowed to play media.", user.Name)); } } @@ -1200,6 +1220,7 @@ namespace Emby.Server.Implementations.Session return _musicManager.GetInstantMixFromItem(item, user, new DtoOptions(false) { EnableImages = false }); } + /// public Task SendBrowseCommand(string controllingSessionId, string sessionId, BrowseRequest command, CancellationToken cancellationToken) { var generalCommand = new GeneralCommand @@ -1216,6 +1237,7 @@ namespace Emby.Server.Implementations.Session return SendGeneralCommand(controllingSessionId, sessionId, generalCommand, cancellationToken); } + /// public Task SendPlaystateCommand(string controllingSessionId, string sessionId, PlaystateRequest command, CancellationToken cancellationToken) { CheckDisposed(); @@ -1299,12 +1321,12 @@ namespace Emby.Server.Implementations.Session var session = GetSession(sessionId); - if (session.UserId.Equals(userId)) + if (session.UserId == userId) { throw new ArgumentException("The requested user is already the primary user of the session."); } - if (session.AdditionalUsers.All(i => !i.UserId.Equals(userId))) + if (session.AdditionalUsers.All(i => i.UserId != userId)) { var user = _userManager.GetUserById(userId); @@ -1430,19 +1452,19 @@ namespace Emby.Server.Implementations.Session private string GetAuthorizationToken(User user, string deviceId, string app, string appVersion, string deviceName) { - var existing = _authRepo.Get(new AuthenticationInfoQuery - { - DeviceId = deviceId, - UserId = user.Id, - Limit = 1 - - }).Items.FirstOrDefault(); - - var allExistingForDevice = _authRepo.Get(new AuthenticationInfoQuery - { - DeviceId = deviceId + var existing = _authRepo.Get( + new AuthenticationInfoQuery + { + DeviceId = deviceId, + UserId = user.Id, + Limit = 1 + }).Items.FirstOrDefault(); - }).Items; + var allExistingForDevice = _authRepo.Get( + new AuthenticationInfoQuery + { + DeviceId = deviceId + }).Items; foreach (var auth in allExistingForDevice) { @@ -1461,7 +1483,7 @@ namespace Emby.Server.Implementations.Session if (existing != null) { - _logger.LogInformation("Reissuing access token: " + existing.AccessToken); + _logger.LogInformation("Reissuing access token: {Token}", existing.AccessToken); return existing.AccessToken; } @@ -1486,6 +1508,7 @@ namespace Emby.Server.Implementations.Session return newToken.AccessToken; } + /// public void Logout(string accessToken) { CheckDisposed(); @@ -1495,19 +1518,20 @@ namespace Emby.Server.Implementations.Session throw new ArgumentNullException(nameof(accessToken)); } - var existing = _authRepo.Get(new AuthenticationInfoQuery - { - Limit = 1, - AccessToken = accessToken - - }).Items.FirstOrDefault(); + var existing = _authRepo.Get( + new AuthenticationInfoQuery + { + Limit = 1, + AccessToken = accessToken + }).Items; - if (existing != null) + if (existing.Count > 0) { - Logout(existing); + Logout(existing[0]); } } + /// public void Logout(AuthenticationInfo existing) { CheckDisposed(); @@ -1533,6 +1557,7 @@ namespace Emby.Server.Implementations.Session } } + /// public void RevokeUserTokens(Guid userId, string currentAccessToken) { CheckDisposed(); @@ -1551,6 +1576,7 @@ namespace Emby.Server.Implementations.Session } } + /// public void RevokeToken(string token) { Logout(token); @@ -1607,10 +1633,8 @@ namespace Emby.Server.Implementations.Session _deviceManager.SaveCapabilities(deviceId, capabilities); } - private DtoOptions _itemInfoDtoOptions; - /// - /// Converts a BaseItem to a BaseItemInfo + /// Converts a BaseItem to a BaseItemInfo. /// private BaseItemDto GetItemInfo(BaseItem item, MediaSourceInfo mediaSource) { @@ -1685,6 +1709,7 @@ namespace Emby.Server.Implementations.Session } } + /// public void ReportNowViewingItem(string sessionId, string itemId) { if (string.IsNullOrEmpty(itemId)) @@ -1692,23 +1717,26 @@ namespace Emby.Server.Implementations.Session throw new ArgumentNullException(nameof(itemId)); } - //var item = _libraryManager.GetItemById(new Guid(itemId)); + var item = _libraryManager.GetItemById(new Guid(itemId)); - //var info = GetItemInfo(item, null, null); + var info = GetItemInfo(item, null); - //ReportNowViewingItem(sessionId, info); + ReportNowViewingItem(sessionId, info); } + /// public void ReportNowViewingItem(string sessionId, BaseItemDto item) { - //var session = GetSession(sessionId); + throw new NotImplementedException(); - //session.NowViewingItem = item; + // var session = GetSession(sessionId); + // session.NowViewingItem = item; } + /// public void ReportTranscodingInfo(string deviceId, TranscodingInfo info) { - var session = Sessions.FirstOrDefault(i => string.Equals(i.DeviceId, deviceId)); + var session = Sessions.FirstOrDefault(i => string.Equals(i.DeviceId, deviceId, StringComparison.Ordinal)); if (session != null) { @@ -1716,17 +1744,18 @@ namespace Emby.Server.Implementations.Session } } + /// public void ClearTranscodingInfo(string deviceId) { ReportTranscodingInfo(deviceId, null); } + /// public SessionInfo GetSession(string deviceId, string client, string version) - { - return Sessions.FirstOrDefault(i => string.Equals(i.DeviceId, deviceId) && - string.Equals(i.Client, client)); - } + => Sessions.FirstOrDefault( + i => string.Equals(i.DeviceId, deviceId, StringComparison.Ordinal) && string.Equals(i.Client, client, StringComparison.Ordinal)); + /// public SessionInfo GetSessionByAuthenticationToken(AuthenticationInfo info, string deviceId, string remoteEndpoint, string appVersion) { if (info == null) @@ -1759,23 +1788,24 @@ namespace Emby.Server.Implementations.Session return LogSessionActivity(appName, appVersion, deviceId, deviceName, remoteEndpoint, user); } + /// public SessionInfo GetSessionByAuthenticationToken(string token, string deviceId, string remoteEndpoint) { - var result = _authRepo.Get(new AuthenticationInfoQuery + var items = _authRepo.Get(new AuthenticationInfoQuery { - AccessToken = token - }); - - var info = result.Items.FirstOrDefault(); + AccessToken = token, + Limit = 1 + }).Items; - if (info == null) + if (items.Count == 0) { return null; } - return GetSessionByAuthenticationToken(info, deviceId, remoteEndpoint, null); + return GetSessionByAuthenticationToken(items[0], deviceId, remoteEndpoint, null); } + /// public Task SendMessageToAdminSessions(string name, T data, CancellationToken cancellationToken) { CheckDisposed(); @@ -1785,6 +1815,7 @@ namespace Emby.Server.Implementations.Session return SendMessageToUserSessions(adminUserIds, name, data, cancellationToken); } + /// public Task SendMessageToUserSessions(List userIds, string name, Func dataFn, CancellationToken cancellationToken) { CheckDisposed(); @@ -1796,11 +1827,10 @@ namespace Emby.Server.Implementations.Session return Task.CompletedTask; } - var data = dataFn(); - - return SendMessageToSessions(sessions, name, data, cancellationToken); + return SendMessageToSessions(sessions, name, dataFn(), cancellationToken); } + /// public Task SendMessageToUserSessions(List userIds, string name, T data, CancellationToken cancellationToken) { CheckDisposed(); @@ -1809,6 +1839,7 @@ namespace Emby.Server.Implementations.Session return SendMessageToSessions(sessions, name, data, cancellationToken); } + /// public Task SendMessageToUserDeviceSessions(string deviceId, string name, T data, CancellationToken cancellationToken) { CheckDisposed(); @@ -1817,22 +1848,5 @@ namespace Emby.Server.Implementations.Session return SendMessageToSessions(sessions, name, data, cancellationToken); } - - public Task SendMessageToUserDeviceAndAdminSessions(string deviceId, string name, T data, CancellationToken cancellationToken) - { - CheckDisposed(); - - var sessions = Sessions - .Where(i => string.Equals(i.DeviceId, deviceId, StringComparison.OrdinalIgnoreCase) || IsAdminSession(i)); - - return SendMessageToSessions(sessions, name, data, cancellationToken); - } - - private bool IsAdminSession(SessionInfo s) - { - var user = _userManager.GetUserById(s.UserId); - - return user != null && user.Policy.IsAdministrator; - } } } -- cgit v1.2.3 From ddf9b38799fa4a0e227ae3c2516a72ec48f13854 Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Tue, 21 Jan 2020 20:26:30 +0100 Subject: Simplify image processing by removing image enhancers --- Emby.Drawing/Emby.Drawing.csproj | 12 + Emby.Drawing/ImageProcessor.cs | 349 ++------------------- Emby.Server.Implementations/ApplicationHost.cs | 2 - Emby.Server.Implementations/Dto/DtoService.cs | 47 +-- Jellyfin.Drawing.Skia/SkiaEncoder.cs | 20 +- Jellyfin.Server/Program.cs | 11 +- MediaBrowser.Api/Images/ImageService.cs | 26 +- MediaBrowser.Controller/Drawing/IImageProcessor.cs | 35 --- MediaBrowser.Controller/Drawing/ImageHelper.cs | 2 - .../Drawing/ImageProcessingOptions.cs | 3 - .../MediaEncoding/EncodingJobInfo.cs | 12 +- .../Providers/IImageEnhancer.cs | 61 ---- MediaBrowser.Model/Drawing/ImageDimensions.cs | 31 +- 13 files changed, 96 insertions(+), 515 deletions(-) delete mode 100644 MediaBrowser.Controller/Providers/IImageEnhancer.cs (limited to 'Emby.Server.Implementations') diff --git a/Emby.Drawing/Emby.Drawing.csproj b/Emby.Drawing/Emby.Drawing.csproj index 85cecdc44..b7090b262 100644 --- a/Emby.Drawing/Emby.Drawing.csproj +++ b/Emby.Drawing/Emby.Drawing.csproj @@ -17,4 +17,16 @@ + + + + + + + + + + ../jellyfin.ruleset + + diff --git a/Emby.Drawing/ImageProcessor.cs b/Emby.Drawing/ImageProcessor.cs index ce8089e59..8f6850936 100644 --- a/Emby.Drawing/ImageProcessor.cs +++ b/Emby.Drawing/ImageProcessor.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; -using System.Threading; using System.Threading.Tasks; using MediaBrowser.Common.Extensions; using MediaBrowser.Controller; @@ -11,10 +10,8 @@ using MediaBrowser.Controller.Drawing; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.MediaEncoding; -using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Drawing; using MediaBrowser.Model.Entities; -using MediaBrowser.Model.Extensions; using MediaBrowser.Model.IO; using MediaBrowser.Model.Net; using Microsoft.Extensions.Logging; @@ -24,7 +21,7 @@ namespace Emby.Drawing /// /// Class ImageProcessor. /// - public class ImageProcessor : IImageProcessor, IDisposable + public sealed class ImageProcessor : IImageProcessor, IDisposable { // Increment this when there's a change requiring caches to be invalidated private const string Version = "3"; @@ -32,28 +29,24 @@ namespace Emby.Drawing private static readonly HashSet _transparentImageTypes = new HashSet(StringComparer.OrdinalIgnoreCase) { ".png", ".webp", ".gif" }; - /// - /// The _logger - /// private readonly ILogger _logger; private readonly IFileSystem _fileSystem; private readonly IServerApplicationPaths _appPaths; - private IImageEncoder _imageEncoder; + private readonly IImageEncoder _imageEncoder; private readonly Func _libraryManager; private readonly Func _mediaEncoder; - private readonly Dictionary _locks = new Dictionary(); private bool _disposed = false; /// - /// + /// Initializes a new instance of the class. /// - /// - /// - /// - /// - /// - /// + /// The logger. + /// The server application paths. + /// The filesystem. + /// The image encoder. + /// The library manager. + /// The media encoder. public ImageProcessor( ILogger logger, IServerApplicationPaths appPaths, @@ -68,16 +61,10 @@ namespace Emby.Drawing _libraryManager = libraryManager; _mediaEncoder = mediaEncoder; _appPaths = appPaths; - - ImageEnhancers = Array.Empty(); - - ImageHelper.ImageProcessor = this; } private string ResizedImageCachePath => Path.Combine(_appPaths.ImageCachePath, "resized-images"); - private string EnhancedImageCachePath => Path.Combine(_appPaths.ImageCachePath, "enhanced-images"); - /// public IReadOnlyCollection SupportedInputFormats => new HashSet(StringComparer.OrdinalIgnoreCase) @@ -90,9 +77,7 @@ namespace Emby.Drawing "aiff", "cr2", "crw", - - // Remove until supported - //"nef", + "nef", "orf", "pef", "arw", @@ -111,19 +96,9 @@ namespace Emby.Drawing "wbmp" }; - /// - public IReadOnlyCollection ImageEnhancers { get; set; } - /// public bool SupportsImageCollageCreation => _imageEncoder.SupportsImageCollageCreation; - /// - public IImageEncoder ImageEncoder - { - get => _imageEncoder; - set => _imageEncoder = value ?? throw new ArgumentNullException(nameof(value)); - } - /// public async Task ProcessImage(ImageProcessingOptions options, Stream toStream) { @@ -151,6 +126,8 @@ namespace Emby.Drawing throw new ArgumentNullException(nameof(options)); } + var libraryManager = _libraryManager(); + ItemImageInfo originalImage = options.Image; BaseItem item = options.Item; @@ -158,9 +135,10 @@ namespace Emby.Drawing { if (item == null) { - item = _libraryManager().GetItemById(options.ItemId); + item = libraryManager.GetItemById(options.ItemId); } - originalImage = await _libraryManager().ConvertImageToLocal(item, originalImage, options.ImageIndex).ConfigureAwait(false); + + originalImage = await libraryManager.ConvertImageToLocal(item, originalImage, options.ImageIndex).ConfigureAwait(false); } string originalImagePath = originalImage.Path; @@ -187,27 +165,6 @@ namespace Emby.Drawing dateModified = supportedImageInfo.dateModified; bool requiresTransparency = _transparentImageTypes.Contains(Path.GetExtension(originalImagePath)); - if (options.Enhancers.Count > 0) - { - if (item == null) - { - item = _libraryManager().GetItemById(options.ItemId); - } - - var tuple = await GetEnhancedImage(new ItemImageInfo - { - DateModified = dateModified, - Type = originalImage.Type, - Path = originalImagePath - }, requiresTransparency, item, options.ImageIndex, options.Enhancers, CancellationToken.None).ConfigureAwait(false); - - originalImagePath = tuple.path; - dateModified = tuple.dateModified; - requiresTransparency = tuple.transparent; - // TODO: Get this info - originalImageSize = null; - } - bool autoOrient = false; ImageOrientation? orientation = null; if (item is Photo photo) @@ -240,12 +197,6 @@ namespace Emby.Drawing ImageFormat outputFormat = GetOutputFormat(options.SupportedOutputFormats, requiresTransparency); string cacheFilePath = GetCacheFilePath(originalImagePath, newSize, quality, dateModified, outputFormat, options.AddPlayedIndicator, options.PercentPlayed, options.UnplayedCount, options.Blur, options.BackgroundColor, options.ForegroundLayer); - CheckDisposed(); - - LockInfo lockInfo = GetLock(cacheFilePath); - - await lockInfo.Lock.WaitAsync().ConfigureAwait(false); - try { if (!File.Exists(cacheFilePath)) @@ -271,10 +222,6 @@ namespace Emby.Drawing _logger.LogError(ex, "Error encoding image"); return (originalImagePath, MimeTypes.GetMimeType(originalImagePath), dateModified); } - finally - { - ReleaseLock(cacheFilePath, lockInfo); - } } private ImageFormat GetOutputFormat(IReadOnlyCollection clientSupportedFormats, bool requiresTransparency) @@ -306,20 +253,18 @@ namespace Emby.Drawing } private string GetMimeType(ImageFormat format, string path) - { - switch(format) - { - case ImageFormat.Bmp: return MimeTypes.GetMimeType("i.bmp"); - case ImageFormat.Gif: return MimeTypes.GetMimeType("i.gif"); - case ImageFormat.Jpg: return MimeTypes.GetMimeType("i.jpg"); - case ImageFormat.Png: return MimeTypes.GetMimeType("i.png"); - case ImageFormat.Webp: return MimeTypes.GetMimeType("i.webp"); - default: return MimeTypes.GetMimeType(path); - } - } + => format switch + { + ImageFormat.Bmp => MimeTypes.GetMimeType("i.bmp"), + ImageFormat.Gif => MimeTypes.GetMimeType("i.gif"), + ImageFormat.Jpg => MimeTypes.GetMimeType("i.jpg"), + ImageFormat.Png => MimeTypes.GetMimeType("i.png"), + ImageFormat.Webp => MimeTypes.GetMimeType("i.webp"), + _ => MimeTypes.GetMimeType(path) + }; /// - /// Gets the cache file path based on a set of parameters + /// Gets the cache file path based on a set of parameters. /// private string GetCacheFilePath(string originalPath, ImageDimensions outputSize, int quality, DateTime dateModified, ImageFormat format, bool addPlayedIndicator, double percentPlayed, int? unwatchedCount, int? blur, string backgroundColor, string foregroundLayer) { @@ -401,11 +346,7 @@ namespace Emby.Drawing /// public string GetImageCacheTag(BaseItem item, ItemImageInfo image) - { - var supportedEnhancers = GetSupportedEnhancers(item, image.Type).ToArray(); - - return GetImageCacheTag(item, image, supportedEnhancers); - } + => (item.Path + image.DateModified.Ticks).GetMD5().ToString("N", CultureInfo.InvariantCulture); /// public string GetImageCacheTag(BaseItem item, ChapterInfo chapter) @@ -425,26 +366,6 @@ namespace Emby.Drawing } } - /// - public string GetImageCacheTag(BaseItem item, ItemImageInfo image, IReadOnlyCollection imageEnhancers) - { - string originalImagePath = image.Path; - DateTime dateModified = image.DateModified; - ImageType imageType = image.Type; - - // Optimization - if (imageEnhancers.Count == 0) - { - return (originalImagePath + dateModified.Ticks).GetMD5().ToString("N", CultureInfo.InvariantCulture); - } - - // Cache name is created with supported enhancers combined with the last config change so we pick up new config changes - var cacheKeys = imageEnhancers.Select(i => i.GetConfigurationCacheKey(item, imageType)).ToList(); - cacheKeys.Add(originalImagePath + dateModified.Ticks); - - return string.Join("|", cacheKeys).GetMD5().ToString("N", CultureInfo.InvariantCulture); - } - private async Task<(string path, DateTime dateModified)> GetSupportedImage(string originalImagePath, DateTime dateModified) { var inputFormat = Path.GetExtension(originalImagePath) @@ -488,154 +409,6 @@ namespace Emby.Drawing return (originalImagePath, dateModified); } - /// - public async Task GetEnhancedImage(BaseItem item, ImageType imageType, int imageIndex) - { - var enhancers = GetSupportedEnhancers(item, imageType).ToArray(); - - ItemImageInfo imageInfo = item.GetImageInfo(imageType, imageIndex); - - bool inputImageSupportsTransparency = SupportsTransparency(imageInfo.Path); - - var result = await GetEnhancedImage(imageInfo, inputImageSupportsTransparency, item, imageIndex, enhancers, CancellationToken.None); - - return result.path; - } - - private async Task<(string path, DateTime dateModified, bool transparent)> GetEnhancedImage( - ItemImageInfo image, - bool inputImageSupportsTransparency, - BaseItem item, - int imageIndex, - IReadOnlyCollection enhancers, - CancellationToken cancellationToken) - { - var originalImagePath = image.Path; - var dateModified = image.DateModified; - var imageType = image.Type; - - try - { - var cacheGuid = GetImageCacheTag(item, image, enhancers); - - // Enhance if we have enhancers - var enhancedImageInfo = await GetEnhancedImageInternal(originalImagePath, item, imageType, imageIndex, enhancers, cacheGuid, cancellationToken).ConfigureAwait(false); - - string enhancedImagePath = enhancedImageInfo.path; - - // If the path changed update dateModified - if (!string.Equals(enhancedImagePath, originalImagePath, StringComparison.OrdinalIgnoreCase)) - { - var treatmentRequiresTransparency = enhancedImageInfo.transparent; - - return (enhancedImagePath, _fileSystem.GetLastWriteTimeUtc(enhancedImagePath), treatmentRequiresTransparency); - } - } - catch (Exception ex) - { - _logger.LogError(ex, "Error enhancing image"); - } - - return (originalImagePath, dateModified, inputImageSupportsTransparency); - } - - /// - /// Gets the enhanced image internal. - /// - /// The original image path. - /// The item. - /// Type of the image. - /// Index of the image. - /// The supported enhancers. - /// The cache unique identifier. - /// The cancellation token. - /// Task<System.String>. - /// - /// originalImagePath - /// or - /// item - /// - private async Task<(string path, bool transparent)> GetEnhancedImageInternal( - string originalImagePath, - BaseItem item, - ImageType imageType, - int imageIndex, - IReadOnlyCollection supportedEnhancers, - string cacheGuid, - CancellationToken cancellationToken = default) - { - if (string.IsNullOrEmpty(originalImagePath)) - { - throw new ArgumentNullException(nameof(originalImagePath)); - } - - if (item == null) - { - throw new ArgumentNullException(nameof(item)); - } - - var treatmentRequiresTransparency = false; - foreach (var enhancer in supportedEnhancers) - { - if (!treatmentRequiresTransparency) - { - treatmentRequiresTransparency = enhancer.GetEnhancedImageInfo(item, originalImagePath, imageType, imageIndex).RequiresTransparency; - } - } - - // All enhanced images are saved as png to allow transparency - string cacheExtension = _imageEncoder.SupportedOutputFormats.Contains(ImageFormat.Webp) ? - ".webp" : - (treatmentRequiresTransparency ? ".png" : ".jpg"); - - string enhancedImagePath = GetCachePath(EnhancedImageCachePath, cacheGuid + cacheExtension); - - LockInfo lockInfo = GetLock(enhancedImagePath); - - await lockInfo.Lock.WaitAsync(cancellationToken).ConfigureAwait(false); - - try - { - // Check again in case of contention - if (File.Exists(enhancedImagePath)) - { - return (enhancedImagePath, treatmentRequiresTransparency); - } - - Directory.CreateDirectory(Path.GetDirectoryName(enhancedImagePath)); - - await ExecuteImageEnhancers(supportedEnhancers, originalImagePath, enhancedImagePath, item, imageType, imageIndex).ConfigureAwait(false); - - return (enhancedImagePath, treatmentRequiresTransparency); - } - finally - { - ReleaseLock(enhancedImagePath, lockInfo); - } - } - - /// - /// Executes the image enhancers. - /// - /// The image enhancers. - /// The input path. - /// The output path. - /// The item. - /// Type of the image. - /// Index of the image. - /// Task{EnhancedImage}. - private static async Task ExecuteImageEnhancers(IEnumerable imageEnhancers, string inputPath, string outputPath, BaseItem item, ImageType imageType, int imageIndex) - { - // Run the enhancers sequentially in order of priority - foreach (var enhancer in imageEnhancers) - { - await enhancer.EnhanceImageAsync(item, inputPath, outputPath, imageType, imageIndex).ConfigureAwait(false); - - // Feed the output into the next enhancer as input - inputPath = outputPath; - } - } - /// /// Gets the cache path. /// @@ -648,7 +421,7 @@ namespace Emby.Drawing /// or /// uniqueName /// or - /// fileExtension + /// fileExtension. /// public string GetCachePath(string path, string uniqueName, string fileExtension) { @@ -681,7 +454,7 @@ namespace Emby.Drawing /// /// path /// or - /// filename + /// filename. /// public string GetCachePath(string path, string filename) { @@ -689,6 +462,7 @@ namespace Emby.Drawing { throw new ArgumentNullException(nameof(path)); } + if (string.IsNullOrEmpty(filename)) { throw new ArgumentNullException(nameof(filename)); @@ -710,74 +484,19 @@ namespace Emby.Drawing } /// - public IEnumerable GetSupportedEnhancers(BaseItem item, ImageType imageType) - { - foreach (var i in ImageEnhancers) - { - if (i.Supports(item, imageType)) - { - yield return i; - } - } - } - - - private class LockInfo - { - public SemaphoreSlim Lock = new SemaphoreSlim(1, 1); - public int Count = 1; - } - - private LockInfo GetLock(string key) - { - lock (_locks) - { - if (_locks.TryGetValue(key, out LockInfo info)) - { - info.Count++; - } - else - { - info = new LockInfo(); - _locks[key] = info; - } - return info; - } - } - - private void ReleaseLock(string key, LockInfo info) + public void Dispose() { - info.Lock.Release(); - - lock (_locks) + if (_disposed) { - info.Count--; - if (info.Count <= 0) - { - _locks.Remove(key); - info.Lock.Dispose(); - } + return; } - } - - /// - public void Dispose() - { - _disposed = true; - var disposable = _imageEncoder as IDisposable; - if (disposable != null) + if (_imageEncoder is IDisposable disposable) { disposable.Dispose(); } - } - private void CheckDisposed() - { - if (_disposed) - { - throw new ObjectDisposedException(GetType().Name); - } + _disposed = true; } } } diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index 0bb1d832f..4f4787443 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -1074,8 +1074,6 @@ namespace Emby.Server.Implementations GetExports(), GetExports()); - ImageProcessor.ImageEnhancers = GetExports(); - LiveTvManager.AddParts(GetExports(), GetExports(), GetExports()); SubtitleManager.AddParts(GetExports()); diff --git a/Emby.Server.Implementations/Dto/DtoService.cs b/Emby.Server.Implementations/Dto/DtoService.cs index fcf0360c7..960f3f2d6 100644 --- a/Emby.Server.Implementations/Dto/DtoService.cs +++ b/Emby.Server.Implementations/Dto/DtoService.cs @@ -1362,56 +1362,33 @@ namespace Emby.Server.Implementations.Dto return null; } - var supportedEnhancers = _imageProcessor.GetSupportedEnhancers(item, ImageType.Primary).ToArray(); - ImageDimensions size; var defaultAspectRatio = item.GetDefaultPrimaryImageAspectRatio(); if (defaultAspectRatio > 0) { - if (supportedEnhancers.Length == 0) - { - return defaultAspectRatio; - } + return defaultAspectRatio; + } - int dummyWidth = 200; - int dummyHeight = Convert.ToInt32(dummyWidth / defaultAspectRatio); - size = new ImageDimensions(dummyWidth, dummyHeight); + if (!imageInfo.IsLocalFile) + { + return null; } - else + + try { - if (!imageInfo.IsLocalFile) - { - return null; - } + size = _imageProcessor.GetImageDimensions(item, imageInfo); - try + if (size.Width <= 0 || size.Height <= 0) { - size = _imageProcessor.GetImageDimensions(item, imageInfo); - - if (size.Width <= 0 || size.Height <= 0) - { - return null; - } - } - catch (Exception ex) - { - _logger.LogError(ex, "Failed to determine primary image aspect ratio for {0}", imageInfo.Path); return null; } } - - foreach (var enhancer in supportedEnhancers) + catch (Exception ex) { - try - { - size = enhancer.GetEnhancedImageSize(item, ImageType.Primary, 0, size); - } - catch (Exception ex) - { - _logger.LogError(ex, "Error in image enhancer: {0}", enhancer.GetType().Name); - } + _logger.LogError(ex, "Failed to determine primary image aspect ratio for {0}", imageInfo.Path); + return null; } var width = size.Width; diff --git a/Jellyfin.Drawing.Skia/SkiaEncoder.cs b/Jellyfin.Drawing.Skia/SkiaEncoder.cs index b080b3e6a..2ea690650 100644 --- a/Jellyfin.Drawing.Skia/SkiaEncoder.cs +++ b/Jellyfin.Drawing.Skia/SkiaEncoder.cs @@ -6,7 +6,6 @@ using MediaBrowser.Common.Configuration; using MediaBrowser.Controller.Drawing; using MediaBrowser.Controller.Extensions; using MediaBrowser.Model.Drawing; -using MediaBrowser.Model.Globalization; using Microsoft.Extensions.Logging; using SkiaSharp; using static Jellyfin.Drawing.Skia.SkiaHelper; @@ -18,27 +17,23 @@ namespace Jellyfin.Drawing.Skia /// public class SkiaEncoder : IImageEncoder { - private readonly ILogger _logger; - private readonly IApplicationPaths _appPaths; - private readonly ILocalizationManager _localizationManager; - private static readonly HashSet _transparentImageTypes = new HashSet(StringComparer.OrdinalIgnoreCase) { ".png", ".gif", ".webp" }; + private readonly ILogger _logger; + private readonly IApplicationPaths _appPaths; + /// /// Initializes a new instance of the class. /// /// The application logger. /// The application paths. - /// The application localization manager. public SkiaEncoder( ILogger logger, - IApplicationPaths appPaths, - ILocalizationManager localizationManager) + IApplicationPaths appPaths) { _logger = logger; _appPaths = appPaths; - _localizationManager = localizationManager; } /// @@ -235,9 +230,12 @@ namespace Jellyfin.Drawing.Skia private bool RequiresSpecialCharacterHack(string path) { - if (_localizationManager.HasUnicodeCategory(path, UnicodeCategory.OtherLetter)) + for (int i = 0; i < path.Length; i++) { - return true; + if (char.GetUnicodeCategory(path[i]) == UnicodeCategory.OtherLetter) + { + return true; + } } if (HasDiacritics(path)) diff --git a/Jellyfin.Server/Program.cs b/Jellyfin.Server/Program.cs index fa9b62674..c0621ba14 100644 --- a/Jellyfin.Server/Program.cs +++ b/Jellyfin.Server/Program.cs @@ -169,7 +169,7 @@ namespace Jellyfin.Server _loggerFactory, options, new ManagedFileSystem(_loggerFactory.CreateLogger(), appPaths), - new NullImageEncoder(), + GetImageEncoder(appPaths), new NetworkManager(_loggerFactory.CreateLogger()), appConfig); try @@ -193,8 +193,6 @@ namespace Jellyfin.Server throw; } - appHost.ImageProcessor.ImageEncoder = GetImageEncoder(appPaths, appHost.LocalizationManager); - await appHost.RunStartupTasksAsync().ConfigureAwait(false); stopWatch.Stop(); @@ -494,9 +492,7 @@ namespace Jellyfin.Server } } - private static IImageEncoder GetImageEncoder( - IApplicationPaths appPaths, - ILocalizationManager localizationManager) + private static IImageEncoder GetImageEncoder(IApplicationPaths appPaths) { try { @@ -505,8 +501,7 @@ namespace Jellyfin.Server return new SkiaEncoder( _loggerFactory.CreateLogger(), - appPaths, - localizationManager); + appPaths); } catch (Exception ex) { diff --git a/MediaBrowser.Api/Images/ImageService.cs b/MediaBrowser.Api/Images/ImageService.cs index e94c1321f..4060bf4cc 100644 --- a/MediaBrowser.Api/Images/ImageService.cs +++ b/MediaBrowser.Api/Images/ImageService.cs @@ -24,7 +24,7 @@ using Microsoft.Net.Http.Headers; namespace MediaBrowser.Api.Images { /// - /// Class GetItemImage + /// Class GetItemImage. /// [Route("/Items/{Id}/Images", "GET", Summary = "Gets information about an item's images")] [Authenticated] @@ -558,21 +558,6 @@ namespace MediaBrowser.Api.Images throw new ResourceNotFoundException(string.Format("{0} does not have an image of type {1}", displayText, request.Type)); } - IImageEnhancer[] supportedImageEnhancers; - if (_imageProcessor.ImageEnhancers.Count > 0) - { - if (item == null) - { - item = _libraryManager.GetItemById(itemId); - } - - supportedImageEnhancers = request.EnableImageEnhancers ? _imageProcessor.GetSupportedEnhancers(item, request.Type).ToArray() : Array.Empty(); - } - else - { - supportedImageEnhancers = Array.Empty(); - } - bool cropwhitespace; if (request.CropWhitespace.HasValue) { @@ -598,25 +583,25 @@ namespace MediaBrowser.Api.Images {"realTimeInfo.dlna.org", "DLNA.ORG_TLAG=*"} }; - return GetImageResult(item, + return GetImageResult( + item, itemId, request, imageInfo, cropwhitespace, outputFormats, - supportedImageEnhancers, cacheDuration, responseHeaders, isHeadRequest); } - private async Task GetImageResult(BaseItem item, + private async Task GetImageResult( + BaseItem item, Guid itemId, ImageRequest request, ItemImageInfo image, bool cropwhitespace, IReadOnlyCollection supportedFormats, - IReadOnlyCollection enhancers, TimeSpan? cacheDuration, IDictionary headers, bool isHeadRequest) @@ -624,7 +609,6 @@ namespace MediaBrowser.Api.Images var options = new ImageProcessingOptions { CropWhiteSpace = cropwhitespace, - Enhancers = enhancers, Height = request.Height, ImageIndex = request.Index ?? 0, Image = image, diff --git a/MediaBrowser.Controller/Drawing/IImageProcessor.cs b/MediaBrowser.Controller/Drawing/IImageProcessor.cs index a58a11bd1..79399807f 100644 --- a/MediaBrowser.Controller/Drawing/IImageProcessor.cs +++ b/MediaBrowser.Controller/Drawing/IImageProcessor.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.IO; using System.Threading.Tasks; using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Drawing; using MediaBrowser.Model.Entities; @@ -20,20 +19,12 @@ namespace MediaBrowser.Controller.Drawing /// The supported input formats. IReadOnlyCollection SupportedInputFormats { get; } - /// - /// Gets the image enhancers. - /// - /// The image enhancers. - IReadOnlyCollection ImageEnhancers { get; set; } - /// /// Gets a value indicating whether [supports image collage creation]. /// /// true if [supports image collage creation]; otherwise, false. bool SupportsImageCollageCreation { get; } - IImageEncoder ImageEncoder { get; set; } - /// /// Gets the dimensions of the image. /// @@ -58,14 +49,6 @@ namespace MediaBrowser.Controller.Drawing /// ImageDimensions ImageDimensions GetImageDimensions(BaseItem item, ItemImageInfo info, bool updateItem); - /// - /// Gets the supported enhancers. - /// - /// The item. - /// Type of the image. - /// IEnumerable{IImageEnhancer}. - IEnumerable GetSupportedEnhancers(BaseItem item, ImageType imageType); - /// /// Gets the image cache tag. /// @@ -75,15 +58,6 @@ namespace MediaBrowser.Controller.Drawing string GetImageCacheTag(BaseItem item, ItemImageInfo image); string GetImageCacheTag(BaseItem item, ChapterInfo info); - /// - /// Gets the image cache tag. - /// - /// The item. - /// The image. - /// The image enhancers. - /// Guid. - string GetImageCacheTag(BaseItem item, ItemImageInfo image, IReadOnlyCollection imageEnhancers); - /// /// Processes the image. /// @@ -99,15 +73,6 @@ namespace MediaBrowser.Controller.Drawing /// Task. Task<(string path, string mimeType, DateTime dateModified)> ProcessImage(ImageProcessingOptions options); - /// - /// Gets the enhanced image. - /// - /// The item. - /// Type of the image. - /// Index of the image. - /// Task{System.String}. - Task GetEnhancedImage(BaseItem item, ImageType imageType, int imageIndex); - /// /// Gets the supported image output formats. /// diff --git a/MediaBrowser.Controller/Drawing/ImageHelper.cs b/MediaBrowser.Controller/Drawing/ImageHelper.cs index 432cf8042..d5a5f547e 100644 --- a/MediaBrowser.Controller/Drawing/ImageHelper.cs +++ b/MediaBrowser.Controller/Drawing/ImageHelper.cs @@ -19,8 +19,6 @@ namespace MediaBrowser.Controller.Drawing return GetSizeEstimate(options); } - public static IImageProcessor ImageProcessor { get; set; } - private static ImageDimensions GetSizeEstimate(ImageProcessingOptions options) { if (options.Width.HasValue && options.Height.HasValue) diff --git a/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs b/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs index 29addf6e6..870e0278e 100644 --- a/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs +++ b/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.IO; using System.Linq; using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Drawing; namespace MediaBrowser.Controller.Drawing @@ -34,8 +33,6 @@ namespace MediaBrowser.Controller.Drawing public int Quality { get; set; } - public IReadOnlyCollection Enhancers { get; set; } - public IReadOnlyCollection SupportedOutputFormats { get; set; } public bool AddPlayedIndicator { get; set; } diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs b/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs index 34af3b156..6b3fb4144 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs @@ -316,11 +316,7 @@ namespace MediaBrowser.Controller.MediaEncoding { if (VideoStream != null && VideoStream.Width.HasValue && VideoStream.Height.HasValue) { - var size = new ImageDimensions - { - Width = VideoStream.Width.Value, - Height = VideoStream.Height.Value - }; + var size = new ImageDimensions(VideoStream.Width.Value, VideoStream.Height.Value); var newSize = DrawingUtils.Resize(size, BaseRequest.Width ?? 0, @@ -346,11 +342,7 @@ namespace MediaBrowser.Controller.MediaEncoding { if (VideoStream != null && VideoStream.Width.HasValue && VideoStream.Height.HasValue) { - var size = new ImageDimensions - { - Width = VideoStream.Width.Value, - Height = VideoStream.Height.Value - }; + var size = new ImageDimensions(VideoStream.Width.Value, VideoStream.Height.Value); var newSize = DrawingUtils.Resize(size, BaseRequest.Width ?? 0, diff --git a/MediaBrowser.Controller/Providers/IImageEnhancer.cs b/MediaBrowser.Controller/Providers/IImageEnhancer.cs deleted file mode 100644 index c27c00ca2..000000000 --- a/MediaBrowser.Controller/Providers/IImageEnhancer.cs +++ /dev/null @@ -1,61 +0,0 @@ -using System.Threading.Tasks; -using MediaBrowser.Controller.Entities; -using MediaBrowser.Model.Drawing; -using MediaBrowser.Model.Entities; - -namespace MediaBrowser.Controller.Providers -{ - public interface IImageEnhancer - { - /// - /// Return true only if the given image for the given item will be enhanced by this enhancer. - /// - /// The item. - /// Type of the image. - /// true if this enhancer will enhance the supplied image for the supplied item, false otherwise - bool Supports(BaseItem item, ImageType imageType); - - /// - /// Gets the priority or order in which this enhancer should be run. - /// - /// The priority. - MetadataProviderPriority Priority { get; } - - /// - /// Return a key incorporating all configuration information related to this item - /// - /// The item. - /// Type of the image. - /// Cache key relating to the current state of this item and configuration - string GetConfigurationCacheKey(BaseItem item, ImageType imageType); - - /// - /// Gets the size of the enhanced image. - /// - /// The item. - /// Type of the image. - /// Index of the image. - /// Size of the original image. - /// ImageSize. - ImageDimensions GetEnhancedImageSize(BaseItem item, ImageType imageType, int imageIndex, ImageDimensions originalImageSize); - - EnhancedImageInfo GetEnhancedImageInfo(BaseItem item, string inputFile, ImageType imageType, int imageIndex); - - /// - /// Enhances the image async. - /// - /// The item. - /// The input file. - /// The output file. - /// Type of the image. - /// Index of the image. - /// Task{Image}. - /// - Task EnhanceImageAsync(BaseItem item, string inputFile, string outputFile, ImageType imageType, int imageIndex); - } - - public class EnhancedImageInfo - { - public bool RequiresTransparency { get; set; } - } -} diff --git a/MediaBrowser.Model/Drawing/ImageDimensions.cs b/MediaBrowser.Model/Drawing/ImageDimensions.cs index e7805ac49..4bd8d85d4 100644 --- a/MediaBrowser.Model/Drawing/ImageDimensions.cs +++ b/MediaBrowser.Model/Drawing/ImageDimensions.cs @@ -1,36 +1,43 @@ +using System.Globalization; + namespace MediaBrowser.Model.Drawing { /// /// Struct ImageDimensions /// - public struct ImageDimensions + public readonly struct ImageDimensions { + public ImageDimensions(int width, int height) + { + Width = width; + Height = height; + } + /// - /// Gets or sets the height. + /// Gets the height. /// /// The height. - public int Height { get; set; } + public int Height { get; } /// - /// Gets or sets the width. + /// Gets the width. /// /// The width. - public int Width { get; set; } + public int Width { get; } public bool Equals(ImageDimensions size) { return Width.Equals(size.Width) && Height.Equals(size.Height); } + /// public override string ToString() { - return string.Format("{0}-{1}", Width, Height); - } - - public ImageDimensions(int width, int height) - { - Width = width; - Height = height; + return string.Format( + CultureInfo.InvariantCulture, + "{0}-{1}", + Width, + Height); } } } -- cgit v1.2.3 From dc62e436c43362f2193415f4c81280c6c1a8560c Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Wed, 22 Jan 2020 22:18:56 +0100 Subject: Clean up Emby.Naming --- Emby.Naming/Audio/AlbumParser.cs | 11 +- Emby.Naming/Audio/MultiPartResult.cs | 26 ----- Emby.Naming/AudioBook/AudioBookFileInfo.cs | 2 +- Emby.Naming/AudioBook/AudioBookListResolver.cs | 19 +-- Emby.Naming/Common/EpisodeExpression.cs | 36 +++--- Emby.Naming/Common/NamingOptions.cs | 83 ++++++------- Emby.Naming/Emby.Naming.csproj | 5 +- Emby.Naming/TV/EpisodePathParser.cs | 5 +- Emby.Naming/TV/EpisodeResolver.cs | 20 +--- Emby.Naming/TV/SeasonPathParser.cs | 39 ++++--- Emby.Naming/Video/StackResolver.cs | 21 ++-- Emby.Naming/Video/StackResult.cs | 17 --- Emby.Naming/Video/StubResolver.cs | 20 ++-- Emby.Naming/Video/VideoFileInfo.cs | 2 +- Emby.Naming/Video/VideoInfo.cs | 18 +-- Emby.Naming/Video/VideoListResolver.cs | 43 ++++--- Emby.Naming/Video/VideoResolver.cs | 21 ++-- .../Library/LibraryManager.cs | 2 +- .../Library/Resolvers/Audio/MusicAlbumResolver.cs | 20 +--- .../Library/Resolvers/Movies/MovieResolver.cs | 73 ++++++------ .../Library/Resolvers/TV/SeasonResolver.cs | 21 ++-- .../Library/Resolvers/TV/SeriesResolver.cs | 2 +- Jellyfin.Server/Jellyfin.Server.csproj | 3 - .../Music/MultiDiscAlbumTests.cs | 2 +- .../Jellyfin.Naming.Tests/TV/SeasonFolderTests.cs | 3 +- tests/Jellyfin.Naming.Tests/Video/StackTests.cs | 130 ++++++++++----------- tests/Jellyfin.Naming.Tests/Video/StubTests.cs | 10 +- 27 files changed, 287 insertions(+), 367 deletions(-) delete mode 100644 Emby.Naming/Audio/MultiPartResult.cs delete mode 100644 Emby.Naming/Video/StackResult.cs (limited to 'Emby.Server.Implementations') diff --git a/Emby.Naming/Audio/AlbumParser.cs b/Emby.Naming/Audio/AlbumParser.cs index 4975b8e19..b807816eb 100644 --- a/Emby.Naming/Audio/AlbumParser.cs +++ b/Emby.Naming/Audio/AlbumParser.cs @@ -19,15 +19,13 @@ namespace Emby.Naming.Audio _options = options; } - public MultiPartResult ParseMultiPart(string path) + public bool IsMultiPart(string path) { - var result = new MultiPartResult(); - var filename = Path.GetFileName(path); if (string.IsNullOrEmpty(filename)) { - return result; + return false; } // TODO: Move this logic into options object @@ -57,12 +55,11 @@ namespace Emby.Naming.Audio if (int.TryParse(tmp, NumberStyles.Integer, CultureInfo.InvariantCulture, out _)) { - result.IsMultiPart = true; - break; + return true; } } - return result; + return false; } } } diff --git a/Emby.Naming/Audio/MultiPartResult.cs b/Emby.Naming/Audio/MultiPartResult.cs deleted file mode 100644 index 8f68d97fa..000000000 --- a/Emby.Naming/Audio/MultiPartResult.cs +++ /dev/null @@ -1,26 +0,0 @@ -#pragma warning disable CS1591 -#pragma warning disable SA1600 - -namespace Emby.Naming.Audio -{ - public class MultiPartResult - { - /// - /// Gets or sets the name. - /// - /// The name. - public string Name { get; set; } - - /// - /// Gets or sets the part. - /// - /// The part. - public string Part { get; set; } - - /// - /// Gets or sets a value indicating whether this instance is multi part. - /// - /// true if this instance is multi part; otherwise, false. - public bool IsMultiPart { get; set; } - } -} diff --git a/Emby.Naming/AudioBook/AudioBookFileInfo.cs b/Emby.Naming/AudioBook/AudioBookFileInfo.cs index 769e3d7fa..0bc6ec7e4 100644 --- a/Emby.Naming/AudioBook/AudioBookFileInfo.cs +++ b/Emby.Naming/AudioBook/AudioBookFileInfo.cs @@ -32,7 +32,7 @@ namespace Emby.Naming.AudioBook public int? ChapterNumber { get; set; } /// - /// Gets or sets the type. + /// Gets or sets a value indicating whether this instance is a directory. /// /// The type. public bool IsDirectory { get; set; } diff --git a/Emby.Naming/AudioBook/AudioBookListResolver.cs b/Emby.Naming/AudioBook/AudioBookListResolver.cs index 97f359285..835e83a08 100644 --- a/Emby.Naming/AudioBook/AudioBookListResolver.cs +++ b/Emby.Naming/AudioBook/AudioBookListResolver.cs @@ -39,9 +39,7 @@ namespace Emby.Naming.AudioBook var stackResult = new StackResolver(_options) .ResolveAudioBooks(metadata); - var list = new List(); - - foreach (var stack in stackResult.Stacks) + foreach (var stack in stackResult) { var stackFiles = stack.Files.Select(i => audioBookResolver.Resolve(i, stack.IsDirectoryStack)).ToList(); stackFiles.Sort(); @@ -50,20 +48,9 @@ namespace Emby.Naming.AudioBook Files = stackFiles, Name = stack.Name }; - list.Add(info); - } - - // Whatever files are left, just add them - /*list.AddRange(remainingFiles.Select(i => new AudioBookInfo - { - Files = new List { i }, - Name = i., - Year = i.Year - }));*/ - - var orderedList = list.OrderBy(i => i.Name); - return orderedList; + yield return info; + } } } } diff --git a/Emby.Naming/Common/EpisodeExpression.cs b/Emby.Naming/Common/EpisodeExpression.cs index 30a74fb65..f60f7e84b 100644 --- a/Emby.Naming/Common/EpisodeExpression.cs +++ b/Emby.Naming/Common/EpisodeExpression.cs @@ -11,6 +11,24 @@ namespace Emby.Naming.Common private string _expression; private Regex _regex; + public EpisodeExpression(string expression, bool byDate) + { + Expression = expression; + IsByDate = byDate; + DateTimeFormats = Array.Empty(); + SupportsAbsoluteEpisodeNumbers = true; + } + + public EpisodeExpression(string expression) + : this(expression, false) + { + } + + public EpisodeExpression() + : this(null) + { + } + public string Expression { get => _expression; @@ -32,23 +50,5 @@ namespace Emby.Naming.Common public string[] DateTimeFormats { get; set; } public Regex Regex => _regex ?? (_regex = new Regex(Expression, RegexOptions.IgnoreCase | RegexOptions.Compiled)); - - public EpisodeExpression(string expression, bool byDate) - { - Expression = expression; - IsByDate = byDate; - DateTimeFormats = Array.Empty(); - SupportsAbsoluteEpisodeNumbers = true; - } - - public EpisodeExpression(string expression) - : this(expression, false) - { - } - - public EpisodeExpression() - : this(null) - { - } } } diff --git a/Emby.Naming/Common/NamingOptions.cs b/Emby.Naming/Common/NamingOptions.cs index 9ce503b8e..1554e61d8 100644 --- a/Emby.Naming/Common/NamingOptions.cs +++ b/Emby.Naming/Common/NamingOptions.cs @@ -11,46 +11,6 @@ namespace Emby.Naming.Common { public class NamingOptions { - public string[] AudioFileExtensions { get; set; } - - public string[] AlbumStackingPrefixes { get; set; } - - public string[] SubtitleFileExtensions { get; set; } - - public char[] SubtitleFlagDelimiters { get; set; } - - public string[] SubtitleForcedFlags { get; set; } - - public string[] SubtitleDefaultFlags { get; set; } - - public EpisodeExpression[] EpisodeExpressions { get; set; } - - public string[] EpisodeWithoutSeasonExpressions { get; set; } - - public string[] EpisodeMultiPartExpressions { get; set; } - - public string[] VideoFileExtensions { get; set; } - - public string[] StubFileExtensions { get; set; } - - public string[] AudioBookPartsExpressions { get; set; } - - public StubTypeRule[] StubTypes { get; set; } - - public char[] VideoFlagDelimiters { get; set; } - - public Format3DRule[] Format3DRules { get; set; } - - public string[] VideoFileStackingExpressions { get; set; } - - public string[] CleanDateTimes { get; set; } - - public string[] CleanStrings { get; set; } - - public EpisodeExpression[] MultipleEpisodeExpressions { get; set; } - - public ExtraRule[] VideoExtraRules { get; set; } - public NamingOptions() { VideoFileExtensions = new[] @@ -681,11 +641,54 @@ namespace Emby.Naming.Common Compile(); } + public string[] AudioFileExtensions { get; set; } + + public string[] AlbumStackingPrefixes { get; set; } + + public string[] SubtitleFileExtensions { get; set; } + + public char[] SubtitleFlagDelimiters { get; set; } + + public string[] SubtitleForcedFlags { get; set; } + + public string[] SubtitleDefaultFlags { get; set; } + + public EpisodeExpression[] EpisodeExpressions { get; set; } + + public string[] EpisodeWithoutSeasonExpressions { get; set; } + + public string[] EpisodeMultiPartExpressions { get; set; } + + public string[] VideoFileExtensions { get; set; } + + public string[] StubFileExtensions { get; set; } + + public string[] AudioBookPartsExpressions { get; set; } + + public StubTypeRule[] StubTypes { get; set; } + + public char[] VideoFlagDelimiters { get; set; } + + public Format3DRule[] Format3DRules { get; set; } + + public string[] VideoFileStackingExpressions { get; set; } + + public string[] CleanDateTimes { get; set; } + + public string[] CleanStrings { get; set; } + + public EpisodeExpression[] MultipleEpisodeExpressions { get; set; } + + public ExtraRule[] VideoExtraRules { get; set; } + public Regex[] VideoFileStackingRegexes { get; private set; } + public Regex[] CleanDateTimeRegexes { get; private set; } + public Regex[] CleanStringRegexes { get; private set; } public Regex[] EpisodeWithoutSeasonRegexes { get; private set; } + public Regex[] EpisodeMultiPartRegexes { get; private set; } public void Compile() diff --git a/Emby.Naming/Emby.Naming.csproj b/Emby.Naming/Emby.Naming.csproj index 900b9694c..4e08170a4 100644 --- a/Emby.Naming/Emby.Naming.csproj +++ b/Emby.Naming/Emby.Naming.csproj @@ -4,9 +4,6 @@ netstandard2.1 false true - - - true @@ -27,7 +24,7 @@ - + diff --git a/Emby.Naming/TV/EpisodePathParser.cs b/Emby.Naming/TV/EpisodePathParser.cs index 6b557d2e1..b97b3137b 100644 --- a/Emby.Naming/TV/EpisodePathParser.cs +++ b/Emby.Naming/TV/EpisodePathParser.cs @@ -1,5 +1,6 @@ #pragma warning disable CS1591 #pragma warning disable SA1600 +#nullable enable using System; using System.Collections.Generic; @@ -28,7 +29,7 @@ namespace Emby.Naming.TV path += ".mp4"; } - EpisodePathParserResult result = null; + EpisodePathParserResult? result = null; foreach (var expression in _options.EpisodeExpressions) { @@ -136,7 +137,7 @@ namespace Emby.Naming.TV // It avoids erroneous parsing of something like "series-s09e14-1080p.mkv" as a multi-episode from E14 to E108 int nextIndex = endingNumberGroup.Index + endingNumberGroup.Length; if (nextIndex >= name.Length - || "0123456789iIpP".IndexOf(name[nextIndex]) == -1) + || !"0123456789iIpP".Contains(name[nextIndex], StringComparison.Ordinal)) { if (int.TryParse(endingNumberGroup.Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out num)) { diff --git a/Emby.Naming/TV/EpisodeResolver.cs b/Emby.Naming/TV/EpisodeResolver.cs index 5e115fc75..57659ee13 100644 --- a/Emby.Naming/TV/EpisodeResolver.cs +++ b/Emby.Naming/TV/EpisodeResolver.cs @@ -1,5 +1,6 @@ #pragma warning disable CS1591 #pragma warning disable SA1600 +#nullable enable using System; using System.IO; @@ -18,7 +19,7 @@ namespace Emby.Naming.TV _options = options; } - public EpisodeInfo Resolve( + public EpisodeInfo? Resolve( string path, bool isDirectory, bool? isNamed = null, @@ -26,14 +27,9 @@ namespace Emby.Naming.TV bool? supportsAbsoluteNumbers = null, bool fillExtendedInfo = true) { - if (string.IsNullOrEmpty(path)) - { - throw new ArgumentNullException(nameof(path)); - } - bool isStub = false; - string container = null; - string stubType = null; + string? container = null; + string? stubType = null; if (!isDirectory) { @@ -41,17 +37,13 @@ namespace Emby.Naming.TV // Check supported extensions if (!_options.VideoFileExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase)) { - var stubResult = StubResolver.ResolveFile(path, _options); - - isStub = stubResult.IsStub; - // It's not supported. Check stub extensions - if (!isStub) + if (!StubResolver.TryResolveFile(path, _options, out stubType)) { return null; } - stubType = stubResult.StubType; + isStub = true; } container = extension.TrimStart('.'); diff --git a/Emby.Naming/TV/SeasonPathParser.cs b/Emby.Naming/TV/SeasonPathParser.cs index e5f90e966..7715a16a4 100644 --- a/Emby.Naming/TV/SeasonPathParser.cs +++ b/Emby.Naming/TV/SeasonPathParser.cs @@ -8,9 +8,24 @@ using System.Linq; namespace Emby.Naming.TV { - public class SeasonPathParser + public static class SeasonPathParser { - public SeasonPathParserResult Parse(string path, bool supportSpecialAliases, bool supportNumericSeasonFolders) + /// + /// A season folder must contain one of these somewhere in the name. + /// + private static readonly string[] _seasonFolderNames = + { + "season", + "sæson", + "temporada", + "saison", + "staffel", + "series", + "сезон", + "stagione" + }; + + public static SeasonPathParserResult Parse(string path, bool supportSpecialAliases, bool supportNumericSeasonFolders) { var result = new SeasonPathParserResult(); @@ -27,21 +42,6 @@ namespace Emby.Naming.TV return result; } - /// - /// A season folder must contain one of these somewhere in the name. - /// - private static readonly string[] _seasonFolderNames = - { - "season", - "sæson", - "temporada", - "saison", - "staffel", - "series", - "сезон", - "stagione" - }; - /// /// Gets the season number from path. /// @@ -150,6 +150,7 @@ namespace Emby.Naming.TV { numericStart = i; } + length++; } } @@ -161,11 +162,11 @@ namespace Emby.Naming.TV } var currentChar = path[i]; - if (currentChar.Equals('(')) + if (currentChar == '(') { hasOpenParenth = true; } - else if (currentChar.Equals(')')) + else if (currentChar == ')') { hasOpenParenth = false; } diff --git a/Emby.Naming/Video/StackResolver.cs b/Emby.Naming/Video/StackResolver.cs index e7a769ae6..8f210fa45 100644 --- a/Emby.Naming/Video/StackResolver.cs +++ b/Emby.Naming/Video/StackResolver.cs @@ -20,7 +20,7 @@ namespace Emby.Naming.Video _options = options; } - public StackResult ResolveDirectories(IEnumerable files) + public IEnumerable ResolveDirectories(IEnumerable files) { return Resolve(files.Select(i => new FileSystemMetadata { @@ -29,7 +29,7 @@ namespace Emby.Naming.Video })); } - public StackResult ResolveFiles(IEnumerable files) + public IEnumerable ResolveFiles(IEnumerable files) { return Resolve(files.Select(i => new FileSystemMetadata { @@ -38,9 +38,8 @@ namespace Emby.Naming.Video })); } - public StackResult ResolveAudioBooks(IEnumerable files) + public IEnumerable ResolveAudioBooks(IEnumerable files) { - var result = new StackResult(); foreach (var directory in files.GroupBy(file => file.IsDirectory ? file.FullName : Path.GetDirectoryName(file.FullName))) { var stack = new FileStack() @@ -58,20 +57,16 @@ namespace Emby.Naming.Video stack.Files.Add(file.FullName); } - result.Stacks.Add(stack); + yield return stack; } - - return result; } - public StackResult Resolve(IEnumerable files) + public IEnumerable Resolve(IEnumerable files) { - var result = new StackResult(); - var resolver = new VideoResolver(_options); var list = files - .Where(i => i.IsDirectory || (resolver.IsVideoFile(i.FullName) || resolver.IsStubFile(i.FullName))) + .Where(i => i.IsDirectory || resolver.IsVideoFile(i.FullName) || resolver.IsStubFile(i.FullName)) .OrderBy(i => i.FullName) .ToList(); @@ -191,14 +186,12 @@ namespace Emby.Naming.Video if (stack.Files.Count > 1) { - result.Stacks.Add(stack); + yield return stack; i += stack.Files.Count - 1; break; } } } - - return result; } private string GetRegexInput(FileSystemMetadata file) diff --git a/Emby.Naming/Video/StackResult.cs b/Emby.Naming/Video/StackResult.cs deleted file mode 100644 index 31ef2d69c..000000000 --- a/Emby.Naming/Video/StackResult.cs +++ /dev/null @@ -1,17 +0,0 @@ -#pragma warning disable CS1591 -#pragma warning disable SA1600 - -using System.Collections.Generic; - -namespace Emby.Naming.Video -{ - public class StackResult - { - public List Stacks { get; set; } - - public StackResult() - { - Stacks = new List(); - } - } -} diff --git a/Emby.Naming/Video/StubResolver.cs b/Emby.Naming/Video/StubResolver.cs index 95868e89d..4024d6d59 100644 --- a/Emby.Naming/Video/StubResolver.cs +++ b/Emby.Naming/Video/StubResolver.cs @@ -1,5 +1,6 @@ #pragma warning disable CS1591 #pragma warning disable SA1600 +#nullable enable using System; using System.IO; @@ -10,25 +11,22 @@ namespace Emby.Naming.Video { public static class StubResolver { - public static StubResult ResolveFile(string path, NamingOptions options) + public static bool TryResolveFile(string path, NamingOptions options, out string? stubType) { + stubType = default; + if (path == null) { - return default; + return false; } var extension = Path.GetExtension(path); if (!options.StubFileExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase)) { - return default; + return false; } - var result = new StubResult() - { - IsStub = true - }; - path = Path.GetFileNameWithoutExtension(path); var token = Path.GetExtension(path).TrimStart('.'); @@ -36,12 +34,12 @@ namespace Emby.Naming.Video { if (string.Equals(rule.Token, token, StringComparison.OrdinalIgnoreCase)) { - result.StubType = rule.StubType; - break; + stubType = rule.StubType; + return true; } } - return result; + return true; } } } diff --git a/Emby.Naming/Video/VideoFileInfo.cs b/Emby.Naming/Video/VideoFileInfo.cs index 90c798da1..aa4f3a35c 100644 --- a/Emby.Naming/Video/VideoFileInfo.cs +++ b/Emby.Naming/Video/VideoFileInfo.cs @@ -68,7 +68,7 @@ namespace Emby.Naming.Video public string StubType { get; set; } /// - /// Gets or sets the type. + /// Gets or sets a value indicating whether this instance is a directory. /// /// The type. public bool IsDirectory { get; set; } diff --git a/Emby.Naming/Video/VideoInfo.cs b/Emby.Naming/Video/VideoInfo.cs index a585bb99a..ea74c40e2 100644 --- a/Emby.Naming/Video/VideoInfo.cs +++ b/Emby.Naming/Video/VideoInfo.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; namespace Emby.Naming.Video @@ -10,11 +11,14 @@ namespace Emby.Naming.Video /// /// Initializes a new instance of the class. /// - public VideoInfo() + /// The name. + public VideoInfo(string name) { - Files = new List(); - Extras = new List(); - AlternateVersions = new List(); + Name = name; + + Files = Array.Empty(); + Extras = Array.Empty(); + AlternateVersions = Array.Empty(); } /// @@ -33,18 +37,18 @@ namespace Emby.Naming.Video /// Gets or sets the files. /// /// The files. - public List Files { get; set; } + public IReadOnlyList Files { get; set; } /// /// Gets or sets the extras. /// /// The extras. - public List Extras { get; set; } + public IReadOnlyList Extras { get; set; } /// /// Gets or sets the alternate versions. /// /// The alternate versions. - public List AlternateVersions { get; set; } + public IReadOnlyList AlternateVersions { get; set; } } } diff --git a/Emby.Naming/Video/VideoListResolver.cs b/Emby.Naming/Video/VideoListResolver.cs index 87498000c..136658353 100644 --- a/Emby.Naming/Video/VideoListResolver.cs +++ b/Emby.Naming/Video/VideoListResolver.cs @@ -41,20 +41,19 @@ namespace Emby.Naming.Video }); var stackResult = new StackResolver(_options) - .Resolve(nonExtras); + .Resolve(nonExtras).ToList(); var remainingFiles = videoInfos - .Where(i => !stackResult.Stacks.Any(s => s.ContainsFile(i.Path, i.IsDirectory))) + .Where(i => !stackResult.Any(s => s.ContainsFile(i.Path, i.IsDirectory))) .ToList(); var list = new List(); - foreach (var stack in stackResult.Stacks) + foreach (var stack in stackResult) { - var info = new VideoInfo + var info = new VideoInfo(stack.Name) { - Files = stack.Files.Select(i => videoResolver.Resolve(i, stack.IsDirectoryStack)).ToList(), - Name = stack.Name + Files = stack.Files.Select(i => videoResolver.Resolve(i, stack.IsDirectoryStack)).ToList() }; info.Year = info.Files[0].Year; @@ -85,10 +84,9 @@ namespace Emby.Naming.Video foreach (var media in standaloneMedia) { - var info = new VideoInfo + var info = new VideoInfo(media.Name) { - Files = new List { media }, - Name = media.Name + Files = new List { media } }; info.Year = info.Files[0].Year; @@ -128,7 +126,8 @@ namespace Emby.Naming.Video .Except(extras) .ToList(); - info.Extras.AddRange(extras); + extras.AddRange(info.Extras); + info.Extras = extras; } } @@ -141,7 +140,8 @@ namespace Emby.Naming.Video .Except(extrasByFileName) .ToList(); - info.Extras.AddRange(extrasByFileName); + extrasByFileName.AddRange(info.Extras); + info.Extras = extrasByFileName; } // If there's only one video, accept all trailers @@ -152,7 +152,8 @@ namespace Emby.Naming.Video .Where(i => i.ExtraType == ExtraType.Trailer) .ToList(); - list[0].Extras.AddRange(trailers); + trailers.AddRange(list[0].Extras); + list[0].Extras = trailers; remainingFiles = remainingFiles .Except(trailers) @@ -160,14 +161,13 @@ namespace Emby.Naming.Video } // Whatever files are left, just add them - list.AddRange(remainingFiles.Select(i => new VideoInfo + list.AddRange(remainingFiles.Select(i => new VideoInfo(i.Name) { Files = new List { i }, - Name = i.Name, Year = i.Year })); - return list.OrderBy(i => i.Name); + return list; } private IEnumerable GetVideosGroupedByVersion(List videos) @@ -191,9 +191,18 @@ namespace Emby.Naming.Video list.Add(ordered[0]); - list[0].AlternateVersions = ordered.Skip(1).Select(i => i.Files[0]).ToList(); + var alternateVersionsLen = ordered.Count - 1; + var alternateVersions = new VideoFileInfo[alternateVersionsLen]; + for (int i = 0; i < alternateVersionsLen; i++) + { + alternateVersions[i] = ordered[i + 1].Files[0]; + } + + list[0].AlternateVersions = alternateVersions; list[0].Name = folderName; - list[0].Extras.AddRange(ordered.Skip(1).SelectMany(i => i.Extras)); + var extras = ordered.Skip(1).SelectMany(i => i.Extras).ToList(); + extras.AddRange(list[0].Extras); + list[0].Extras = extras; return list; } diff --git a/Emby.Naming/Video/VideoResolver.cs b/Emby.Naming/Video/VideoResolver.cs index f93db2486..699bbe40a 100644 --- a/Emby.Naming/Video/VideoResolver.cs +++ b/Emby.Naming/Video/VideoResolver.cs @@ -1,5 +1,6 @@ #pragma warning disable CS1591 #pragma warning disable SA1600 +#nullable enable using System; using System.IO; @@ -22,7 +23,7 @@ namespace Emby.Naming.Video /// /// The path. /// VideoFileInfo. - public VideoFileInfo ResolveDirectory(string path) + public VideoFileInfo? ResolveDirectory(string path) { return Resolve(path, true); } @@ -32,7 +33,7 @@ namespace Emby.Naming.Video /// /// The path. /// VideoFileInfo. - public VideoFileInfo ResolveFile(string path) + public VideoFileInfo? ResolveFile(string path) { return Resolve(path, false); } @@ -42,10 +43,10 @@ namespace Emby.Naming.Video /// /// The path. /// if set to true [is folder]. - /// Whether or not the name should be parsed for info + /// Whether or not the name should be parsed for info. /// VideoFileInfo. /// path is null. - public VideoFileInfo Resolve(string path, bool isDirectory, bool parseName = true) + public VideoFileInfo? Resolve(string path, bool isDirectory, bool parseName = true) { if (string.IsNullOrEmpty(path)) { @@ -53,8 +54,8 @@ namespace Emby.Naming.Video } bool isStub = false; - string container = null; - string stubType = null; + string? container = null; + string? stubType = null; if (!isDirectory) { @@ -63,17 +64,13 @@ namespace Emby.Naming.Video // Check supported extensions if (!_options.VideoFileExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase)) { - var stubResult = StubResolver.ResolveFile(path, _options); - - isStub = stubResult.IsStub; - // It's not supported. Check stub extensions - if (!isStub) + if (!StubResolver.TryResolveFile(path, _options, out stubType)) { return null; } - stubType = stubResult.StubType; + isStub = true; } container = extension.TrimStart('.'); diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index 6fb623554..5c04631da 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -2384,7 +2384,7 @@ namespace Emby.Server.Implementations.Library public int? GetSeasonNumberFromPath(string path) { - return new SeasonPathParser().Parse(path, true, true).SeasonNumber; + return SeasonPathParser.Parse(path, true, true).SeasonNumber; } public bool FillMissingEpisodeNumbersFromPath(Episode episode, bool forceRefresh) diff --git a/Emby.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs b/Emby.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs index 4a2d210d5..9f858f98d 100644 --- a/Emby.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs @@ -76,7 +76,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio } /// - /// Determine if the supplied file data points to a music album + /// Determine if the supplied file data points to a music album. /// public bool IsMusicAlbum(string path, IDirectoryService directoryService, LibraryOptions libraryOptions) { @@ -84,7 +84,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio } /// - /// Determine if the supplied resolve args should be considered a music album + /// Determine if the supplied resolve args should be considered a music album. /// /// The args. /// true if [is music album] [the specified args]; otherwise, false. @@ -104,7 +104,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio } /// - /// Determine if the supplied list contains what we should consider music + /// Determine if the supplied list contains what we should consider music. /// private bool ContainsMusic( IEnumerable list, @@ -118,6 +118,8 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio var discSubfolderCount = 0; var notMultiDisc = false; + var namingOptions = ((LibraryManager)_libraryManager).GetNamingOptions(); + var parser = new AlbumParser(namingOptions); foreach (var fileSystemInfo in list) { if (fileSystemInfo.IsDirectory) @@ -134,7 +136,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio if (hasMusic) { - if (IsMultiDiscFolder(path, libraryOptions)) + if (parser.IsMultiPart(path)) { logger.LogDebug("Found multi-disc folder: " + path); discSubfolderCount++; @@ -165,15 +167,5 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio return discSubfolderCount > 0; } - - private bool IsMultiDiscFolder(string path, LibraryOptions libraryOptions) - { - var namingOptions = ((LibraryManager)_libraryManager).GetNamingOptions(); - - var parser = new AlbumParser(namingOptions); - var result = parser.ParseMultiPart(path); - - return result.IsMultiPart; - } } } diff --git a/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs b/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs index 6c7690055..08db168bc 100644 --- a/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs @@ -21,6 +21,28 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies /// public class MovieResolver : BaseVideoResolver