From bbc08753878b7b8a37ed876385d2e6864349d00d Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Sun, 20 Oct 2019 16:08:40 +0200 Subject: Don't shuffle some types by default --- .../Session/SessionManager.cs | 50 +++++++++++----------- 1 file changed, 24 insertions(+), 26 deletions(-) (limited to 'Emby.Server.Implementations/Session') diff --git a/Emby.Server.Implementations/Session/SessionManager.cs b/Emby.Server.Implementations/Session/SessionManager.cs index 61329160ae..68cd3c0bae 100644 --- a/Emby.Server.Implementations/Session/SessionManager.cs +++ b/Emby.Server.Implementations/Session/SessionManager.cs @@ -1061,7 +1061,7 @@ namespace Emby.Server.Implementations.Session var session = GetSessionToRemoteControl(sessionId); - var user = !session.UserId.Equals(Guid.Empty) ? _userManager.GetUserById(session.UserId) : null; + var user = session.UserId == Guid.Empty ? null : _userManager.GetUserById(session.UserId); List items; @@ -1086,7 +1086,7 @@ namespace Emby.Server.Implementations.Session if (command.PlayCommand == PlayCommand.PlayShuffle) { - items = items.OrderBy(i => Guid.NewGuid()).ToList(); + items.Shuffle(); command.PlayCommand = PlayCommand.PlayNow; } @@ -1100,28 +1100,27 @@ namespace Emby.Server.Implementations.Session } } - if (user != null && command.ItemIds.Length == 1 && user.Configuration.EnableNextEpisodeAutoPlay) + if (user != null + && command.ItemIds.Length == 1 + && user.Configuration.EnableNextEpisodeAutoPlay + && _libraryManager.GetItemById(command.ItemIds[0]) is Episode episode) { - var episode = _libraryManager.GetItemById(command.ItemIds[0]) as Episode; - if (episode != null) + var series = episode.Series; + if (series != null) { - var series = episode.Series; - if (series != null) + var episodes = series.GetEpisodes( + user, + new DtoOptions(false) + { + EnableImages = false + }) + .Where(i => !i.IsVirtualItem) + .SkipWhile(i => i.Id != episode.Id) + .ToList(); + + if (episodes.Count > 0) { - var episodes = series.GetEpisodes( - user, - new DtoOptions(false) - { - EnableImages = false - }) - .Where(i => !i.IsVirtualItem) - .SkipWhile(i => i.Id != episode.Id) - .ToList(); - - if (episodes.Count > 0) - { - command.ItemIds = episodes.Select(i => i.Id).ToArray(); - } + command.ItemIds = episodes.Select(i => i.Id).ToArray(); } } } @@ -1146,7 +1145,7 @@ namespace Emby.Server.Implementations.Session if (item == null) { _logger.LogError("A non-existant item Id {0} was passed into TranslateItemForPlayback", id); - return new List(); + return Array.Empty(); } if (item is IItemByName byName) @@ -1164,7 +1163,7 @@ namespace Emby.Server.Implementations.Session } }, IsVirtualItem = false, - OrderBy = new ValueTuple[] { new ValueTuple(ItemSortBy.SortName, SortOrder.Ascending) } + OrderBy = new[] { (ItemSortBy.SortName, SortOrder.Ascending) } }); } @@ -1185,12 +1184,11 @@ namespace Emby.Server.Implementations.Session } }, IsVirtualItem = false, - OrderBy = new ValueTuple[] { new ValueTuple(ItemSortBy.SortName, SortOrder.Ascending) } - + OrderBy = new[] { (ItemSortBy.SortName, SortOrder.Ascending) } }); } - return new List { item }; + return new[] { item }; } private IEnumerable TranslateItemForInstantMix(Guid id, User user) -- cgit v1.2.3 From fef35d0505c6485954b1eb233a5ea67e33fe1138 Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Sun, 20 Oct 2019 21:12:03 +0200 Subject: Add clearer exceptions, warnings and docs --- .../Cryptography/CryptographyProvider.cs | 10 +++----- .../Library/DefaultAuthenticationProvider.cs | 5 +++- Emby.Server.Implementations/Library/UserManager.cs | 20 +++++----------- .../Library/UserViewManager.cs | 20 ++++++++-------- .../Session/SessionManager.cs | 27 +++++++++++----------- MediaBrowser.Api/UserLibrary/UserViewsService.cs | 8 ++++++- MediaBrowser.Common/Cryptography/PasswordHash.cs | 6 ++--- MediaBrowser.Controller/Entities/Folder.cs | 10 +++++++- MediaBrowser.Controller/Library/IUserManager.cs | 10 +++++--- MediaBrowser.Model/Cryptography/ICryptoProvider.cs | 4 ---- 10 files changed, 63 insertions(+), 57 deletions(-) (limited to 'Emby.Server.Implementations/Session') diff --git a/Emby.Server.Implementations/Cryptography/CryptographyProvider.cs b/Emby.Server.Implementations/Cryptography/CryptographyProvider.cs index 23b77e2687..fec7d161e5 100644 --- a/Emby.Server.Implementations/Cryptography/CryptographyProvider.cs +++ b/Emby.Server.Implementations/Cryptography/CryptographyProvider.cs @@ -30,6 +30,9 @@ namespace Emby.Server.Implementations.Cryptography private bool _disposed = false; + /// + /// Initializes a new instance of the class. + /// public CryptographyProvider() { // FIXME: When we get DotNet Standard 2.1 we need to revisit how we do the crypto @@ -59,12 +62,6 @@ namespace Emby.Server.Implementations.Cryptography throw new CryptographicException($"Cannot currently use PBKDF2 with requested hash method: {method}"); } - public byte[] ComputeHash(string hashMethod, byte[] bytes) - => ComputeHash(hashMethod, bytes, Array.Empty()); - - public byte[] ComputeHashWithDefaultMethod(byte[] bytes) - => ComputeHash(DefaultHashMethod, bytes); - public byte[] ComputeHash(string hashMethod, byte[] bytes, byte[] salt) { if (hashMethod == DefaultHashMethod) @@ -90,7 +87,6 @@ namespace Emby.Server.Implementations.Cryptography } throw new CryptographicException($"Requested hash method is not supported: {hashMethod}"); - } public byte[] ComputeHashWithDefaultMethod(byte[] bytes, byte[] salt) diff --git a/Emby.Server.Implementations/Library/DefaultAuthenticationProvider.cs b/Emby.Server.Implementations/Library/DefaultAuthenticationProvider.cs index c95b00ede2..a1143471da 100644 --- a/Emby.Server.Implementations/Library/DefaultAuthenticationProvider.cs +++ b/Emby.Server.Implementations/Library/DefaultAuthenticationProvider.cs @@ -59,7 +59,10 @@ namespace Emby.Server.Implementations.Library if (_cryptographyProvider.GetSupportedHashMethods().Contains(readyHash.Id) || _cryptographyProvider.DefaultHashMethod == readyHash.Id) { - byte[] calculatedHash = _cryptographyProvider.ComputeHash(readyHash.Id, passwordbytes, readyHash.Salt); + byte[] calculatedHash = _cryptographyProvider.ComputeHash( + readyHash.Id, + passwordbytes, + readyHash.Salt); if (calculatedHash.SequenceEqual(readyHash.Hash)) { diff --git a/Emby.Server.Implementations/Library/UserManager.cs b/Emby.Server.Implementations/Library/UserManager.cs index 52b2f56ffc..3d1030d4bb 100644 --- a/Emby.Server.Implementations/Library/UserManager.cs +++ b/Emby.Server.Implementations/Library/UserManager.cs @@ -179,12 +179,7 @@ namespace Emby.Server.Implementations.Library _defaultPasswordResetProvider = passwordResetProviders.OfType().First(); } - /// - /// Gets a User by Id. - /// - /// The id. - /// User. - /// + /// public User GetUserById(Guid id) { if (id == Guid.Empty) @@ -196,11 +191,7 @@ namespace Emby.Server.Implementations.Library return user; } - /// - /// Gets the user by identifier. - /// - /// The identifier. - /// User. + /// public User GetUserById(string id) => GetUserById(new Guid(id)); @@ -428,7 +419,6 @@ namespace Emby.Server.Implementations.Library { try { - var authenticationResult = provider is IRequiresResolvedUser requiresResolvedUser ? await requiresResolvedUser.Authenticate(username, password, resolvedUser).ConfigureAwait(false) : await provider.Authenticate(username, password).ConfigureAwait(false); @@ -538,6 +528,8 @@ namespace Emby.Server.Implementations.Library defaultName = "MyJellyfinUser"; } + _logger.LogWarning("No users, creating one with username {UserName}", defaultName); + var name = MakeValidUsername(defaultName); var user = InstantiateNewUser(name); @@ -601,7 +593,7 @@ namespace Emby.Server.Implementations.Library catch (Exception ex) { // Have to use a catch-all unfortunately because some .net image methods throw plain Exceptions - _logger.LogError(ex, "Error generating PrimaryImageAspectRatio for {user}", user.Name); + _logger.LogError(ex, "Error generating PrimaryImageAspectRatio for {User}", user.Name); } } @@ -625,7 +617,7 @@ namespace Emby.Server.Implementations.Library } catch (Exception ex) { - _logger.LogError(ex, "Error getting {imageType} image info for {imagePath}", image.Type, image.Path); + _logger.LogError(ex, "Error getting {ImageType} image info for {ImagePath}", image.Type, image.Path); return null; } } diff --git a/Emby.Server.Implementations/Library/UserViewManager.cs b/Emby.Server.Implementations/Library/UserViewManager.cs index 88e2a8fa69..474884e428 100644 --- a/Emby.Server.Implementations/Library/UserViewManager.cs +++ b/Emby.Server.Implementations/Library/UserViewManager.cs @@ -42,6 +42,11 @@ namespace Emby.Server.Implementations.Library { var user = _userManager.GetUserById(query.UserId); + if (user == null) + { + throw new ArgumentException("User Id does not exists.", nameof(query)); + } + var folders = _libraryManager.GetUserRootFolder() .GetChildren(user, true) .OfType() @@ -54,7 +59,7 @@ namespace Emby.Server.Implementations.Library foreach (var folder in folders) { var collectionFolder = folder as ICollectionFolder; - var folderViewType = collectionFolder == null ? null : collectionFolder.CollectionType; + var folderViewType = collectionFolder?.CollectionType; if (UserView.IsUserSpecific(folder)) { @@ -130,16 +135,11 @@ namespace Emby.Server.Implementations.Library { var index = orders.IndexOf(i.Id.ToString("N", CultureInfo.InvariantCulture)); - if (index == -1) + if (index == -1 + && i is UserView view + && view.DisplayParentId != Guid.Empty) { - var view = i as UserView; - if (view != null) - { - if (!view.DisplayParentId.Equals(Guid.Empty)) - { - index = orders.IndexOf(view.DisplayParentId.ToString("N", CultureInfo.InvariantCulture)); - } - } + index = orders.IndexOf(view.DisplayParentId.ToString("N", CultureInfo.InvariantCulture)); } return index == -1 ? int.MaxValue : index; diff --git a/Emby.Server.Implementations/Session/SessionManager.cs b/Emby.Server.Implementations/Session/SessionManager.cs index 61329160ae..d1392e1623 100644 --- a/Emby.Server.Implementations/Session/SessionManager.cs +++ b/Emby.Server.Implementations/Session/SessionManager.cs @@ -1388,27 +1388,28 @@ namespace Emby.Server.Implementations.Session if (user != null) { // TODO: Move this to userManager? - if (!string.IsNullOrEmpty(request.DeviceId)) + if (!string.IsNullOrEmpty(request.DeviceId) + && !_deviceManager.CanAccessDevice(user, request.DeviceId)) { - if (!_deviceManager.CanAccessDevice(user, request.DeviceId)) - { - throw new SecurityException("User is not allowed access from this device."); - } + throw new SecurityException("User is not allowed access from this device."); } } if (enforcePassword) { - var result = await _userManager.AuthenticateUser(request.Username, request.Password, request.PasswordSha1, request.RemoteEndPoint, true).ConfigureAwait(false); - - if (result == null) - { - AuthenticationFailed?.Invoke(this, new GenericEventArgs(request)); + user = await _userManager.AuthenticateUser( + request.Username, + request.Password, + request.PasswordSha1, + request.RemoteEndPoint, + true).ConfigureAwait(false); + } - throw new SecurityException("Invalid user or password entered."); - } + if (user == null) + { + AuthenticationFailed?.Invoke(this, new GenericEventArgs(request)); - user = result; + throw new SecurityException("Invalid user or password entered."); } var token = GetAuthorizationToken(user, request.DeviceId, request.App, request.AppVersion, request.DeviceName); diff --git a/MediaBrowser.Api/UserLibrary/UserViewsService.cs b/MediaBrowser.Api/UserLibrary/UserViewsService.cs index 2fa5d8933c..d62049ce9e 100644 --- a/MediaBrowser.Api/UserLibrary/UserViewsService.cs +++ b/MediaBrowser.Api/UserLibrary/UserViewsService.cs @@ -10,6 +10,7 @@ using MediaBrowser.Model.Entities; using MediaBrowser.Model.Library; using MediaBrowser.Model.Querying; using MediaBrowser.Model.Services; +using Microsoft.Extensions.Logging; namespace MediaBrowser.Api.UserLibrary { @@ -49,7 +50,12 @@ namespace MediaBrowser.Api.UserLibrary private readonly IAuthorizationContext _authContext; private readonly ILibraryManager _libraryManager; - public UserViewsService(IUserManager userManager, IUserViewManager userViewManager, IDtoService dtoService, IAuthorizationContext authContext, ILibraryManager libraryManager) + public UserViewsService( + IUserManager userManager, + IUserViewManager userViewManager, + IDtoService dtoService, + IAuthorizationContext authContext, + ILibraryManager libraryManager) { _userManager = userManager; _userViewManager = userViewManager; diff --git a/MediaBrowser.Common/Cryptography/PasswordHash.cs b/MediaBrowser.Common/Cryptography/PasswordHash.cs index 7741571db9..1cb70675c6 100644 --- a/MediaBrowser.Common/Cryptography/PasswordHash.cs +++ b/MediaBrowser.Common/Cryptography/PasswordHash.cs @@ -61,13 +61,13 @@ namespace MediaBrowser.Common.Cryptography /// Return the hashed password. public byte[] Hash { get; } - public static PasswordHash Parse(string storageString) + public static PasswordHash Parse(string hashString) { - string[] splitted = storageString.Split('$'); + string[] splitted = hashString.Split('$'); // The string should at least contain the hash function and the hash itself if (splitted.Length < 3) { - throw new ArgumentException("String doesn't contain enough segments", nameof(storageString)); + throw new ArgumentException("String doesn't contain enough segments", nameof(hashString)); } // Start at 1, the first index shouldn't contain any data diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index d61a07066c..b697f6576f 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -1152,6 +1152,11 @@ namespace MediaBrowser.Controller.Entities public List GetChildren(User user, bool includeLinkedChildren) { + if (user == null) + { + throw new ArgumentNullException(nameof(user)); + } + return GetChildren(user, includeLinkedChildren, null); } @@ -1163,7 +1168,10 @@ namespace MediaBrowser.Controller.Entities } //the true root should return our users root folder children - if (IsPhysicalRoot) return LibraryManager.GetUserRootFolder().GetChildren(user, includeLinkedChildren); + if (IsPhysicalRoot) + { + return LibraryManager.GetUserRootFolder().GetChildren(user, includeLinkedChildren); + } var result = new Dictionary(); diff --git a/MediaBrowser.Controller/Library/IUserManager.cs b/MediaBrowser.Controller/Library/IUserManager.cs index bbedc04425..6163c0ce63 100644 --- a/MediaBrowser.Controller/Library/IUserManager.cs +++ b/MediaBrowser.Controller/Library/IUserManager.cs @@ -39,17 +39,21 @@ namespace MediaBrowser.Controller.Library event EventHandler> UserDeleted; event EventHandler> UserCreated; + event EventHandler> UserPolicyUpdated; + event EventHandler> UserConfigurationUpdated; + event EventHandler> UserPasswordChanged; + event EventHandler> UserLockedOut; /// - /// Gets a User by Id + /// Gets a User by Id. /// /// The id. - /// User. - /// + /// The user with the specified Id, or null id the user doesn't exist. + /// id is an empty Guid. User GetUserById(Guid id); /// diff --git a/MediaBrowser.Model/Cryptography/ICryptoProvider.cs b/MediaBrowser.Model/Cryptography/ICryptoProvider.cs index ce6493232f..2d75c9b3ec 100644 --- a/MediaBrowser.Model/Cryptography/ICryptoProvider.cs +++ b/MediaBrowser.Model/Cryptography/ICryptoProvider.cs @@ -8,10 +8,6 @@ namespace MediaBrowser.Model.Cryptography IEnumerable GetSupportedHashMethods(); - byte[] ComputeHash(string HashMethod, byte[] bytes); - - byte[] ComputeHashWithDefaultMethod(byte[] bytes); - byte[] ComputeHash(string HashMethod, byte[] bytes, byte[] salt); byte[] ComputeHashWithDefaultMethod(byte[] bytes, byte[] salt); -- cgit v1.2.3 From b477b3874ef8d79a1e27f8bb298d38443c3ec425 Mon Sep 17 00:00:00 2001 From: Bond-009 Date: Fri, 25 Oct 2019 12:47:20 +0200 Subject: Fix some warnings --- Emby.Naming/AudioBook/AudioBookFileInfo.cs | 2 +- Emby.Naming/AudioBook/AudioBookInfo.cs | 2 +- Emby.Naming/TV/SeasonPathParser.cs | 4 +-- Emby.Naming/Video/CleanDateTimeParser.cs | 2 +- Emby.Naming/Video/VideoFileInfo.cs | 2 +- Emby.Naming/Video/VideoInfo.cs | 2 +- Emby.Naming/Video/VideoResolver.cs | 2 +- .../Activity/ActivityLogEntryPoint.cs | 4 +-- .../AppBase/BaseConfigurationManager.cs | 8 +++--- .../AppBase/ConfigurationHelper.cs | 4 +-- Emby.Server.Implementations/ApplicationHost.cs | 6 ++-- .../Channels/ChannelManager.cs | 4 +-- .../Collections/CollectionManager.cs | 2 +- .../Data/SqliteItemRepository.cs | 2 +- .../Devices/DeviceManager.cs | 1 - .../EntryPoints/ExternalPortForwarding.cs | 1 - .../EntryPoints/LibraryChangedNotifier.cs | 2 +- .../EntryPoints/ServerEventNotifier.cs | 2 +- .../HttpClientManager/HttpClientManager.cs | 2 +- .../HttpServer/HttpResultFactory.cs | 2 +- .../HttpServer/RangeRequestWriter.cs | 4 ++- .../Library/SearchEngine.cs | 2 +- .../Library/Validators/ArtistsValidator.cs | 3 +- .../Library/Validators/GenresPostScanTask.cs | 5 ++-- .../Library/Validators/MusicGenresPostScanTask.cs | 3 +- .../Library/Validators/StudiosPostScanTask.cs | 4 ++- .../LiveTv/EmbyTV/EmbyTV.cs | 2 +- .../LiveTv/Listings/SchedulesDirect.cs | 10 +++---- .../LiveTv/RefreshChannelsScheduledTask.cs | 4 +-- .../LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs | 6 ++-- .../Localization/LocalizationManager.cs | 2 -- .../Middleware/WebSocketMiddleware.cs | 4 +-- .../Networking/NetworkManager.cs | 18 ++++++++---- .../Playlists/ManualPlaylistsFolder.cs | 1 - .../ScheduledTasks/ScheduledTaskWorker.cs | 9 +++--- .../ScheduledTasks/TaskManager.cs | 32 +++++++++++----------- .../ScheduledTasks/Triggers/DailyTrigger.cs | 5 ++-- .../Services/ServicePath.cs | 16 +++++++---- .../Services/SwaggerService.cs | 4 +-- .../Session/HttpSessionController.cs | 2 +- .../SocketSharp/SharpWebSocket.cs | 2 +- .../SocketSharp/WebSocketSharpListener.cs | 6 ++-- .../SocketSharp/WebSocketSharpRequest.cs | 3 +- .../Sorting/NameComparer.cs | 4 +++ .../Sorting/OfficialRatingComparer.cs | 4 +++ .../Sorting/StudioComparer.cs | 5 ++++ .../WebSockets/WebSocketManager.cs | 10 ++++--- MediaBrowser.Api/Playback/BaseStreamingService.cs | 2 +- 48 files changed, 128 insertions(+), 100 deletions(-) (limited to 'Emby.Server.Implementations/Session') diff --git a/Emby.Naming/AudioBook/AudioBookFileInfo.cs b/Emby.Naming/AudioBook/AudioBookFileInfo.cs index 326ea05ef3..769e3d7fac 100644 --- a/Emby.Naming/AudioBook/AudioBookFileInfo.cs +++ b/Emby.Naming/AudioBook/AudioBookFileInfo.cs @@ -3,7 +3,7 @@ using System; namespace Emby.Naming.AudioBook { /// - /// Represents a single video file + /// Represents a single video file. /// public class AudioBookFileInfo : IComparable { diff --git a/Emby.Naming/AudioBook/AudioBookInfo.cs b/Emby.Naming/AudioBook/AudioBookInfo.cs index 600d3f05da..d53f53c528 100644 --- a/Emby.Naming/AudioBook/AudioBookInfo.cs +++ b/Emby.Naming/AudioBook/AudioBookInfo.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; namespace Emby.Naming.AudioBook { /// - /// Represents a complete video, including all parts and subtitles + /// Represents a complete video, including all parts and subtitles. /// public class AudioBookInfo { diff --git a/Emby.Naming/TV/SeasonPathParser.cs b/Emby.Naming/TV/SeasonPathParser.cs index 9096ccaf5d..f34faf8e83 100644 --- a/Emby.Naming/TV/SeasonPathParser.cs +++ b/Emby.Naming/TV/SeasonPathParser.cs @@ -25,7 +25,7 @@ namespace Emby.Naming.TV } /// - /// A season folder must contain one of these somewhere in the name + /// A season folder must contain one of these somewhere in the name. /// private static readonly string[] _seasonFolderNames = { @@ -124,7 +124,7 @@ namespace Emby.Naming.TV } /// - /// Extracts the season number from the second half of the Season folder name (everything after "Season", or "Staffel") + /// Extracts the season number from the second half of the Season folder name (everything after "Season", or "Staffel"). /// /// The path. /// System.Nullable{System.Int32}. diff --git a/Emby.Naming/Video/CleanDateTimeParser.cs b/Emby.Naming/Video/CleanDateTimeParser.cs index 25fa09c488..c6b6039d4d 100644 --- a/Emby.Naming/Video/CleanDateTimeParser.cs +++ b/Emby.Naming/Video/CleanDateTimeParser.cs @@ -8,7 +8,7 @@ using Emby.Naming.Common; namespace Emby.Naming.Video { /// - /// http://kodi.wiki/view/Advancedsettings.xml#video + /// . /// public class CleanDateTimeParser { diff --git a/Emby.Naming/Video/VideoFileInfo.cs b/Emby.Naming/Video/VideoFileInfo.cs index 78f688ca8a..2f42f77845 100644 --- a/Emby.Naming/Video/VideoFileInfo.cs +++ b/Emby.Naming/Video/VideoFileInfo.cs @@ -1,7 +1,7 @@ namespace Emby.Naming.Video { /// - /// Represents a single video file + /// Represents a single video file. /// public class VideoFileInfo { diff --git a/Emby.Naming/Video/VideoInfo.cs b/Emby.Naming/Video/VideoInfo.cs index 2e456bda2b..f576b6ca28 100644 --- a/Emby.Naming/Video/VideoInfo.cs +++ b/Emby.Naming/Video/VideoInfo.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; namespace Emby.Naming.Video { /// - /// Represents a complete video, including all parts and subtitles + /// Represents a complete video, including all parts and subtitles. /// public class VideoInfo { diff --git a/Emby.Naming/Video/VideoResolver.cs b/Emby.Naming/Video/VideoResolver.cs index 02a25c4b5b..91f443500f 100644 --- a/Emby.Naming/Video/VideoResolver.cs +++ b/Emby.Naming/Video/VideoResolver.cs @@ -41,7 +41,7 @@ namespace Emby.Naming.Video /// if set to true [is folder]. /// Whether or not the name should be parsed for info /// VideoFileInfo. - /// path + /// path is null. public VideoFileInfo Resolve(string path, bool isDirectory, bool parseName = true) { if (string.IsNullOrEmpty(path)) diff --git a/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs b/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs index 1514402d68..efaaa116c6 100644 --- a/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs +++ b/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs @@ -616,8 +616,8 @@ namespace Emby.Server.Implementations.Activity /// /// Constructs a string description of a time-span value. /// - /// The value of this item - /// The name of this item (singular form) + /// The value of this item. + /// The name of this item (singular form). private static string CreateValueString(int value, string description) { return string.Format( diff --git a/Emby.Server.Implementations/AppBase/BaseConfigurationManager.cs b/Emby.Server.Implementations/AppBase/BaseConfigurationManager.cs index 7ec5252d07..0b7c35f3e9 100644 --- a/Emby.Server.Implementations/AppBase/BaseConfigurationManager.cs +++ b/Emby.Server.Implementations/AppBase/BaseConfigurationManager.cs @@ -16,7 +16,7 @@ using Microsoft.Extensions.Logging; namespace Emby.Server.Implementations.AppBase { /// - /// Class BaseConfigurationManager + /// Class BaseConfigurationManager. /// public abstract class BaseConfigurationManager : IConfigurationManager { @@ -48,7 +48,7 @@ namespace Emby.Server.Implementations.AppBase /// The application paths. /// The logger factory. /// The XML serializer. - /// The file system + /// The file system. protected BaseConfigurationManager(IApplicationPaths applicationPaths, ILoggerFactory loggerFactory, IXmlSerializer xmlSerializer, IFileSystem fileSystem) { CommonApplicationPaths = applicationPaths; @@ -92,7 +92,7 @@ namespace Emby.Server.Implementations.AppBase protected IXmlSerializer XmlSerializer { get; private set; } /// - /// Gets or sets the application paths. + /// Gets the application paths. /// /// The application paths. public IApplicationPaths CommonApplicationPaths { get; private set; } @@ -173,7 +173,7 @@ namespace Emby.Server.Implementations.AppBase /// Replaces the configuration. /// /// The new configuration. - /// newConfiguration + /// newConfiguration is null. public virtual void ReplaceConfiguration(BaseApplicationConfiguration newConfiguration) { if (newConfiguration == null) diff --git a/Emby.Server.Implementations/AppBase/ConfigurationHelper.cs b/Emby.Server.Implementations/AppBase/ConfigurationHelper.cs index 90b97061f3..854d7b4cbf 100644 --- a/Emby.Server.Implementations/AppBase/ConfigurationHelper.cs +++ b/Emby.Server.Implementations/AppBase/ConfigurationHelper.cs @@ -6,13 +6,13 @@ using MediaBrowser.Model.Serialization; namespace Emby.Server.Implementations.AppBase { /// - /// Class ConfigurationHelper + /// Class ConfigurationHelper. /// public static class ConfigurationHelper { /// /// Reads an xml configuration file from the file system - /// It will immediately re-serialize and save if new serialization data is available due to property changes + /// It will immediately re-serialize and save if new serialization data is available due to property changes. /// /// The type. /// The path. diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index 120a5adc48..1bacd8aef2 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -321,7 +321,7 @@ namespace Emby.Server.Implementations private readonly IConfiguration _configuration; /// - /// Gets or sets the installation manager. + /// Gets the installation manager. /// /// The installation manager. protected IInstallationManager InstallationManager { get; private set; } @@ -500,7 +500,7 @@ namespace Emby.Server.Implementations /// /// Gets the export types. /// - /// The type + /// The type. /// IEnumerable{Type}. public IEnumerable GetExportTypes() { @@ -1022,7 +1022,7 @@ namespace Emby.Server.Implementations } /// - /// Dirty hacks + /// Dirty hacks. /// private void SetStaticProperties() { diff --git a/Emby.Server.Implementations/Channels/ChannelManager.cs b/Emby.Server.Implementations/Channels/ChannelManager.cs index 22681fb499..151670074a 100644 --- a/Emby.Server.Implementations/Channels/ChannelManager.cs +++ b/Emby.Server.Implementations/Channels/ChannelManager.cs @@ -473,7 +473,7 @@ namespace Emby.Server.Implementations.Channels await item.RefreshMetadata(new MetadataRefreshOptions(new DirectoryService(_fileSystem)) { ForceSave = !isNew && forceUpdate - }, cancellationToken); + }, cancellationToken).ConfigureAwait(false); return item; } @@ -636,7 +636,7 @@ namespace Emby.Server.Implementations.Channels private async Task RefreshLatestChannelItems(IChannel channel, CancellationToken cancellationToken) { - var internalChannel = await GetChannel(channel, cancellationToken); + var internalChannel = await GetChannel(channel, cancellationToken).ConfigureAwait(false); var query = new InternalItemsQuery(); query.Parent = internalChannel; diff --git a/Emby.Server.Implementations/Collections/CollectionManager.cs b/Emby.Server.Implementations/Collections/CollectionManager.cs index 6d414be739..c5a77ce5b5 100644 --- a/Emby.Server.Implementations/Collections/CollectionManager.cs +++ b/Emby.Server.Implementations/Collections/CollectionManager.cs @@ -121,7 +121,7 @@ namespace Emby.Server.Implementations.Collections // This could cause it to get re-resolved as a plain folder var folderName = _fileSystem.GetValidFilename(name) + " [boxset]"; - var parentFolder = GetCollectionsFolder(true).Result; + var parentFolder = GetCollectionsFolder(true).GetAwaiter().GetResult(); if (parentFolder == null) { diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs index 65f8a915f9..8d509f6888 100644 --- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs @@ -1177,7 +1177,7 @@ namespace Emby.Server.Implementations.Data { if (id == Guid.Empty) { - throw new ArgumentException(nameof(id), "Guid can't be empty"); + throw new ArgumentException("Guid can't be empty", nameof(id)); } CheckDisposed(); diff --git a/Emby.Server.Implementations/Devices/DeviceManager.cs b/Emby.Server.Implementations/Devices/DeviceManager.cs index d1704b3736..36d4418512 100644 --- a/Emby.Server.Implementations/Devices/DeviceManager.cs +++ b/Emby.Server.Implementations/Devices/DeviceManager.cs @@ -130,7 +130,6 @@ namespace Emby.Server.Implementations.Devices var session = _authRepo.Get(new AuthenticationInfoQuery { DeviceId = id - }).Items.FirstOrDefault(); var device = session == null ? null : ToDeviceInfo(session); diff --git a/Emby.Server.Implementations/EntryPoints/ExternalPortForwarding.cs b/Emby.Server.Implementations/EntryPoints/ExternalPortForwarding.cs index 08041eb59f..a2619367d5 100644 --- a/Emby.Server.Implementations/EntryPoints/ExternalPortForwarding.cs +++ b/Emby.Server.Implementations/EntryPoints/ExternalPortForwarding.cs @@ -70,7 +70,6 @@ namespace Emby.Server.Implementations.EntryPoints if (!string.Equals(_lastConfigIdentifier, GetConfigIdentifier(), StringComparison.OrdinalIgnoreCase)) { Stop(); - Start(); } } diff --git a/Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs b/Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs index 7bef2ae581..24906220d1 100644 --- a/Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs +++ b/Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs @@ -455,7 +455,7 @@ namespace Emby.Server.Implementations.EntryPoints return new[] { item }; } - return new T[] { }; + return Array.Empty(); } /// diff --git a/Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs b/Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs index 141e729584..3ff8d99685 100644 --- a/Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs +++ b/Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs @@ -156,7 +156,7 @@ namespace Emby.Server.Implementations.EntryPoints { try { - await _sessionManager.SendMessageToAdminSessions(name, data, CancellationToken.None); + await _sessionManager.SendMessageToAdminSessions(name, data, CancellationToken.None).ConfigureAwait(false); } catch (Exception) { diff --git a/Emby.Server.Implementations/HttpClientManager/HttpClientManager.cs b/Emby.Server.Implementations/HttpClientManager/HttpClientManager.cs index 0e6083773d..810b46200d 100644 --- a/Emby.Server.Implementations/HttpClientManager/HttpClientManager.cs +++ b/Emby.Server.Implementations/HttpClientManager/HttpClientManager.cs @@ -325,7 +325,7 @@ namespace Emby.Server.Implementations.HttpClientManager if (options.LogErrorResponseBody) { - var msg = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + string msg = await response.Content.ReadAsStringAsync().ConfigureAwait(false); _logger.LogError("HTTP request failed with message: {Message}", msg); } diff --git a/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs b/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs index 0b2924a3ba..b5cfb6b09a 100644 --- a/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs +++ b/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs @@ -460,7 +460,7 @@ namespace Emby.Server.Implementations.HttpServer if (string.IsNullOrEmpty(path)) { - throw new ArgumentNullException(nameof(path)); + throw new ArgumentException("Path can't be empty.", nameof(options)); } if (fileShare != FileShareMode.Read && fileShare != FileShareMode.ReadWrite) diff --git a/Emby.Server.Implementations/HttpServer/RangeRequestWriter.cs b/Emby.Server.Implementations/HttpServer/RangeRequestWriter.cs index e27f794ba6..320136d11a 100644 --- a/Emby.Server.Implementations/HttpServer/RangeRequestWriter.cs +++ b/Emby.Server.Implementations/HttpServer/RangeRequestWriter.cs @@ -48,12 +48,14 @@ namespace Emby.Server.Implementations.HttpServer public IDictionary Headers => _options; /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// The range header. + /// The content length. /// The source. /// Type of the content. /// if set to true [is head request]. + /// The logger instance. public RangeRequestWriter(string rangeHeader, long contentLength, Stream source, string contentType, bool isHeadRequest, ILogger logger) { if (string.IsNullOrEmpty(contentType)) diff --git a/Emby.Server.Implementations/Library/SearchEngine.cs b/Emby.Server.Implementations/Library/SearchEngine.cs index 9c7f7dfcb1..6783b07eb8 100644 --- a/Emby.Server.Implementations/Library/SearchEngine.cs +++ b/Emby.Server.Implementations/Library/SearchEngine.cs @@ -83,7 +83,7 @@ namespace Emby.Server.Implementations.Library if (string.IsNullOrEmpty(searchTerm)) { - throw new ArgumentNullException(nameof(searchTerm)); + throw new ArgumentNullException("SearchTerm can't be empty.", nameof(searchTerm)); } searchTerm = searchTerm.Trim().RemoveDiacritics(); diff --git a/Emby.Server.Implementations/Library/Validators/ArtistsValidator.cs b/Emby.Server.Implementations/Library/Validators/ArtistsValidator.cs index b584cc649d..d06cda177f 100644 --- a/Emby.Server.Implementations/Library/Validators/ArtistsValidator.cs +++ b/Emby.Server.Implementations/Library/Validators/ArtistsValidator.cs @@ -28,10 +28,11 @@ namespace Emby.Server.Implementations.Library.Validators private readonly IItemRepository _itemRepo; /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// The library manager. /// The logger. + /// The item repository. public ArtistsValidator(ILibraryManager libraryManager, ILogger logger, IItemRepository itemRepo) { _libraryManager = libraryManager; diff --git a/Emby.Server.Implementations/Library/Validators/GenresPostScanTask.cs b/Emby.Server.Implementations/Library/Validators/GenresPostScanTask.cs index 0568073005..3bc5c2fb2a 100644 --- a/Emby.Server.Implementations/Library/Validators/GenresPostScanTask.cs +++ b/Emby.Server.Implementations/Library/Validators/GenresPostScanTask.cs @@ -10,17 +10,18 @@ namespace Emby.Server.Implementations.Library.Validators public class GenresPostScanTask : ILibraryPostScanTask { /// - /// The _library manager + /// The _library manager. /// private readonly ILibraryManager _libraryManager; private readonly ILogger _logger; private readonly IItemRepository _itemRepo; /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// The library manager. /// The logger. + /// The item repository. public GenresPostScanTask(ILibraryManager libraryManager, ILogger logger, IItemRepository itemRepo) { _libraryManager = libraryManager; diff --git a/Emby.Server.Implementations/Library/Validators/MusicGenresPostScanTask.cs b/Emby.Server.Implementations/Library/Validators/MusicGenresPostScanTask.cs index d7ab92d306..9ac4bf7618 100644 --- a/Emby.Server.Implementations/Library/Validators/MusicGenresPostScanTask.cs +++ b/Emby.Server.Implementations/Library/Validators/MusicGenresPostScanTask.cs @@ -20,10 +20,11 @@ namespace Emby.Server.Implementations.Library.Validators private readonly IItemRepository _itemRepo; /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// The library manager. /// The logger. + /// The item repository. public MusicGenresPostScanTask(ILibraryManager libraryManager, ILogger logger, IItemRepository itemRepo) { _libraryManager = libraryManager; diff --git a/Emby.Server.Implementations/Library/Validators/StudiosPostScanTask.cs b/Emby.Server.Implementations/Library/Validators/StudiosPostScanTask.cs index 4aa5c7e72a..2efae0fe44 100644 --- a/Emby.Server.Implementations/Library/Validators/StudiosPostScanTask.cs +++ b/Emby.Server.Implementations/Library/Validators/StudiosPostScanTask.cs @@ -21,9 +21,11 @@ namespace Emby.Server.Implementations.Library.Validators private readonly IItemRepository _itemRepo; /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// The library manager. + /// The logger. + /// Th item repository. public StudiosPostScanTask(ILibraryManager libraryManager, ILogger logger, IItemRepository itemRepo) { _libraryManager = libraryManager; diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index 687a178a68..ef5928e480 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -237,7 +237,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV if (requiresRefresh) { - await _libraryManager.ValidateMediaLibrary(new SimpleProgress(), CancellationToken.None); + await _libraryManager.ValidateMediaLibrary(new SimpleProgress(), CancellationToken.None).ConfigureAwait(false); } } diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs index 9a4c91d0bd..838ac97d77 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs @@ -501,7 +501,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings public async Task> GetHeadends(ListingsProviderInfo info, string country, string location, CancellationToken cancellationToken) { - var token = await GetToken(info, cancellationToken); + var token = await GetToken(info, cancellationToken).ConfigureAwait(false); var lineups = new List(); @@ -713,7 +713,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings private async Task AddLineupToAccount(ListingsProviderInfo info, CancellationToken cancellationToken) { - var token = await GetToken(info, cancellationToken); + var token = await GetToken(info, cancellationToken).ConfigureAwait(false); if (string.IsNullOrEmpty(token)) { @@ -738,7 +738,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings httpOptions.RequestHeaders["token"] = token; - using (await _httpClient.SendAsync(httpOptions, "PUT")) + using (await _httpClient.SendAsync(httpOptions, "PUT").ConfigureAwait(false)) { } } @@ -750,7 +750,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings throw new ArgumentException("Listings Id required"); } - var token = await GetToken(info, cancellationToken); + var token = await GetToken(info, cancellationToken).ConfigureAwait(false); if (string.IsNullOrEmpty(token)) { @@ -833,7 +833,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings throw new Exception("ListingsId required"); } - var token = await GetToken(info, cancellationToken); + var token = await GetToken(info, cancellationToken).ConfigureAwait(false); if (string.IsNullOrEmpty(token)) { diff --git a/Emby.Server.Implementations/LiveTv/RefreshChannelsScheduledTask.cs b/Emby.Server.Implementations/LiveTv/RefreshChannelsScheduledTask.cs index 542951de4a..1056a33b9a 100644 --- a/Emby.Server.Implementations/LiveTv/RefreshChannelsScheduledTask.cs +++ b/Emby.Server.Implementations/LiveTv/RefreshChannelsScheduledTask.cs @@ -38,8 +38,8 @@ namespace Emby.Server.Implementations.LiveTv /// IEnumerable{BaseTaskTrigger}. public IEnumerable GetDefaultTriggers() { - return new[] { - + return new[] + { // Every so often new TaskTriggerInfo { Type = TaskTriggerInfo.TriggerInterval, IntervalTicks = TimeSpan.FromHours(24).Ticks} }; diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs index da98f3e58b..f834566605 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs @@ -185,7 +185,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun Url = string.Format("{0}/tuners.html", GetApiUrl(info)), CancellationToken = cancellationToken, BufferContent = false - }, HttpMethod.Get)) + }, HttpMethod.Get).ConfigureAwait(false)) using (var stream = response.Content) using (var sr = new StreamReader(stream, System.Text.Encoding.UTF8)) { @@ -259,7 +259,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun for (int i = 0; i < model.TunerCount; ++i) { var name = string.Format("Tuner {0}", i + 1); - var currentChannel = "none"; /// @todo Get current channel and map back to Station Id + var currentChannel = "none"; // @todo Get current channel and map back to Station Id var isAvailable = await manager.CheckTunerAvailability(ipInfo, i, cancellationToken).ConfigureAwait(false); var status = isAvailable ? LiveTvTunerStatus.Available : LiveTvTunerStatus.LiveTv; tuners.Add(new LiveTvTunerInfo @@ -298,7 +298,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun public async Task> GetTunerInfos(TunerHostInfo info, CancellationToken cancellationToken) { // TODO Need faster way to determine UDP vs HTTP - var channels = await GetChannels(info, true, cancellationToken); + var channels = await GetChannels(info, true, cancellationToken).ConfigureAwait(false); var hdHomerunChannelInfo = channels.FirstOrDefault() as HdHomerunChannelInfo; diff --git a/Emby.Server.Implementations/Localization/LocalizationManager.cs b/Emby.Server.Implementations/Localization/LocalizationManager.cs index 13cdc50ca4..bda43e832a 100644 --- a/Emby.Server.Implementations/Localization/LocalizationManager.cs +++ b/Emby.Server.Implementations/Localization/LocalizationManager.cs @@ -5,11 +5,9 @@ using System.Globalization; using System.IO; using System.Linq; using System.Reflection; -using System.Text; using System.Threading.Tasks; using MediaBrowser.Controller.Configuration; using MediaBrowser.Model.Entities; -using MediaBrowser.Model.Extensions; using MediaBrowser.Model.Globalization; using MediaBrowser.Model.Serialization; using Microsoft.Extensions.Logging; diff --git a/Emby.Server.Implementations/Middleware/WebSocketMiddleware.cs b/Emby.Server.Implementations/Middleware/WebSocketMiddleware.cs index 268bf4042d..fda32da5e8 100644 --- a/Emby.Server.Implementations/Middleware/WebSocketMiddleware.cs +++ b/Emby.Server.Implementations/Middleware/WebSocketMiddleware.cs @@ -27,12 +27,12 @@ namespace Emby.Server.Implementations.Middleware var webSocketContext = await httpContext.WebSockets.AcceptWebSocketAsync(null).ConfigureAwait(false); if (webSocketContext != null) { - await _webSocketManager.OnWebSocketConnected(webSocketContext); + await _webSocketManager.OnWebSocketConnected(webSocketContext).ConfigureAwait(false); } } else { - await _next.Invoke(httpContext); + await _next.Invoke(httpContext).ConfigureAwait(false); } } } diff --git a/Emby.Server.Implementations/Networking/NetworkManager.cs b/Emby.Server.Implementations/Networking/NetworkManager.cs index d948dad688..098bd518e3 100644 --- a/Emby.Server.Implementations/Networking/NetworkManager.cs +++ b/Emby.Server.Implementations/Networking/NetworkManager.cs @@ -490,23 +490,25 @@ namespace Emby.Server.Implementations.Networking IPAddress ipaddy; int port = -1; - //check if we have an IPv6 or ports + // check if we have an IPv6 or ports if (values.Length <= 2) // ipv4 or hostname { port = values.Length == 1 ? defaultport : GetPort(values[1]); - //try to use the address as IPv4, otherwise get hostname + // try to use the address as IPv4, otherwise get hostname if (!IPAddress.TryParse(values[0], out ipaddy)) + { ipaddy = await GetIPfromHost(values[0]).ConfigureAwait(false); + } } - else if (values.Length > 2) //ipv6 + else if (values.Length > 2) // ipv6 { - //could [a:b:c]:d + //ncould [a:b:c]:d if (values[0].StartsWith("[") && values[values.Length - 2].EndsWith("]")) { string ipaddressstring = string.Join(":", values.Take(values.Length - 1).ToArray()); ipaddy = IPAddress.Parse(ipaddressstring); - port = GetPort(values[values.Length - 1]); + port = GetPort(values[^1]); } else //[a:b:c] or a:b:c { @@ -516,7 +518,11 @@ namespace Emby.Server.Implementations.Networking } else { - throw new FormatException(string.Format("Invalid endpoint ipaddress '{0}'", endpointstring)); + throw new FormatException( + string.Format( + CultureInfo.InvariantCulture, + "Invalid endpoint ipaddress '{0}'", + endpointstring)); } if (port == -1) diff --git a/Emby.Server.Implementations/Playlists/ManualPlaylistsFolder.cs b/Emby.Server.Implementations/Playlists/ManualPlaylistsFolder.cs index de51a37ab7..cd9f7946e9 100644 --- a/Emby.Server.Implementations/Playlists/ManualPlaylistsFolder.cs +++ b/Emby.Server.Implementations/Playlists/ManualPlaylistsFolder.cs @@ -48,4 +48,3 @@ namespace Emby.Server.Implementations.Playlists } } } - diff --git a/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs b/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs index 83226b07f1..5b188d9626 100644 --- a/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs +++ b/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs @@ -23,7 +23,7 @@ namespace Emby.Server.Implementations.ScheduledTasks public event EventHandler> TaskProgress; /// - /// Gets or sets the scheduled task. + /// Gets the scheduled task. /// /// The scheduled task. public IScheduledTask ScheduledTask { get; private set; } @@ -215,11 +215,12 @@ namespace Emby.Server.Implementations.ScheduledTasks public double? CurrentProgress { get; private set; } /// - /// The _triggers + /// The _triggers. /// private Tuple[] _triggers; + /// - /// Gets the triggers that define when the task will run + /// Gets the triggers that define when the task will run. /// /// The triggers. private Tuple[] InternalTriggers @@ -245,7 +246,7 @@ namespace Emby.Server.Implementations.ScheduledTasks } /// - /// Gets the triggers that define when the task will run + /// Gets the triggers that define when the task will run. /// /// The triggers. /// value diff --git a/Emby.Server.Implementations/ScheduledTasks/TaskManager.cs b/Emby.Server.Implementations/ScheduledTasks/TaskManager.cs index 595c3037d7..ecf58dbc0e 100644 --- a/Emby.Server.Implementations/ScheduledTasks/TaskManager.cs +++ b/Emby.Server.Implementations/ScheduledTasks/TaskManager.cs @@ -36,19 +36,19 @@ namespace Emby.Server.Implementations.ScheduledTasks /// Gets or sets the json serializer. /// /// The json serializer. - private IJsonSerializer JsonSerializer { get; set; } + private readonly IJsonSerializer _jsonSerializer; /// /// Gets or sets the application paths. /// /// The application paths. - private IApplicationPaths ApplicationPaths { get; set; } + private readonly IApplicationPaths _applicationPaths; /// /// Gets the logger. /// /// The logger. - private ILogger Logger { get; set; } + private readonly ILogger _logger; private readonly IFileSystem _fileSystem; /// @@ -57,19 +57,19 @@ namespace Emby.Server.Implementations.ScheduledTasks /// The application paths. /// The json serializer. /// The logger factory. - /// kernel + /// The filesystem manager. public TaskManager( IApplicationPaths applicationPaths, IJsonSerializer jsonSerializer, ILoggerFactory loggerFactory, IFileSystem fileSystem) { - ApplicationPaths = applicationPaths; - JsonSerializer = jsonSerializer; - Logger = loggerFactory.CreateLogger(nameof(TaskManager)); + _applicationPaths = applicationPaths; + _jsonSerializer = jsonSerializer; + _logger = loggerFactory.CreateLogger(nameof(TaskManager)); _fileSystem = fileSystem; - ScheduledTasks = new IScheduledTaskWorker[] { }; + ScheduledTasks = Array.Empty(); } /// @@ -78,7 +78,7 @@ namespace Emby.Server.Implementations.ScheduledTasks /// /// Task options. public void CancelIfRunningAndQueue(TaskOptions options) - where T : IScheduledTask + where T : IScheduledTask { var task = ScheduledTasks.First(t => t.ScheduledTask.GetType() == typeof(T)); ((ScheduledTaskWorker)task).CancelIfRunning(); @@ -115,7 +115,7 @@ namespace Emby.Server.Implementations.ScheduledTasks if (scheduledTask == null) { - Logger.LogError("Unable to find scheduled task of type {0} in QueueScheduledTask.", typeof(T).Name); + _logger.LogError("Unable to find scheduled task of type {0} in QueueScheduledTask.", typeof(T).Name); } else { @@ -147,13 +147,13 @@ namespace Emby.Server.Implementations.ScheduledTasks if (scheduledTask == null) { - Logger.LogError("Unable to find scheduled task of type {0} in Execute.", typeof(T).Name); + _logger.LogError("Unable to find scheduled task of type {0} in Execute.", typeof(T).Name); } else { var type = scheduledTask.ScheduledTask.GetType(); - Logger.LogInformation("Queueing task {0}", type.Name); + _logger.LogInformation("Queueing task {0}", type.Name); lock (_taskQueue) { @@ -176,7 +176,7 @@ namespace Emby.Server.Implementations.ScheduledTasks if (scheduledTask == null) { - Logger.LogError("Unable to find scheduled task of type {0} in QueueScheduledTask.", task.GetType().Name); + _logger.LogError("Unable to find scheduled task of type {0} in QueueScheduledTask.", task.GetType().Name); } else { @@ -193,7 +193,7 @@ namespace Emby.Server.Implementations.ScheduledTasks { var type = task.ScheduledTask.GetType(); - Logger.LogInformation("Queueing task {0}", type.Name); + _logger.LogInformation("Queueing task {0}", type.Name); lock (_taskQueue) { @@ -213,7 +213,7 @@ namespace Emby.Server.Implementations.ScheduledTasks /// The tasks. public void AddTasks(IEnumerable tasks) { - var list = tasks.Select(t => new ScheduledTaskWorker(t, ApplicationPaths, this, JsonSerializer, Logger, _fileSystem)); + var list = tasks.Select(t => new ScheduledTaskWorker(t, _applicationPaths, this, _jsonSerializer, _logger, _fileSystem)); ScheduledTasks = ScheduledTasks.Concat(list).ToArray(); } @@ -281,7 +281,7 @@ namespace Emby.Server.Implementations.ScheduledTasks /// private void ExecuteQueuedTasks() { - Logger.LogInformation("ExecuteQueuedTasks"); + _logger.LogInformation("ExecuteQueuedTasks"); // Execute queued tasks lock (_taskQueue) diff --git a/Emby.Server.Implementations/ScheduledTasks/Triggers/DailyTrigger.cs b/Emby.Server.Implementations/ScheduledTasks/Triggers/DailyTrigger.cs index ec9466c4ab..ea278de0d9 100644 --- a/Emby.Server.Implementations/ScheduledTasks/Triggers/DailyTrigger.cs +++ b/Emby.Server.Implementations/ScheduledTasks/Triggers/DailyTrigger.cs @@ -1,5 +1,4 @@ using System; -using System.Globalization; using System.Threading; using MediaBrowser.Model.Tasks; using Microsoft.Extensions.Logging; @@ -7,12 +6,12 @@ using Microsoft.Extensions.Logging; namespace Emby.Server.Implementations.ScheduledTasks { /// - /// Represents a task trigger that fires everyday + /// Represents a task trigger that fires everyday. /// public class DailyTrigger : ITaskTrigger { /// - /// Get the time of day to trigger the task to run + /// Get the time of day to trigger the task to run. /// /// The time of day. public TimeSpan TimeOfDay { get; set; } diff --git a/Emby.Server.Implementations/Services/ServicePath.cs b/Emby.Server.Implementations/Services/ServicePath.cs index 0b67669b94..27c4dcba07 100644 --- a/Emby.Server.Implementations/Services/ServicePath.cs +++ b/Emby.Server.Implementations/Services/ServicePath.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.IO; using System.Linq; using System.Reflection; @@ -45,8 +46,8 @@ namespace Emby.Server.Implementations.Services public int PathComponentsCount { get; set; } /// - /// The total number of segments after subparts have been exploded ('.') - /// e.g. /path/to/here.ext == 4 + /// Gets or sets the total number of segments after subparts have been exploded ('.') + /// e.g. /path/to/here.ext == 4. /// public int TotalComponentsCount { get; set; } @@ -279,7 +280,7 @@ namespace Emby.Server.Implementations.Services } /// - /// Provide for quick lookups based on hashes that can be determined from a request url + /// Provide for quick lookups based on hashes that can be determined from a request url. /// public string FirstMatchHashKey { get; private set; } @@ -436,9 +437,12 @@ namespace Emby.Server.Implementations.Services && requestComponents.Length >= this.TotalComponentsCount - this.wildcardCount; if (!isValidWildCardPath) - throw new ArgumentException(string.Format( - "Path Mismatch: Request Path '{0}' has invalid number of components compared to: '{1}'", - pathInfo, this.restPath)); + throw new ArgumentException( + string.Format( + CultureInfo.InvariantCulture, + "Path Mismatch: Request Path '{0}' has invalid number of components compared to: '{1}'", + pathInfo, + this.restPath)); } var requestKeyValuesMap = new Dictionary(); diff --git a/Emby.Server.Implementations/Services/SwaggerService.cs b/Emby.Server.Implementations/Services/SwaggerService.cs index d223864364..c30f32af94 100644 --- a/Emby.Server.Implementations/Services/SwaggerService.cs +++ b/Emby.Server.Implementations/Services/SwaggerService.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using MediaBrowser.Controller.Net; @@ -175,7 +175,7 @@ namespace Emby.Server.Implementations.Services private SwaggerTag[] GetTags() { - return new SwaggerTag[] { }; + return Array.Empty(); } private Dictionary GetDefinitions() diff --git a/Emby.Server.Implementations/Session/HttpSessionController.cs b/Emby.Server.Implementations/Session/HttpSessionController.cs index 1104a7a85b..dfb81816c7 100644 --- a/Emby.Server.Implementations/Session/HttpSessionController.cs +++ b/Emby.Server.Implementations/Session/HttpSessionController.cs @@ -105,7 +105,7 @@ namespace Emby.Server.Implementations.Session return SendMessage(command.Command.ToString(), messageId, args, cancellationToken); } - private string[] _supportedMessages = new string[] { }; + private string[] _supportedMessages = Array.Empty(); public Task SendMessage(string name, string messageId, T data, ISessionController[] allControllers, CancellationToken cancellationToken) { if (!IsSessionActive) diff --git a/Emby.Server.Implementations/SocketSharp/SharpWebSocket.cs b/Emby.Server.Implementations/SocketSharp/SharpWebSocket.cs index 62b16ed8c8..67521d6c63 100644 --- a/Emby.Server.Implementations/SocketSharp/SharpWebSocket.cs +++ b/Emby.Server.Implementations/SocketSharp/SharpWebSocket.cs @@ -33,7 +33,7 @@ namespace Emby.Server.Implementations.SocketSharp } /// - /// Gets or sets the state. + /// Gets the state. /// /// The state. public WebSocketState State => _webSocket.State; diff --git a/Emby.Server.Implementations/SocketSharp/WebSocketSharpListener.cs b/Emby.Server.Implementations/SocketSharp/WebSocketSharpListener.cs index e93bff1244..ba5ba1904c 100644 --- a/Emby.Server.Implementations/SocketSharp/WebSocketSharpListener.cs +++ b/Emby.Server.Implementations/SocketSharp/WebSocketSharpListener.cs @@ -81,8 +81,10 @@ namespace Emby.Server.Implementations.SocketSharp if (webSocketContext.State == WebSocketState.Open) { - await webSocketContext.CloseAsync(result.CloseStatus ?? WebSocketCloseStatus.NormalClosure, - result.CloseStatusDescription, _disposeCancellationToken); + await webSocketContext.CloseAsync( + result.CloseStatus ?? WebSocketCloseStatus.NormalClosure, + result.CloseStatusDescription, + _disposeCancellationToken).ConfigureAwait(false); } socket.Dispose(); diff --git a/Emby.Server.Implementations/SocketSharp/WebSocketSharpRequest.cs b/Emby.Server.Implementations/SocketSharp/WebSocketSharpRequest.cs index 332ce39034..690ba0be4a 100644 --- a/Emby.Server.Implementations/SocketSharp/WebSocketSharpRequest.cs +++ b/Emby.Server.Implementations/SocketSharp/WebSocketSharpRequest.cs @@ -2,7 +2,6 @@ using System; using System.Collections.Generic; using System.IO; using System.Net; -using System.Linq; using MediaBrowser.Common.Net; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Extensions; @@ -13,7 +12,7 @@ using IHttpRequest = MediaBrowser.Model.Services.IHttpRequest; namespace Emby.Server.Implementations.SocketSharp { - public partial class WebSocketSharpRequest : IHttpRequest + public class WebSocketSharpRequest : IHttpRequest { public const string FormUrlEncoded = "application/x-www-form-urlencoded"; public const string MultiPartFormData = "multipart/form-data"; diff --git a/Emby.Server.Implementations/Sorting/NameComparer.cs b/Emby.Server.Implementations/Sorting/NameComparer.cs index 10fa4359aa..4eb1549f58 100644 --- a/Emby.Server.Implementations/Sorting/NameComparer.cs +++ b/Emby.Server.Implementations/Sorting/NameComparer.cs @@ -19,10 +19,14 @@ namespace Emby.Server.Implementations.Sorting public int Compare(BaseItem x, BaseItem y) { if (x == null) + { throw new ArgumentNullException(nameof(x)); + } if (y == null) + { throw new ArgumentNullException(nameof(y)); + } return string.Compare(x.Name, y.Name, StringComparison.CurrentCultureIgnoreCase); } diff --git a/Emby.Server.Implementations/Sorting/OfficialRatingComparer.cs b/Emby.Server.Implementations/Sorting/OfficialRatingComparer.cs index e8fa8edc8e..7afbd9ff7d 100644 --- a/Emby.Server.Implementations/Sorting/OfficialRatingComparer.cs +++ b/Emby.Server.Implementations/Sorting/OfficialRatingComparer.cs @@ -24,10 +24,14 @@ namespace Emby.Server.Implementations.Sorting public int Compare(BaseItem x, BaseItem y) { if (x == null) + { throw new ArgumentNullException(nameof(x)); + } if (y == null) + { throw new ArgumentNullException(nameof(y)); + } var levelX = string.IsNullOrEmpty(x.OfficialRating) ? 0 : _localization.GetRatingLevel(x.OfficialRating) ?? 0; var levelY = string.IsNullOrEmpty(y.OfficialRating) ? 0 : _localization.GetRatingLevel(y.OfficialRating) ?? 0; diff --git a/Emby.Server.Implementations/Sorting/StudioComparer.cs b/Emby.Server.Implementations/Sorting/StudioComparer.cs index 617ed55d52..c9ac765c10 100644 --- a/Emby.Server.Implementations/Sorting/StudioComparer.cs +++ b/Emby.Server.Implementations/Sorting/StudioComparer.cs @@ -17,10 +17,15 @@ namespace Emby.Server.Implementations.Sorting public int Compare(BaseItem x, BaseItem y) { if (x == null) + { throw new ArgumentNullException(nameof(x)); + } if (y == null) + { throw new ArgumentNullException(nameof(y)); + } + return AlphanumComparator.CompareValues(x.Studios.FirstOrDefault() ?? string.Empty, y.Studios.FirstOrDefault() ?? string.Empty); } diff --git a/Emby.Server.Implementations/WebSockets/WebSocketManager.cs b/Emby.Server.Implementations/WebSockets/WebSocketManager.cs index 04c73ecea7..efd97e4ff1 100644 --- a/Emby.Server.Implementations/WebSockets/WebSocketManager.cs +++ b/Emby.Server.Implementations/WebSockets/WebSocketManager.cs @@ -39,12 +39,12 @@ namespace Emby.Server.Implementations.WebSockets do { var buffer = WebSocket.CreateServerBuffer(BufferSize); - result = await webSocket.ReceiveAsync(buffer, cancellationToken); + result = await webSocket.ReceiveAsync(buffer, cancellationToken).ConfigureAwait(false); message.AddRange(buffer.Array.Take(result.Count)); if (result.EndOfMessage) { - await ProcessMessage(message.ToArray(), taskCompletionSource); + await ProcessMessage(message.ToArray(), taskCompletionSource).ConfigureAwait(false); message.Clear(); } } while (!taskCompletionSource.Task.IsCompleted && @@ -53,8 +53,10 @@ namespace Emby.Server.Implementations.WebSockets if (webSocket.State == WebSocketState.Open) { - await webSocket.CloseAsync(result.CloseStatus ?? WebSocketCloseStatus.NormalClosure, - result.CloseStatusDescription, cancellationToken); + await webSocket.CloseAsync( + result.CloseStatus ?? WebSocketCloseStatus.NormalClosure, + result.CloseStatusDescription, + cancellationToken).ConfigureAwait(false); } } diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index c7104c9507..833fcc54bc 100644 --- a/MediaBrowser.Api/Playback/BaseStreamingService.cs +++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs @@ -588,7 +588,7 @@ namespace MediaBrowser.Api.Playback /// /// Parses query parameters as StreamOptions - /// + /// /// The stream request. private void ParseStreamOptions(StreamRequest request) { -- cgit v1.2.3 From 27e3cf15588f8ab8fe19aa611d79fa2ccd8ecda8 Mon Sep 17 00:00:00 2001 From: Claus Vium Date: Sun, 24 Nov 2019 15:27:58 +0100 Subject: Move appbuilder and service collection to Jellyfin.Server --- Emby.Server.Implementations/ApplicationHost.cs | 110 +++------------------ .../HttpServer/HttpListenerHost.cs | 3 +- .../Session/SessionWebSocketListener.cs | 4 +- Jellyfin.Api/Controllers/StartupController.cs | 2 +- .../Extensions/ApiApplicationBuilderExtensions.cs | 27 ----- .../Extensions/ApiServiceCollectionExtensions.cs | 96 ------------------ .../Models/Startup/StartupConfigurationDto.cs | 23 ----- Jellyfin.Api/Models/Startup/StartupUserDto.cs | 18 ---- .../Models/StartupDtos/StartupConfigurationDto.cs | 23 +++++ Jellyfin.Api/Models/StartupDtos/StartupUserDto.cs | 18 ++++ .../Extensions/ApiApplicationBuilderExtensions.cs | 27 +++++ .../Extensions/ApiServiceCollectionExtensions.cs | 89 +++++++++++++++++ Jellyfin.Server/Jellyfin.Server.csproj | 4 + Jellyfin.Server/Program.cs | 70 ++++++++++++- Jellyfin.Server/Startup.cs | 81 +++++++++++++++ MediaBrowser.Controller/IServerApplicationHost.cs | 5 + 16 files changed, 336 insertions(+), 264 deletions(-) delete mode 100644 Jellyfin.Api/Extensions/ApiApplicationBuilderExtensions.cs delete mode 100644 Jellyfin.Api/Extensions/ApiServiceCollectionExtensions.cs delete mode 100644 Jellyfin.Api/Models/Startup/StartupConfigurationDto.cs delete mode 100644 Jellyfin.Api/Models/Startup/StartupUserDto.cs create mode 100644 Jellyfin.Api/Models/StartupDtos/StartupConfigurationDto.cs create mode 100644 Jellyfin.Api/Models/StartupDtos/StartupUserDto.cs create mode 100644 Jellyfin.Server/Extensions/ApiApplicationBuilderExtensions.cs create mode 100644 Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs create mode 100644 Jellyfin.Server/Startup.cs (limited to 'Emby.Server.Implementations/Session') diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index c6cdd4786b..3b9ea41219 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -47,7 +47,6 @@ using Emby.Server.Implementations.Session; using Emby.Server.Implementations.SocketSharp; using Emby.Server.Implementations.TV; using Emby.Server.Implementations.Updates; -using Jellyfin.Api.Extensions; using MediaBrowser.Api; using MediaBrowser.Common; using MediaBrowser.Common.Configuration; @@ -232,7 +231,7 @@ namespace Emby.Server.Implementations } } - protected IServiceProvider _serviceProvider; + public IServiceProvider ServiceProvider; /// /// Gets the server configuration manager. @@ -461,7 +460,7 @@ namespace Emby.Server.Implementations /// The type. /// System.Object. public object CreateInstance(Type type) - => ActivatorUtilities.CreateInstance(_serviceProvider, type); + => ActivatorUtilities.CreateInstance(ServiceProvider, type); /// /// Creates an instance of type and resolves all constructor dependencies @@ -469,7 +468,7 @@ namespace Emby.Server.Implementations /// /// The type. /// T. public T CreateInstance() - => ActivatorUtilities.CreateInstance(_serviceProvider); + => ActivatorUtilities.CreateInstance(ServiceProvider); /// /// Creates the instance safe. @@ -481,7 +480,7 @@ namespace Emby.Server.Implementations try { Logger.LogDebug("Creating instance of {Type}", type); - return ActivatorUtilities.CreateInstance(_serviceProvider, type); + return ActivatorUtilities.CreateInstance(ServiceProvider, type); } catch (Exception ex) { @@ -495,7 +494,7 @@ namespace Emby.Server.Implementations /// /// The type /// ``0. - public T Resolve() => _serviceProvider.GetService(); + public T Resolve() => ServiceProvider.GetService(); /// /// Gets the export types. @@ -611,93 +610,14 @@ namespace Emby.Server.Implementations await RegisterResources(serviceCollection).ConfigureAwait(false); - string contentRoot = ServerConfigurationManager.Configuration.DashboardSourcePath; - if (string.IsNullOrEmpty(contentRoot)) + ContentRoot = ServerConfigurationManager.Configuration.DashboardSourcePath; + if (string.IsNullOrEmpty(ContentRoot)) { - contentRoot = ServerConfigurationManager.ApplicationPaths.WebPath; - } - - var host = new WebHostBuilder() - .UseKestrel(options => - { - var addresses = ServerConfigurationManager - .Configuration - .LocalNetworkAddresses - .Select(NormalizeConfiguredLocalAddress) - .Where(i => i != null) - .ToList(); - if (addresses.Any()) - { - foreach (var address in addresses) - { - Logger.LogInformation("Kestrel listening on {ipaddr}", address); - options.Listen(address, HttpPort); - - if (EnableHttps && Certificate != null) - { - options.Listen(address, HttpsPort, listenOptions => listenOptions.UseHttps(Certificate)); - } - } - } - else - { - Logger.LogInformation("Kestrel listening on all interfaces"); - options.ListenAnyIP(HttpPort); - - if (EnableHttps && Certificate != null) - { - options.ListenAnyIP(HttpsPort, listenOptions => listenOptions.UseHttps(Certificate)); - } - } - }) - .UseContentRoot(contentRoot) - .ConfigureServices(services => - { - services.AddResponseCompression(); - services.AddHttpContextAccessor(); - services.AddJellyfinApi(ServerConfigurationManager.Configuration.BaseUrl.TrimStart('/')); - - services.AddJellyfinApiSwagger(); - - // configure custom legacy authentication - services.AddCustomAuthentication(); - - services.AddJellyfinApiAuthorization(); - - // Merge the external ServiceCollection into ASP.NET DI - services.TryAdd(serviceCollection); - }) - .Configure(app => - { - app.UseWebSockets(); - - app.UseResponseCompression(); - - // TODO app.UseMiddleware(); - app.Use(ExecuteWebsocketHandlerAsync); - - // TODO use when old API is removed: app.UseAuthentication(); - app.UseJellyfinApiSwagger(); - app.UseMvc(); - app.Use(ExecuteHttpHandlerAsync); - }) - .Build(); - - _serviceProvider = host.Services; - FindParts(); - - try - { - await host.StartAsync().ConfigureAwait(false); - } - catch - { - Logger.LogError("Kestrel failed to start! This is most likely due to an invalid address or port bind - correct your bind configuration in system.xml and try again."); - throw; + ContentRoot = ServerConfigurationManager.ApplicationPaths.WebPath; } } - private async Task ExecuteWebsocketHandlerAsync(HttpContext context, Func next) + public async Task ExecuteWebsocketHandlerAsync(HttpContext context, Func next) { if (!context.WebSockets.IsWebSocketRequest) { @@ -708,7 +628,7 @@ namespace Emby.Server.Implementations await HttpServer.ProcessWebSocketRequest(context).ConfigureAwait(false); } - private async Task ExecuteHttpHandlerAsync(HttpContext context, Func next) + public async Task ExecuteHttpHandlerAsync(HttpContext context, Func next) { if (context.WebSockets.IsWebSocketRequest) { @@ -1090,9 +1010,9 @@ namespace Emby.Server.Implementations /// /// Finds the parts. /// - protected void FindParts() + public void FindParts() { - InstallationManager = _serviceProvider.GetService(); + InstallationManager = ServiceProvider.GetService(); InstallationManager.PluginInstalled += PluginInstalled; if (!ServerConfigurationManager.Configuration.IsPortAuthorized) @@ -1221,7 +1141,7 @@ namespace Emby.Server.Implementations private CertificateInfo CertificateInfo { get; set; } - protected X509Certificate2 Certificate { get; private set; } + public X509Certificate2 Certificate { get; private set; } private IEnumerable GetUrlPrefixes() { @@ -1605,7 +1525,7 @@ namespace Emby.Server.Implementations return resultList; } - private IPAddress NormalizeConfiguredLocalAddress(string address) + public IPAddress NormalizeConfiguredLocalAddress(string address) { var index = address.Trim('/').IndexOf('/'); @@ -1685,6 +1605,8 @@ namespace Emby.Server.Implementations public int HttpsPort { get; private set; } + public string ContentRoot { get; private set; } + /// /// Shuts down. /// diff --git a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs index dc1a56e271..6dd016f8a2 100644 --- a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs +++ b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs @@ -18,7 +18,6 @@ using MediaBrowser.Model.Events; using MediaBrowser.Model.Serialization; using MediaBrowser.Model.Services; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Http.Internal; using Microsoft.AspNetCore.WebUtilities; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; @@ -164,7 +163,7 @@ namespace Emby.Server.Implementations.HttpServer { OnReceive = ProcessWebSocketMessageReceived, Url = e.Url, - QueryString = e.QueryString ?? new QueryCollection() + QueryString = e.QueryString }; connection.Closed += OnConnectionClosed; diff --git a/Emby.Server.Implementations/Session/SessionWebSocketListener.cs b/Emby.Server.Implementations/Session/SessionWebSocketListener.cs index 63ec757626..930f2d35d3 100644 --- a/Emby.Server.Implementations/Session/SessionWebSocketListener.cs +++ b/Emby.Server.Implementations/Session/SessionWebSocketListener.cs @@ -4,7 +4,6 @@ using MediaBrowser.Controller.Net; using MediaBrowser.Controller.Session; using MediaBrowser.Model.Events; using MediaBrowser.Model.Serialization; -using MediaBrowser.Model.Services; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging; @@ -67,7 +66,7 @@ namespace Emby.Server.Implementations.Session { if (queryString == null) { - throw new ArgumentNullException(nameof(queryString)); + return null; } var token = queryString["api_key"]; @@ -75,6 +74,7 @@ namespace Emby.Server.Implementations.Session { return null; } + var deviceId = queryString["deviceId"]; return _sessionManager.GetSessionByAuthenticationToken(token, deviceId, remoteEndpoint); } diff --git a/Jellyfin.Api/Controllers/StartupController.cs b/Jellyfin.Api/Controllers/StartupController.cs index 0e7d17a27f..50f3dc83cf 100644 --- a/Jellyfin.Api/Controllers/StartupController.cs +++ b/Jellyfin.Api/Controllers/StartupController.cs @@ -1,6 +1,6 @@ using System.Linq; using System.Threading.Tasks; -using Jellyfin.Api.Models.Startup; +using Jellyfin.Api.Models.StartupDtos; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Library; using Microsoft.AspNetCore.Authorization; diff --git a/Jellyfin.Api/Extensions/ApiApplicationBuilderExtensions.cs b/Jellyfin.Api/Extensions/ApiApplicationBuilderExtensions.cs deleted file mode 100644 index f70466ebec..0000000000 --- a/Jellyfin.Api/Extensions/ApiApplicationBuilderExtensions.cs +++ /dev/null @@ -1,27 +0,0 @@ -using Microsoft.AspNetCore.Builder; - -namespace Jellyfin.Api.Extensions -{ - /// - /// Extensions for adding API specific functionality to the application pipeline. - /// - public static class ApiApplicationBuilderExtensions - { - /// - /// Adds swagger and swagger UI to the application pipeline. - /// - /// The application builder. - /// The updated application builder. - public static IApplicationBuilder UseJellyfinApiSwagger(this IApplicationBuilder applicationBuilder) - { - applicationBuilder.UseSwagger(); - - // Enable middleware to serve swagger-ui (HTML, JS, CSS, etc.), - // specifying the Swagger JSON endpoint. - return applicationBuilder.UseSwaggerUI(c => - { - c.SwaggerEndpoint("/swagger/v1/swagger.json", "Jellyfin API V1"); - }); - } - } -} diff --git a/Jellyfin.Api/Extensions/ApiServiceCollectionExtensions.cs b/Jellyfin.Api/Extensions/ApiServiceCollectionExtensions.cs deleted file mode 100644 index 38f5f6d390..0000000000 --- a/Jellyfin.Api/Extensions/ApiServiceCollectionExtensions.cs +++ /dev/null @@ -1,96 +0,0 @@ -using Jellyfin.Api.Auth; -using Jellyfin.Api.Auth.FirstTimeSetupOrElevatedPolicy; -using Jellyfin.Api.Auth.RequiresElevationPolicy; -using Jellyfin.Api.Controllers; -using Microsoft.AspNetCore.Authentication; -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Mvc.Authorization; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.OpenApi.Models; - -namespace Jellyfin.Api.Extensions -{ - /// - /// API specific extensions for the service collection. - /// - public static class ApiServiceCollectionExtensions - { - /// - /// Adds jellyfin API authorization policies to the DI container. - /// - /// The service collection. - /// The updated service collection. - public static IServiceCollection AddJellyfinApiAuthorization(this IServiceCollection serviceCollection) - { - serviceCollection.AddSingleton(); - serviceCollection.AddSingleton(); - return serviceCollection.AddAuthorizationCore(options => - { - options.AddPolicy( - "RequiresElevation", - policy => - { - policy.AddAuthenticationSchemes("CustomAuthentication"); - policy.AddRequirements(new RequiresElevationRequirement()); - }); - options.AddPolicy( - "FirstTimeSetupOrElevated", - policy => - { - policy.AddAuthenticationSchemes("CustomAuthentication"); - policy.AddRequirements(new FirstTimeSetupOrElevatedRequirement()); - }); - }); - } - - /// - /// Adds custom legacy authentication to the service collection. - /// - /// The service collection. - /// The updated service collection. - public static AuthenticationBuilder AddCustomAuthentication(this IServiceCollection serviceCollection) - { - return serviceCollection.AddAuthentication("CustomAuthentication") - .AddScheme("CustomAuthentication", null); - } - - /// - /// Extension method for adding the jellyfin API to the service collection. - /// - /// The service collection. - /// The base url for the API. - /// The MVC builder. - public static IMvcBuilder AddJellyfinApi(this IServiceCollection serviceCollection, string baseUrl) - { - return serviceCollection.AddMvc(opts => - { - var policy = new AuthorizationPolicyBuilder() - .RequireAuthenticatedUser() - .Build(); - opts.Filters.Add(new AuthorizeFilter(policy)); - opts.EnableEndpointRouting = false; - opts.UseGeneralRoutePrefix(baseUrl); - }) - .SetCompatibilityVersion(CompatibilityVersion.Version_2_2) - - // Clear app parts to avoid other assemblies being picked up - .ConfigureApplicationPartManager(a => a.ApplicationParts.Clear()) - .AddApplicationPart(typeof(StartupController).Assembly) - .AddControllersAsServices(); - } - - /// - /// Adds Swagger to the service collection. - /// - /// The service collection. - /// The updated service collection. - public static IServiceCollection AddJellyfinApiSwagger(this IServiceCollection serviceCollection) - { - return serviceCollection.AddSwaggerGen(c => - { - c.SwaggerDoc("v1", new OpenApiInfo { Title = "Jellyfin API", Version = "v1" }); - }); - } - } -} diff --git a/Jellyfin.Api/Models/Startup/StartupConfigurationDto.cs b/Jellyfin.Api/Models/Startup/StartupConfigurationDto.cs deleted file mode 100644 index dac15e412c..0000000000 --- a/Jellyfin.Api/Models/Startup/StartupConfigurationDto.cs +++ /dev/null @@ -1,23 +0,0 @@ -namespace Jellyfin.Api.Models.Startup -{ - /// - /// The startup configuration DTO. - /// - public class StartupConfigurationDto - { - /// - /// Gets or sets UI language culture. - /// - public string UICulture { get; set; } - - /// - /// Gets or sets the metadata country code. - /// - public string MetadataCountryCode { get; set; } - - /// - /// Gets or sets the preferred language for the metadata. - /// - public string PreferredMetadataLanguage { get; set; } - } -} diff --git a/Jellyfin.Api/Models/Startup/StartupUserDto.cs b/Jellyfin.Api/Models/Startup/StartupUserDto.cs deleted file mode 100644 index 7e890d76a0..0000000000 --- a/Jellyfin.Api/Models/Startup/StartupUserDto.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace Jellyfin.Api.Models.Startup -{ - /// - /// The startup user DTO. - /// - public class StartupUserDto - { - /// - /// Gets or sets the username. - /// - public string Name { get; set; } - - /// - /// Gets or sets the user's password. - /// - public string Password { get; set; } - } -} diff --git a/Jellyfin.Api/Models/StartupDtos/StartupConfigurationDto.cs b/Jellyfin.Api/Models/StartupDtos/StartupConfigurationDto.cs new file mode 100644 index 0000000000..d048dad0a1 --- /dev/null +++ b/Jellyfin.Api/Models/StartupDtos/StartupConfigurationDto.cs @@ -0,0 +1,23 @@ +namespace Jellyfin.Api.Models.StartupDtos +{ + /// + /// The startup configuration DTO. + /// + public class StartupConfigurationDto + { + /// + /// Gets or sets UI language culture. + /// + public string UICulture { get; set; } + + /// + /// Gets or sets the metadata country code. + /// + public string MetadataCountryCode { get; set; } + + /// + /// Gets or sets the preferred language for the metadata. + /// + public string PreferredMetadataLanguage { get; set; } + } +} diff --git a/Jellyfin.Api/Models/StartupDtos/StartupUserDto.cs b/Jellyfin.Api/Models/StartupDtos/StartupUserDto.cs new file mode 100644 index 0000000000..3a9348037a --- /dev/null +++ b/Jellyfin.Api/Models/StartupDtos/StartupUserDto.cs @@ -0,0 +1,18 @@ +namespace Jellyfin.Api.Models.StartupDtos +{ + /// + /// The startup user DTO. + /// + public class StartupUserDto + { + /// + /// Gets or sets the username. + /// + public string Name { get; set; } + + /// + /// Gets or sets the user's password. + /// + public string Password { get; set; } + } +} diff --git a/Jellyfin.Server/Extensions/ApiApplicationBuilderExtensions.cs b/Jellyfin.Server/Extensions/ApiApplicationBuilderExtensions.cs new file mode 100644 index 0000000000..db06eb4552 --- /dev/null +++ b/Jellyfin.Server/Extensions/ApiApplicationBuilderExtensions.cs @@ -0,0 +1,27 @@ +using Microsoft.AspNetCore.Builder; + +namespace Jellyfin.Server.Extensions +{ + /// + /// Extensions for adding API specific functionality to the application pipeline. + /// + public static class ApiApplicationBuilderExtensions + { + /// + /// Adds swagger and swagger UI to the application pipeline. + /// + /// The application builder. + /// The updated application builder. + public static IApplicationBuilder UseJellyfinApiSwagger(this IApplicationBuilder applicationBuilder) + { + applicationBuilder.UseSwagger(); + + // Enable middleware to serve swagger-ui (HTML, JS, CSS, etc.), + // specifying the Swagger JSON endpoint. + return applicationBuilder.UseSwaggerUI(c => + { + c.SwaggerEndpoint("/swagger/v1/swagger.json", "Jellyfin API V1"); + }); + } + } +} diff --git a/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs b/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs new file mode 100644 index 0000000000..e5a8937e87 --- /dev/null +++ b/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs @@ -0,0 +1,89 @@ +using Jellyfin.Api; +using Jellyfin.Api.Auth; +using Jellyfin.Api.Auth.FirstTimeSetupOrElevatedPolicy; +using Jellyfin.Api.Auth.RequiresElevationPolicy; +using Jellyfin.Api.Controllers; +using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Authorization; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.OpenApi.Models; + +namespace Jellyfin.Server.Extensions +{ + /// + /// API specific extensions for the service collection. + /// + public static class ApiServiceCollectionExtensions + { + /// + /// Adds jellyfin API authorization policies to the DI container. + /// + /// The service collection. + /// The updated service collection. + public static IServiceCollection AddJellyfinApiAuthorization(this IServiceCollection serviceCollection) + { + serviceCollection.AddSingleton(); + serviceCollection.AddSingleton(); + return serviceCollection.AddAuthorizationCore(options => + { + options.AddPolicy( + "RequiresElevation", + policy => + { + policy.AddAuthenticationSchemes("CustomAuthentication"); + policy.AddRequirements(new RequiresElevationRequirement()); + }); + options.AddPolicy( + "FirstTimeSetupOrElevated", + policy => + { + policy.AddAuthenticationSchemes("CustomAuthentication"); + policy.AddRequirements(new FirstTimeSetupOrElevatedRequirement()); + }); + }); + } + + /// + /// Adds custom legacy authentication to the service collection. + /// + /// The service collection. + /// The updated service collection. + public static AuthenticationBuilder AddCustomAuthentication(this IServiceCollection serviceCollection) + { + return serviceCollection.AddAuthentication("CustomAuthentication") + .AddScheme("CustomAuthentication", null); + } + + /// + /// Extension method for adding the jellyfin API to the service collection. + /// + /// The service collection. + /// The base url for the API. + /// The MVC builder. + public static IMvcBuilder AddJellyfinApi(this IServiceCollection serviceCollection, string baseUrl) + { + return serviceCollection.AddMvc(opts => + { + opts.UseGeneralRoutePrefix(baseUrl); + }) + + // Clear app parts to avoid other assemblies being picked up + .ConfigureApplicationPartManager(a => a.ApplicationParts.Clear()) + .AddApplicationPart(typeof(StartupController).Assembly) + .AddControllersAsServices(); + } + + /// + /// Adds Swagger to the service collection. + /// + /// The service collection. + /// The updated service collection. + public static IServiceCollection AddJellyfinApiSwagger(this IServiceCollection serviceCollection) + { + return serviceCollection.AddSwaggerGen(c => + { + c.SwaggerDoc("v1", new OpenApiInfo { Title = "Jellyfin API", Version = "v1" }); + }); + } + } +} diff --git a/Jellyfin.Server/Jellyfin.Server.csproj b/Jellyfin.Server/Jellyfin.Server.csproj index 4238d7fe3e..dc784becfb 100644 --- a/Jellyfin.Server/Jellyfin.Server.csproj +++ b/Jellyfin.Server/Jellyfin.Server.csproj @@ -20,6 +20,10 @@ + + + + diff --git a/Jellyfin.Server/Program.cs b/Jellyfin.Server/Program.cs index e8bd0cd309..998f1125f5 100644 --- a/Jellyfin.Server/Program.cs +++ b/Jellyfin.Server/Program.cs @@ -18,8 +18,10 @@ using Jellyfin.Drawing.Skia; using MediaBrowser.Common.Configuration; using MediaBrowser.Controller.Drawing; using MediaBrowser.Model.Globalization; +using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.Logging; using Serilog; using Serilog.Extensions.Logging; @@ -164,7 +166,24 @@ namespace Jellyfin.Server appConfig); try { - await appHost.InitAsync(new ServiceCollection()).ConfigureAwait(false); + ServiceCollection serviceCollection = new ServiceCollection(); + await appHost.InitAsync(serviceCollection).ConfigureAwait(false); + + var host = CreateWebHostBuilder(appHost, serviceCollection).Build(); + + // A bit hacky to re-use service provider since ASP.NET doesn't allow a custom service collection. + appHost.ServiceProvider = host.Services; + appHost.FindParts(); + + try + { + await host.StartAsync().ConfigureAwait(false); + } + catch + { + _logger.LogError("Kestrel failed to start! This is most likely due to an invalid address or port bind - correct your bind configuration in system.xml and try again."); + throw; + } appHost.ImageProcessor.ImageEncoder = GetImageEncoder(appPaths, appHost.LocalizationManager); @@ -196,6 +215,55 @@ namespace Jellyfin.Server } } + private static IWebHostBuilder CreateWebHostBuilder(ApplicationHost appHost, IServiceCollection serviceCollection) + { + return new WebHostBuilder() + .UseKestrel(options => + { + var addresses = appHost.ServerConfigurationManager + .Configuration + .LocalNetworkAddresses + .Select(appHost.NormalizeConfiguredLocalAddress) + .Where(i => i != null) + .ToList(); + if (addresses.Any()) + { + foreach (var address in addresses) + { + _logger.LogInformation("Kestrel listening on {ipaddr}", address); + options.Listen(address, appHost.HttpPort); + + if (appHost.EnableHttps && appHost.Certificate != null) + { + options.Listen( + address, + appHost.HttpsPort, + listenOptions => listenOptions.UseHttps(appHost.Certificate)); + } + } + } + else + { + _logger.LogInformation("Kestrel listening on all interfaces"); + options.ListenAnyIP(appHost.HttpPort); + + if (appHost.EnableHttps && appHost.Certificate != null) + { + options.ListenAnyIP( + appHost.HttpsPort, + listenOptions => listenOptions.UseHttps(appHost.Certificate)); + } + } + }) + .UseContentRoot(appHost.ContentRoot) + .ConfigureServices(services => + { + // Merge the external ServiceCollection into ASP.NET DI + services.TryAdd(serviceCollection); + }) + .UseStartup(); + } + /// /// Create the data, config and log paths from the variety of inputs(command line args, /// environment variables) or decide on what default to use. For Windows it's %AppPath% diff --git a/Jellyfin.Server/Startup.cs b/Jellyfin.Server/Startup.cs new file mode 100644 index 0000000000..3ee5fb8b50 --- /dev/null +++ b/Jellyfin.Server/Startup.cs @@ -0,0 +1,81 @@ +using Jellyfin.Server.Extensions; +using MediaBrowser.Controller; +using MediaBrowser.Controller.Configuration; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; + +namespace Jellyfin.Server +{ + /// + /// Startup configuration for the Kestrel webhost. + /// + public class Startup + { + private readonly IServerConfigurationManager _serverConfigurationManager; + + /// + /// Initializes a new instance of the class. + /// + /// The server configuration manager. + public Startup(IServerConfigurationManager serverConfigurationManager) + { + _serverConfigurationManager = serverConfigurationManager; + } + + /// + /// Configures the service collection for the webhost. + /// + /// The service collection. + public void ConfigureServices(IServiceCollection services) + { + services.AddResponseCompression(); + services.AddHttpContextAccessor(); + services.AddJellyfinApi(_serverConfigurationManager.Configuration.BaseUrl.TrimStart('/')); + + services.AddJellyfinApiSwagger(); + + // configure custom legacy authentication + services.AddCustomAuthentication(); + + services.AddJellyfinApiAuthorization(); + } + + /// + /// Configures the app builder for the webhost. + /// + /// The application builder. + /// The webhost environment. + /// The server application host. + public void Configure( + IApplicationBuilder app, + IWebHostEnvironment env, + IServerApplicationHost serverApplicationHost) + { + if (env.IsDevelopment()) + { + app.UseDeveloperExceptionPage(); + } + + app.UseWebSockets(); + + app.UseResponseCompression(); + + // TODO app.UseMiddleware(); + app.Use(serverApplicationHost.ExecuteWebsocketHandlerAsync); + + // TODO use when old API is removed: app.UseAuthentication(); + app.UseJellyfinApiSwagger(); + app.UseRouting(); + app.UseAuthorization(); + app.UseEndpoints(endpoints => + { + endpoints.MapControllers(); + }); + + app.Use(serverApplicationHost.ExecuteHttpHandlerAsync); + } + } +} diff --git a/MediaBrowser.Controller/IServerApplicationHost.cs b/MediaBrowser.Controller/IServerApplicationHost.cs index 61b2c15ae2..b3c56bdd5f 100644 --- a/MediaBrowser.Controller/IServerApplicationHost.cs +++ b/MediaBrowser.Controller/IServerApplicationHost.cs @@ -5,6 +5,7 @@ using System.Threading; using System.Threading.Tasks; using MediaBrowser.Common; using MediaBrowser.Model.System; +using Microsoft.AspNetCore.Http; namespace MediaBrowser.Controller { @@ -87,5 +88,9 @@ namespace MediaBrowser.Controller string ExpandVirtualPath(string path); string ReverseVirtualPath(string path); + + Task ExecuteHttpHandlerAsync(HttpContext context, Func next); + + Task ExecuteWebsocketHandlerAsync(HttpContext context, Func next); } } -- cgit v1.2.3 From 6231fc18eac67966340fddc121dc2895fd99ab5e Mon Sep 17 00:00:00 2001 From: Cromefire_ <26320625+cromefire@users.noreply.github.com> Date: Fri, 13 Dec 2019 15:27:12 +0100 Subject: Fixed invalid username handling --- Emby.Server.Implementations/Session/SessionManager.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'Emby.Server.Implementations/Session') diff --git a/Emby.Server.Implementations/Session/SessionManager.cs b/Emby.Server.Implementations/Session/SessionManager.cs index b87ca3a114..80079ae6c0 100644 --- a/Emby.Server.Implementations/Session/SessionManager.cs +++ b/Emby.Server.Implementations/Session/SessionManager.cs @@ -1393,6 +1393,13 @@ namespace Emby.Server.Implementations.Session } } + if (user == null) + { + AuthenticationFailed?.Invoke(this, new GenericEventArgs(request)); + + throw new SecurityException("Invalid user or password entered."); + } + if (enforcePassword) { user = await _userManager.AuthenticateUser( @@ -1403,13 +1410,6 @@ namespace Emby.Server.Implementations.Session true).ConfigureAwait(false); } - if (user == null) - { - AuthenticationFailed?.Invoke(this, new GenericEventArgs(request)); - - throw new SecurityException("Invalid user or password entered."); - } - var token = GetAuthorizationToken(user, request.DeviceId, request.App, request.AppVersion, request.DeviceName); var session = LogSessionActivity( -- cgit v1.2.3 From 7e987b9642fd1826b9adb8dc6e208454c44da4dc Mon Sep 17 00:00:00 2001 From: Cromefire_ <26320625+cromefire@users.noreply.github.com> Date: Fri, 13 Dec 2019 15:30:08 +0100 Subject: Remove whitespace Co-Authored-By: Claus Vium --- Emby.Server.Implementations/Session/SessionManager.cs | 1 - 1 file changed, 1 deletion(-) (limited to 'Emby.Server.Implementations/Session') diff --git a/Emby.Server.Implementations/Session/SessionManager.cs b/Emby.Server.Implementations/Session/SessionManager.cs index 80079ae6c0..367e1d4983 100644 --- a/Emby.Server.Implementations/Session/SessionManager.cs +++ b/Emby.Server.Implementations/Session/SessionManager.cs @@ -1396,7 +1396,6 @@ namespace Emby.Server.Implementations.Session if (user == null) { AuthenticationFailed?.Invoke(this, new GenericEventArgs(request)); - throw new SecurityException("Invalid user or password entered."); } -- cgit v1.2.3 From 02928128b998608e0a6fd2f8ac611be5961fa78f Mon Sep 17 00:00:00 2001 From: dkanada Date: Sat, 14 Dec 2019 11:36:06 +0900 Subject: track progress for any item that supports the feature --- Emby.Server.Implementations/Library/UserDataManager.cs | 8 +++----- Emby.Server.Implementations/Session/SessionManager.cs | 8 ++------ 2 files changed, 5 insertions(+), 11 deletions(-) (limited to 'Emby.Server.Implementations/Session') diff --git a/Emby.Server.Implementations/Library/UserDataManager.cs b/Emby.Server.Implementations/Library/UserDataManager.cs index 48d33c26c1..071681b08f 100644 --- a/Emby.Server.Implementations/Library/UserDataManager.cs +++ b/Emby.Server.Implementations/Library/UserDataManager.cs @@ -226,24 +226,21 @@ namespace Emby.Server.Implementations.Library { var pctIn = decimal.Divide(positionTicks, runtimeTicks) * 100; - // Don't track in very beginning if (pctIn < _config.Configuration.MinResumePct) { + // ignore progress during the beginning positionTicks = 0; } - - // If we're at the end, assume completed else if (pctIn > _config.Configuration.MaxResumePct || positionTicks >= runtimeTicks) { + // mark as completed close to the end positionTicks = 0; data.Played = playedToCompletion = true; } - else { // Enforce MinResumeDuration var durationSeconds = TimeSpan.FromTicks(runtimeTicks).TotalSeconds; - if (durationSeconds < _config.Configuration.MinResumeDurationSeconds) { positionTicks = 0; @@ -263,6 +260,7 @@ namespace Emby.Server.Implementations.Library positionTicks = 0; data.Played = false; } + if (!item.SupportsPositionTicksResume) { positionTicks = 0; diff --git a/Emby.Server.Implementations/Session/SessionManager.cs b/Emby.Server.Implementations/Session/SessionManager.cs index b87ca3a114..34ffceebd2 100644 --- a/Emby.Server.Implementations/Session/SessionManager.cs +++ b/Emby.Server.Implementations/Session/SessionManager.cs @@ -667,12 +667,9 @@ namespace Emby.Server.Implementations.Session data.PlayCount++; data.LastPlayedDate = DateTime.UtcNow; - if (item.SupportsPlayedStatus) + if (item.SupportsPlayedStatus && !item.SupportsPositionTicksResume) { - if (!(item is Video)) - { - data.Played = true; - } + data.Played = true; } else { @@ -769,7 +766,6 @@ namespace Emby.Server.Implementations.Session { _userDataManager.SaveUserData(user, item, data, UserDataSaveReason.PlaybackProgress, CancellationToken.None); } - } private static bool UpdatePlaybackSettings(User user, PlaybackProgressInfo info, UserItemData data) -- cgit v1.2.3