diff options
36 files changed, 277 insertions, 325 deletions
diff --git a/Emby.Dlna/Didl/DidlBuilder.cs b/Emby.Dlna/Didl/DidlBuilder.cs index 8b50d47fb..66ae07329 100644 --- a/Emby.Dlna/Didl/DidlBuilder.cs +++ b/Emby.Dlna/Didl/DidlBuilder.cs @@ -208,7 +208,8 @@ namespace Emby.Dlna.Didl var targetWidth = streamInfo.TargetWidth; var targetHeight = streamInfo.TargetHeight; - var contentFeatureList = new ContentFeatureBuilder(_profile).BuildVideoHeader( + var contentFeatureList = ContentFeatureBuilder.BuildVideoHeader( + _profile, streamInfo.Container, streamInfo.TargetVideoCodec.FirstOrDefault(), streamInfo.TargetAudioCodec.FirstOrDefault(), @@ -599,7 +600,8 @@ namespace Emby.Dlna.Didl ? MimeTypes.GetMimeType(filename) : mediaProfile.MimeType; - var contentFeatures = new ContentFeatureBuilder(_profile).BuildAudioHeader( + var contentFeatures = ContentFeatureBuilder.BuildAudioHeader( + _profile, streamInfo.Container, streamInfo.TargetAudioCodec.FirstOrDefault(), targetAudioBitrate, @@ -1033,8 +1035,7 @@ namespace Emby.Dlna.Didl var width = albumartUrlInfo.width ?? maxWidth; var height = albumartUrlInfo.height ?? maxHeight; - var contentFeatures = new ContentFeatureBuilder(_profile) - .BuildImageHeader(format, width, height, imageInfo.IsDirectStream, org_Pn); + var contentFeatures = ContentFeatureBuilder.BuildImageHeader(_profile, format, width, height, imageInfo.IsDirectStream, org_Pn); writer.WriteAttributeString( "protocolInfo", diff --git a/Emby.Dlna/PlayTo/PlayToController.cs b/Emby.Dlna/PlayTo/PlayToController.cs index 25ba18add..ee09cc65a 100644 --- a/Emby.Dlna/PlayTo/PlayToController.cs +++ b/Emby.Dlna/PlayTo/PlayToController.cs @@ -499,8 +499,8 @@ namespace Emby.Dlna.PlayTo if (streamInfo.MediaType == DlnaProfileType.Audio) { - return new ContentFeatureBuilder(profile) - .BuildAudioHeader( + return ContentFeatureBuilder.BuildAudioHeader( + profile, streamInfo.Container, streamInfo.TargetAudioCodec.FirstOrDefault(), streamInfo.TargetAudioBitrate, @@ -514,8 +514,8 @@ namespace Emby.Dlna.PlayTo if (streamInfo.MediaType == DlnaProfileType.Video) { - var list = new ContentFeatureBuilder(profile) - .BuildVideoHeader( + var list = ContentFeatureBuilder.BuildVideoHeader( + profile, streamInfo.Container, streamInfo.TargetVideoCodec.FirstOrDefault(), streamInfo.TargetAudioCodec.FirstOrDefault(), diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index 0512adf10..703f8d20d 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -607,12 +607,8 @@ namespace Emby.Server.Implementations ServiceCollection.AddSingleton<IAuthenticationRepository, AuthenticationRepository>(); - // TODO: Refactor to eliminate the circular dependency here so that Lazy<T> isn't required - ServiceCollection.AddTransient(provider => new Lazy<IDtoService>(provider.GetRequiredService<IDtoService>)); - - // TODO: Refactor to eliminate the circular dependency here so that Lazy<T> isn't required - ServiceCollection.AddTransient(provider => new Lazy<EncodingHelper>(provider.GetRequiredService<EncodingHelper>)); ServiceCollection.AddSingleton<IMediaEncoder, MediaBrowser.MediaEncoding.Encoder.MediaEncoder>(); + ServiceCollection.AddSingleton<EncodingHelper>(); // TODO: Refactor to eliminate the circular dependencies here so that Lazy<T> isn't required ServiceCollection.AddTransient(provider => new Lazy<ILibraryMonitor>(provider.GetRequiredService<ILibraryMonitor>)); @@ -677,8 +673,6 @@ namespace Emby.Server.Implementations ServiceCollection.AddSingleton<ISubtitleEncoder, MediaBrowser.MediaEncoding.Subtitles.SubtitleEncoder>(); - ServiceCollection.AddSingleton<EncodingHelper>(); - ServiceCollection.AddSingleton<IAttachmentExtractor, MediaBrowser.MediaEncoding.Attachments.AttachmentExtractor>(); ServiceCollection.AddSingleton<TranscodingJobHelper>(); diff --git a/Emby.Server.Implementations/Collections/CollectionManager.cs b/Emby.Server.Implementations/Collections/CollectionManager.cs index e984afdba..1b85a9d4b 100644 --- a/Emby.Server.Implementations/Collections/CollectionManager.cs +++ b/Emby.Server.Implementations/Collections/CollectionManager.cs @@ -121,7 +121,7 @@ namespace Emby.Server.Implementations.Collections private IEnumerable<BoxSet> GetCollections(User user) { - var folder = GetCollectionsFolder(false).Result; + var folder = GetCollectionsFolder(false).GetAwaiter().GetResult(); return folder == null ? Enumerable.Empty<BoxSet>() @@ -316,11 +316,11 @@ namespace Emby.Server.Implementations.Collections { var results = new Dictionary<Guid, BaseItem>(); - var allBoxsets = GetCollections(user).ToList(); + var allBoxSets = GetCollections(user).ToList(); foreach (var item in items) { - if (!(item is ISupportsBoxSetGrouping)) + if (item is not ISupportsBoxSetGrouping) { results[item.Id] = item; } @@ -328,34 +328,45 @@ namespace Emby.Server.Implementations.Collections { var itemId = item.Id; - var currentBoxSets = allBoxsets - .Where(i => i.ContainsLinkedChildByItemId(itemId)) - .ToList(); - - if (currentBoxSets.Count > 0) + var itemIsInBoxSet = false; + foreach (var boxSet in allBoxSets) { - foreach (var boxset in currentBoxSets) + if (!boxSet.ContainsLinkedChildByItemId(itemId)) { - results[boxset.Id] = boxset; + continue; } + + itemIsInBoxSet = true; + + results.TryAdd(boxSet.Id, boxSet); + } + + // skip any item that is in a box set + if (itemIsInBoxSet) + { + continue; } - else + + var alreadyInResults = false; + // this is kind of a performance hack because only Video has alternate versions that should be in a box set? + if (item is Video video) { - var alreadyInResults = false; - foreach (var child in item.GetMediaSources(true)) + foreach (var childId in video.GetLocalAlternateVersionIds()) { - if (Guid.TryParse(child.Id, out var id) && results.ContainsKey(id)) + if (!results.ContainsKey(childId)) { - alreadyInResults = true; - break; + continue; } - } - if (!alreadyInResults) - { - results[item.Id] = item; + alreadyInResults = true; + break; } } + + if (!alreadyInResults) + { + results[itemId] = item; + } } } diff --git a/Emby.Server.Implementations/Library/UserDataManager.cs b/Emby.Server.Implementations/Library/UserDataManager.cs index e8caea196..827e3c64b 100644 --- a/Emby.Server.Implementations/Library/UserDataManager.cs +++ b/Emby.Server.Implementations/Library/UserDataManager.cs @@ -248,15 +248,15 @@ namespace Emby.Server.Implementations.Library } else if (positionTicks > 0 && hasRuntime && item is AudioBook) { - var minIn = TimeSpan.FromTicks(positionTicks).TotalMinutes; - var minOut = TimeSpan.FromTicks(runtimeTicks - positionTicks).TotalMinutes; + var playbackPositionInMinutes = TimeSpan.FromTicks(positionTicks).TotalMinutes; + var remainingTimeInMinutes = TimeSpan.FromTicks(runtimeTicks - positionTicks).TotalMinutes; - if (minIn > _config.Configuration.MinAudiobookResume) + if (playbackPositionInMinutes < _config.Configuration.MinAudiobookResume) { // ignore progress during the beginning positionTicks = 0; } - else if (minOut < _config.Configuration.MaxAudiobookResume || positionTicks >= runtimeTicks) + else if (remainingTimeInMinutes < _config.Configuration.MaxAudiobookResume || positionTicks >= runtimeTicks) { // mark as completed close to the end positionTicks = 0; diff --git a/Emby.Server.Implementations/Session/SessionManager.cs b/Emby.Server.Implementations/Session/SessionManager.cs index 10e28c33a..6f21ec31e 100644 --- a/Emby.Server.Implementations/Session/SessionManager.cs +++ b/Emby.Server.Implementations/Session/SessionManager.cs @@ -1485,7 +1485,7 @@ namespace Emby.Server.Implementations.Session user = await _userManager.AuthenticateUser( request.Username, request.Password, - request.PasswordSha1, + null, request.RemoteEndPoint, true).ConfigureAwait(false); } diff --git a/Jellyfin.Api/Controllers/DynamicHlsController.cs b/Jellyfin.Api/Controllers/DynamicHlsController.cs index c4e75fe85..b4154b361 100644 --- a/Jellyfin.Api/Controllers/DynamicHlsController.cs +++ b/Jellyfin.Api/Controllers/DynamicHlsController.cs @@ -52,8 +52,6 @@ namespace Jellyfin.Api.Controllers private readonly IServerConfigurationManager _serverConfigurationManager; private readonly IMediaEncoder _mediaEncoder; private readonly IFileSystem _fileSystem; - private readonly ISubtitleEncoder _subtitleEncoder; - private readonly IConfiguration _configuration; private readonly IDeviceManager _deviceManager; private readonly TranscodingJobHelper _transcodingJobHelper; private readonly ILogger<DynamicHlsController> _logger; @@ -72,12 +70,11 @@ namespace Jellyfin.Api.Controllers /// <param name="serverConfigurationManager">Instance of the <see cref="IServerConfigurationManager"/> interface.</param> /// <param name="mediaEncoder">Instance of the <see cref="IMediaEncoder"/> interface.</param> /// <param name="fileSystem">Instance of the <see cref="IFileSystem"/> interface.</param> - /// <param name="subtitleEncoder">Instance of the <see cref="ISubtitleEncoder"/> interface.</param> - /// <param name="configuration">Instance of the <see cref="IConfiguration"/> interface.</param> /// <param name="deviceManager">Instance of the <see cref="IDeviceManager"/> interface.</param> /// <param name="transcodingJobHelper">Instance of the <see cref="TranscodingJobHelper"/> class.</param> /// <param name="logger">Instance of the <see cref="ILogger{DynamicHlsController}"/> interface.</param> /// <param name="dynamicHlsHelper">Instance of <see cref="DynamicHlsHelper"/>.</param> + /// <param name="encodingHelper">Instance of <see cref="EncodingHelper"/>.</param> public DynamicHlsController( ILibraryManager libraryManager, IUserManager userManager, @@ -87,15 +84,12 @@ namespace Jellyfin.Api.Controllers IServerConfigurationManager serverConfigurationManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, - ISubtitleEncoder subtitleEncoder, - IConfiguration configuration, IDeviceManager deviceManager, TranscodingJobHelper transcodingJobHelper, ILogger<DynamicHlsController> logger, - DynamicHlsHelper dynamicHlsHelper) + DynamicHlsHelper dynamicHlsHelper, + EncodingHelper encodingHelper) { - _encodingHelper = new EncodingHelper(mediaEncoder, fileSystem, subtitleEncoder, configuration); - _libraryManager = libraryManager; _userManager = userManager; _dlnaManager = dlnaManager; @@ -104,12 +98,12 @@ namespace Jellyfin.Api.Controllers _serverConfigurationManager = serverConfigurationManager; _mediaEncoder = mediaEncoder; _fileSystem = fileSystem; - _subtitleEncoder = subtitleEncoder; - _configuration = configuration; _deviceManager = deviceManager; _transcodingJobHelper = transcodingJobHelper; _logger = logger; _dynamicHlsHelper = dynamicHlsHelper; + _encodingHelper = encodingHelper; + _encodingOptions = serverConfigurationManager.GetEncodingOptions(); } @@ -1126,9 +1120,7 @@ namespace Jellyfin.Api.Controllers _libraryManager, _serverConfigurationManager, _mediaEncoder, - _fileSystem, - _subtitleEncoder, - _configuration, + _encodingHelper, _dlnaManager, _deviceManager, _transcodingJobHelper, @@ -1211,9 +1203,7 @@ namespace Jellyfin.Api.Controllers _libraryManager, _serverConfigurationManager, _mediaEncoder, - _fileSystem, - _subtitleEncoder, - _configuration, + _encodingHelper, _dlnaManager, _deviceManager, _transcodingJobHelper, diff --git a/Jellyfin.Api/Controllers/MoviesController.cs b/Jellyfin.Api/Controllers/MoviesController.cs index 4d788ad7d..d0a2358ae 100644 --- a/Jellyfin.Api/Controllers/MoviesController.cs +++ b/Jellyfin.Api/Controllers/MoviesController.cs @@ -89,7 +89,7 @@ namespace Jellyfin.Api.Controllers // nameof(LiveTvProgram) }, // IsMovie = true - OrderBy = new[] { ItemSortBy.DatePlayed, ItemSortBy.Random }.Select(i => new ValueTuple<string, SortOrder>(i, SortOrder.Descending)).ToArray(), + OrderBy = new[] { (ItemSortBy.DatePlayed, SortOrder.Descending), (ItemSortBy.Random, SortOrder.Descending) }, Limit = 7, ParentId = parentIdGuid, Recursive = true, @@ -110,7 +110,7 @@ namespace Jellyfin.Api.Controllers { IncludeItemTypes = itemTypes.ToArray(), IsMovie = true, - OrderBy = new[] { ItemSortBy.Random }.Select(i => new ValueTuple<string, SortOrder>(i, SortOrder.Descending)).ToArray(), + OrderBy = new[] { (ItemSortBy.Random, SortOrder.Descending) }, Limit = 10, IsFavoriteOrLiked = true, ExcludeItemIds = recentlyPlayedMovies.Select(i => i.Id).ToArray(), @@ -120,7 +120,7 @@ namespace Jellyfin.Api.Controllers DtoOptions = dtoOptions }); - var mostRecentMovies = recentlyPlayedMovies.Take(6).ToList(); + var mostRecentMovies = recentlyPlayedMovies.GetRange(0, Math.Min(recentlyPlayedMovies.Count, 6)); // Get recently played directors var recentDirectors = GetDirectors(mostRecentMovies) .ToList(); @@ -191,7 +191,8 @@ namespace Jellyfin.Api.Controllers foreach (var name in names) { - var items = _libraryManager.GetItemList(new InternalItemsQuery(user) + var items = _libraryManager.GetItemList( + new InternalItemsQuery(user) { Person = name, // Account for duplicates by imdb id, since the database doesn't support this yet diff --git a/Jellyfin.Api/Controllers/SuggestionsController.cs b/Jellyfin.Api/Controllers/SuggestionsController.cs index a55f13e66..a811a29c3 100644 --- a/Jellyfin.Api/Controllers/SuggestionsController.cs +++ b/Jellyfin.Api/Controllers/SuggestionsController.cs @@ -69,7 +69,7 @@ namespace Jellyfin.Api.Controllers var dtoOptions = new DtoOptions().AddClientFields(Request); var result = _libraryManager.GetItemsResult(new InternalItemsQuery(user) { - OrderBy = new[] { ItemSortBy.Random }.Select(i => new ValueTuple<string, SortOrder>(i, SortOrder.Descending)).ToArray(), + OrderBy = new[] { (ItemSortBy.Random, SortOrder.Descending) }, MediaTypes = mediaType, IncludeItemTypes = type, IsVirtualItem = false, diff --git a/Jellyfin.Api/Controllers/TvShowsController.cs b/Jellyfin.Api/Controllers/TvShowsController.cs index e1c67f830..59400db2a 100644 --- a/Jellyfin.Api/Controllers/TvShowsController.cs +++ b/Jellyfin.Api/Controllers/TvShowsController.cs @@ -155,7 +155,7 @@ namespace Jellyfin.Api.Controllers var itemsResult = _libraryManager.GetItemList(new InternalItemsQuery(user) { IncludeItemTypes = new[] { nameof(Episode) }, - OrderBy = new[] { ItemSortBy.PremiereDate, ItemSortBy.SortName }.Select(i => new ValueTuple<string, SortOrder>(i, SortOrder.Ascending)).ToArray(), + OrderBy = new[] { (ItemSortBy.PremiereDate, SortOrder.Ascending), (ItemSortBy.SortName, SortOrder.Ascending) }, MinPremiereDate = minPremiereDate, StartIndex = startIndex, Limit = limit, diff --git a/Jellyfin.Api/Controllers/UserController.cs b/Jellyfin.Api/Controllers/UserController.cs index 3c0d2aca1..b13db4baa 100644 --- a/Jellyfin.Api/Controllers/UserController.cs +++ b/Jellyfin.Api/Controllers/UserController.cs @@ -177,11 +177,9 @@ namespace Jellyfin.Api.Controllers return StatusCode(StatusCodes.Status403Forbidden, "Only sha1 password is not allowed."); } - // Password should always be null AuthenticateUserByName request = new AuthenticateUserByName { Username = user.Username, - Password = null, Pw = pw }; return await AuthenticateUserByName(request).ConfigureAwait(false); @@ -208,7 +206,6 @@ namespace Jellyfin.Api.Controllers DeviceId = auth.DeviceId, DeviceName = auth.Device, Password = request.Pw, - PasswordSha1 = request.Password, RemoteEndPoint = HttpContext.GetNormalizedRemoteIp().ToString(), Username = request.Username }).ConfigureAwait(false); diff --git a/Jellyfin.Api/Controllers/VideoHlsController.cs b/Jellyfin.Api/Controllers/VideoHlsController.cs index e95410d02..308334b23 100644 --- a/Jellyfin.Api/Controllers/VideoHlsController.cs +++ b/Jellyfin.Api/Controllers/VideoHlsController.cs @@ -48,9 +48,6 @@ namespace Jellyfin.Api.Controllers private readonly IMediaSourceManager _mediaSourceManager; private readonly IServerConfigurationManager _serverConfigurationManager; private readonly IMediaEncoder _mediaEncoder; - private readonly IFileSystem _fileSystem; - private readonly ISubtitleEncoder _subtitleEncoder; - private readonly IConfiguration _configuration; private readonly IDeviceManager _deviceManager; private readonly TranscodingJobHelper _transcodingJobHelper; private readonly ILogger<VideoHlsController> _logger; @@ -60,9 +57,6 @@ namespace Jellyfin.Api.Controllers /// Initializes a new instance of the <see cref="VideoHlsController"/> class. /// </summary> /// <param name="mediaEncoder">Instance of the <see cref="IMediaEncoder"/> interface.</param> - /// <param name="fileSystem">Instance of the <see cref="IFileSystem"/> interface.</param> - /// <param name="subtitleEncoder">Instance of the <see cref="ISubtitleEncoder"/> interface.</param> - /// <param name="configuration">Instance of the <see cref="IConfiguration"/> interface.</param> /// <param name="dlnaManager">Instance of the <see cref="IDlnaManager"/> interface.</param> /// <param name="userManger">Instance of the <see cref="IUserManager"/> interface.</param> /// <param name="authorizationContext">Instance of the <see cref="IAuthorizationContext"/> interface.</param> @@ -72,11 +66,9 @@ namespace Jellyfin.Api.Controllers /// <param name="deviceManager">Instance of the <see cref="IDeviceManager"/> interface.</param> /// <param name="transcodingJobHelper">The <see cref="TranscodingJobHelper"/> singleton.</param> /// <param name="logger">Instance of the <see cref="ILogger{VideoHlsController}"/>.</param> + /// <param name="encodingHelper">Instance of <see cref="EncodingHelper"/>.</param> public VideoHlsController( IMediaEncoder mediaEncoder, - IFileSystem fileSystem, - ISubtitleEncoder subtitleEncoder, - IConfiguration configuration, IDlnaManager dlnaManager, IUserManager userManger, IAuthorizationContext authorizationContext, @@ -85,10 +77,9 @@ namespace Jellyfin.Api.Controllers IServerConfigurationManager serverConfigurationManager, IDeviceManager deviceManager, TranscodingJobHelper transcodingJobHelper, - ILogger<VideoHlsController> logger) + ILogger<VideoHlsController> logger, + EncodingHelper encodingHelper) { - _encodingHelper = new EncodingHelper(mediaEncoder, fileSystem, subtitleEncoder, configuration); - _dlnaManager = dlnaManager; _authContext = authorizationContext; _userManager = userManger; @@ -96,12 +87,11 @@ namespace Jellyfin.Api.Controllers _mediaSourceManager = mediaSourceManager; _serverConfigurationManager = serverConfigurationManager; _mediaEncoder = mediaEncoder; - _fileSystem = fileSystem; - _subtitleEncoder = subtitleEncoder; - _configuration = configuration; _deviceManager = deviceManager; _transcodingJobHelper = transcodingJobHelper; _logger = logger; + _encodingHelper = encodingHelper; + _encodingOptions = serverConfigurationManager.GetEncodingOptions(); } @@ -285,9 +275,7 @@ namespace Jellyfin.Api.Controllers _libraryManager, _serverConfigurationManager, _mediaEncoder, - _fileSystem, - _subtitleEncoder, - _configuration, + _encodingHelper, _dlnaManager, _deviceManager, _transcodingJobHelper, diff --git a/Jellyfin.Api/Controllers/VideosController.cs b/Jellyfin.Api/Controllers/VideosController.cs index 699ca5327..8dbb6aaa5 100644 --- a/Jellyfin.Api/Controllers/VideosController.cs +++ b/Jellyfin.Api/Controllers/VideosController.cs @@ -49,12 +49,10 @@ namespace Jellyfin.Api.Controllers private readonly IMediaSourceManager _mediaSourceManager; private readonly IServerConfigurationManager _serverConfigurationManager; private readonly IMediaEncoder _mediaEncoder; - private readonly IFileSystem _fileSystem; - private readonly ISubtitleEncoder _subtitleEncoder; - private readonly IConfiguration _configuration; private readonly IDeviceManager _deviceManager; private readonly TranscodingJobHelper _transcodingJobHelper; private readonly IHttpClientFactory _httpClientFactory; + private readonly EncodingHelper _encodingHelper; private readonly TranscodingJobType _transcodingJobType = TranscodingJobType.Progressive; @@ -69,12 +67,10 @@ namespace Jellyfin.Api.Controllers /// <param name="mediaSourceManager">Instance of the <see cref="IMediaSourceManager"/> interface.</param> /// <param name="serverConfigurationManager">Instance of the <see cref="IServerConfigurationManager"/> interface.</param> /// <param name="mediaEncoder">Instance of the <see cref="IMediaEncoder"/> interface.</param> - /// <param name="fileSystem">Instance of the <see cref="IFileSystem"/> interface.</param> - /// <param name="subtitleEncoder">Instance of the <see cref="ISubtitleEncoder"/> interface.</param> - /// <param name="configuration">Instance of the <see cref="IConfiguration"/> interface.</param> /// <param name="deviceManager">Instance of the <see cref="IDeviceManager"/> interface.</param> /// <param name="transcodingJobHelper">Instance of the <see cref="TranscodingJobHelper"/> class.</param> /// <param name="httpClientFactory">Instance of the <see cref="IHttpClientFactory"/> interface.</param> + /// <param name="encodingHelper">Instance of <see cref="EncodingHelper"/>.</param> public VideosController( ILibraryManager libraryManager, IUserManager userManager, @@ -84,12 +80,10 @@ namespace Jellyfin.Api.Controllers IMediaSourceManager mediaSourceManager, IServerConfigurationManager serverConfigurationManager, IMediaEncoder mediaEncoder, - IFileSystem fileSystem, - ISubtitleEncoder subtitleEncoder, - IConfiguration configuration, IDeviceManager deviceManager, TranscodingJobHelper transcodingJobHelper, - IHttpClientFactory httpClientFactory) + IHttpClientFactory httpClientFactory, + EncodingHelper encodingHelper) { _libraryManager = libraryManager; _userManager = userManager; @@ -99,12 +93,10 @@ namespace Jellyfin.Api.Controllers _mediaSourceManager = mediaSourceManager; _serverConfigurationManager = serverConfigurationManager; _mediaEncoder = mediaEncoder; - _fileSystem = fileSystem; - _subtitleEncoder = subtitleEncoder; - _configuration = configuration; _deviceManager = deviceManager; _transcodingJobHelper = transcodingJobHelper; _httpClientFactory = httpClientFactory; + _encodingHelper = encodingHelper; } /// <summary> @@ -444,9 +436,7 @@ namespace Jellyfin.Api.Controllers _libraryManager, _serverConfigurationManager, _mediaEncoder, - _fileSystem, - _subtitleEncoder, - _configuration, + _encodingHelper, _dlnaManager, _deviceManager, _transcodingJobHelper, @@ -515,8 +505,7 @@ namespace Jellyfin.Api.Controllers // Need to start ffmpeg (because media can't be returned directly) var encodingOptions = _serverConfigurationManager.GetEncodingOptions(); - var encodingHelper = new EncodingHelper(_mediaEncoder, _fileSystem, _subtitleEncoder, _configuration); - var ffmpegCommandLineArguments = encodingHelper.GetProgressiveVideoFullCommandLine(state, encodingOptions, outputPath, "superfast"); + var ffmpegCommandLineArguments = _encodingHelper.GetProgressiveVideoFullCommandLine(state, encodingOptions, outputPath, "superfast"); return await FileStreamResponseHelpers.GetTranscodedFile( state, isHeadRequest, diff --git a/Jellyfin.Api/Helpers/AudioHelper.cs b/Jellyfin.Api/Helpers/AudioHelper.cs index 9c35d1ec1..cf35ee23a 100644 --- a/Jellyfin.Api/Helpers/AudioHelper.cs +++ b/Jellyfin.Api/Helpers/AudioHelper.cs @@ -32,13 +32,11 @@ namespace Jellyfin.Api.Helpers private readonly IMediaSourceManager _mediaSourceManager; private readonly IServerConfigurationManager _serverConfigurationManager; private readonly IMediaEncoder _mediaEncoder; - private readonly IFileSystem _fileSystem; - private readonly ISubtitleEncoder _subtitleEncoder; - private readonly IConfiguration _configuration; private readonly IDeviceManager _deviceManager; private readonly TranscodingJobHelper _transcodingJobHelper; private readonly IHttpClientFactory _httpClientFactory; private readonly IHttpContextAccessor _httpContextAccessor; + private readonly EncodingHelper _encodingHelper; /// <summary> /// Initializes a new instance of the <see cref="AudioHelper"/> class. @@ -50,13 +48,11 @@ namespace Jellyfin.Api.Helpers /// <param name="mediaSourceManager">Instance of the <see cref="IMediaSourceManager"/> interface.</param> /// <param name="serverConfigurationManager">Instance of the <see cref="IServerConfigurationManager"/> interface.</param> /// <param name="mediaEncoder">Instance of the <see cref="IMediaEncoder"/> interface.</param> - /// <param name="fileSystem">Instance of the <see cref="IFileSystem"/> interface.</param> - /// <param name="subtitleEncoder">Instance of the <see cref="ISubtitleEncoder"/> interface.</param> - /// <param name="configuration">Instance of the <see cref="IConfiguration"/> interface.</param> /// <param name="deviceManager">Instance of the <see cref="IDeviceManager"/> interface.</param> /// <param name="transcodingJobHelper">Instance of <see cref="TranscodingJobHelper"/>.</param> /// <param name="httpClientFactory">Instance of the <see cref="IHttpClientFactory"/> interface.</param> /// <param name="httpContextAccessor">Instance of the <see cref="IHttpContextAccessor"/> interface.</param> + /// <param name="encodingHelper">Instance of <see cref="EncodingHelper"/>.</param> public AudioHelper( IDlnaManager dlnaManager, IAuthorizationContext authContext, @@ -65,13 +61,11 @@ namespace Jellyfin.Api.Helpers IMediaSourceManager mediaSourceManager, IServerConfigurationManager serverConfigurationManager, IMediaEncoder mediaEncoder, - IFileSystem fileSystem, - ISubtitleEncoder subtitleEncoder, - IConfiguration configuration, IDeviceManager deviceManager, TranscodingJobHelper transcodingJobHelper, IHttpClientFactory httpClientFactory, - IHttpContextAccessor httpContextAccessor) + IHttpContextAccessor httpContextAccessor, + EncodingHelper encodingHelper) { _dlnaManager = dlnaManager; _authContext = authContext; @@ -80,13 +74,11 @@ namespace Jellyfin.Api.Helpers _mediaSourceManager = mediaSourceManager; _serverConfigurationManager = serverConfigurationManager; _mediaEncoder = mediaEncoder; - _fileSystem = fileSystem; - _subtitleEncoder = subtitleEncoder; - _configuration = configuration; _deviceManager = deviceManager; _transcodingJobHelper = transcodingJobHelper; _httpClientFactory = httpClientFactory; _httpContextAccessor = httpContextAccessor; + _encodingHelper = encodingHelper; } /// <summary> @@ -116,9 +108,7 @@ namespace Jellyfin.Api.Helpers _libraryManager, _serverConfigurationManager, _mediaEncoder, - _fileSystem, - _subtitleEncoder, - _configuration, + _encodingHelper, _dlnaManager, _deviceManager, _transcodingJobHelper, @@ -187,8 +177,7 @@ namespace Jellyfin.Api.Helpers // Need to start ffmpeg (because media can't be returned directly) var encodingOptions = _serverConfigurationManager.GetEncodingOptions(); - var encodingHelper = new EncodingHelper(_mediaEncoder, _fileSystem, _subtitleEncoder, _configuration); - var ffmpegCommandLineArguments = encodingHelper.GetProgressiveAudioFullCommandLine(state, encodingOptions, outputPath); + var ffmpegCommandLineArguments = _encodingHelper.GetProgressiveAudioFullCommandLine(state, encodingOptions, outputPath); return await FileStreamResponseHelpers.GetTranscodedFile( state, isHeadRequest, diff --git a/Jellyfin.Api/Helpers/DynamicHlsHelper.cs b/Jellyfin.Api/Helpers/DynamicHlsHelper.cs index 1bb504ad1..fcada0e77 100644 --- a/Jellyfin.Api/Helpers/DynamicHlsHelper.cs +++ b/Jellyfin.Api/Helpers/DynamicHlsHelper.cs @@ -40,14 +40,12 @@ namespace Jellyfin.Api.Helpers private readonly IMediaSourceManager _mediaSourceManager; private readonly IServerConfigurationManager _serverConfigurationManager; private readonly IMediaEncoder _mediaEncoder; - private readonly IFileSystem _fileSystem; - private readonly ISubtitleEncoder _subtitleEncoder; - private readonly IConfiguration _configuration; private readonly IDeviceManager _deviceManager; private readonly TranscodingJobHelper _transcodingJobHelper; private readonly INetworkManager _networkManager; private readonly ILogger<DynamicHlsHelper> _logger; private readonly IHttpContextAccessor _httpContextAccessor; + private readonly EncodingHelper _encodingHelper; /// <summary> /// Initializes a new instance of the <see cref="DynamicHlsHelper"/> class. @@ -59,14 +57,12 @@ namespace Jellyfin.Api.Helpers /// <param name="mediaSourceManager">Instance of the <see cref="IMediaSourceManager"/> interface.</param> /// <param name="serverConfigurationManager">Instance of the <see cref="IServerConfigurationManager"/> interface.</param> /// <param name="mediaEncoder">Instance of the <see cref="IMediaEncoder"/> interface.</param> - /// <param name="fileSystem">Instance of the <see cref="IFileSystem"/> interface.</param> - /// <param name="subtitleEncoder">Instance of the <see cref="ISubtitleEncoder"/> interface.</param> - /// <param name="configuration">Instance of the <see cref="IConfiguration"/> interface.</param> /// <param name="deviceManager">Instance of the <see cref="IDeviceManager"/> interface.</param> /// <param name="transcodingJobHelper">Instance of <see cref="TranscodingJobHelper"/>.</param> /// <param name="networkManager">Instance of the <see cref="INetworkManager"/> interface.</param> /// <param name="logger">Instance of the <see cref="ILogger{DynamicHlsHelper}"/> interface.</param> /// <param name="httpContextAccessor">Instance of the <see cref="IHttpContextAccessor"/> interface.</param> + /// <param name="encodingHelper">Instance of <see cref="EncodingHelper"/>.</param> public DynamicHlsHelper( ILibraryManager libraryManager, IUserManager userManager, @@ -75,14 +71,12 @@ namespace Jellyfin.Api.Helpers IMediaSourceManager mediaSourceManager, IServerConfigurationManager serverConfigurationManager, IMediaEncoder mediaEncoder, - IFileSystem fileSystem, - ISubtitleEncoder subtitleEncoder, - IConfiguration configuration, IDeviceManager deviceManager, TranscodingJobHelper transcodingJobHelper, INetworkManager networkManager, ILogger<DynamicHlsHelper> logger, - IHttpContextAccessor httpContextAccessor) + IHttpContextAccessor httpContextAccessor, + EncodingHelper encodingHelper) { _libraryManager = libraryManager; _userManager = userManager; @@ -91,14 +85,12 @@ namespace Jellyfin.Api.Helpers _mediaSourceManager = mediaSourceManager; _serverConfigurationManager = serverConfigurationManager; _mediaEncoder = mediaEncoder; - _fileSystem = fileSystem; - _subtitleEncoder = subtitleEncoder; - _configuration = configuration; _deviceManager = deviceManager; _transcodingJobHelper = transcodingJobHelper; _networkManager = networkManager; _logger = logger; _httpContextAccessor = httpContextAccessor; + _encodingHelper = encodingHelper; } /// <summary> @@ -144,9 +136,7 @@ namespace Jellyfin.Api.Helpers _libraryManager, _serverConfigurationManager, _mediaEncoder, - _fileSystem, - _subtitleEncoder, - _configuration, + _encodingHelper, _dlnaManager, _deviceManager, _transcodingJobHelper, @@ -227,9 +217,8 @@ namespace Jellyfin.Api.Helpers var sdrVideoUrl = ReplaceProfile(playlistUrl, "hevc", string.Join(',', requestedVideoProfiles), "main"); sdrVideoUrl += "&AllowVideoStreamCopy=false"; - EncodingHelper encodingHelper = new EncodingHelper(_mediaEncoder, _fileSystem, _subtitleEncoder, _configuration); - var sdrOutputVideoBitrate = encodingHelper.GetVideoBitrateParamValue(state.VideoRequest, state.VideoStream, state.OutputVideoCodec) ?? 0; - var sdrOutputAudioBitrate = encodingHelper.GetAudioBitrateParam(state.VideoRequest, state.AudioStream) ?? 0; + var sdrOutputVideoBitrate = _encodingHelper.GetVideoBitrateParamValue(state.VideoRequest, state.VideoStream, state.OutputVideoCodec) ?? 0; + var sdrOutputAudioBitrate = _encodingHelper.GetAudioBitrateParam(state.VideoRequest, state.AudioStream) ?? 0; var sdrTotalBitrate = sdrOutputAudioBitrate + sdrOutputVideoBitrate; AppendPlaylist(builder, state, sdrVideoUrl, sdrTotalBitrate, subtitleGroup); diff --git a/Jellyfin.Api/Helpers/StreamingHelpers.cs b/Jellyfin.Api/Helpers/StreamingHelpers.cs index e2306aa27..9218cb202 100644 --- a/Jellyfin.Api/Helpers/StreamingHelpers.cs +++ b/Jellyfin.Api/Helpers/StreamingHelpers.cs @@ -41,9 +41,7 @@ namespace Jellyfin.Api.Helpers /// <param name="libraryManager">Instance of the <see cref="ILibraryManager"/> interface.</param> /// <param name="serverConfigurationManager">Instance of the <see cref="IServerConfigurationManager"/> interface.</param> /// <param name="mediaEncoder">Instance of the <see cref="IMediaEncoder"/> interface.</param> - /// <param name="fileSystem">Instance of the <see cref="IFileSystem"/> interface.</param> - /// <param name="subtitleEncoder">Instance of the <see cref="ISubtitleEncoder"/> interface.</param> - /// <param name="configuration">Instance of the <see cref="IConfiguration"/> interface.</param> + /// <param name="encodingHelper">Instance of <see cref="EncodingHelper"/>.</param> /// <param name="dlnaManager">Instance of the <see cref="IDlnaManager"/> interface.</param> /// <param name="deviceManager">Instance of the <see cref="IDeviceManager"/> interface.</param> /// <param name="transcodingJobHelper">Initialized <see cref="TranscodingJobHelper"/>.</param> @@ -59,16 +57,13 @@ namespace Jellyfin.Api.Helpers ILibraryManager libraryManager, IServerConfigurationManager serverConfigurationManager, IMediaEncoder mediaEncoder, - IFileSystem fileSystem, - ISubtitleEncoder subtitleEncoder, - IConfiguration configuration, + EncodingHelper encodingHelper, IDlnaManager dlnaManager, IDeviceManager deviceManager, TranscodingJobHelper transcodingJobHelper, TranscodingJobType transcodingJobType, CancellationToken cancellationToken) { - EncodingHelper encodingHelper = new EncodingHelper(mediaEncoder, fileSystem, subtitleEncoder, configuration); // Parse the DLNA time seek header if (!streamingRequest.StartTimeTicks.HasValue) { @@ -306,7 +301,8 @@ namespace Jellyfin.Api.Helpers if (!state.IsVideoRequest) { - responseHeaders.Add("contentFeatures.dlna.org", new ContentFeatureBuilder(profile).BuildAudioHeader( + responseHeaders.Add("contentFeatures.dlna.org", ContentFeatureBuilder.BuildAudioHeader( + profile, state.OutputContainer, audioCodec, state.OutputAudioBitrate, @@ -323,7 +319,7 @@ namespace Jellyfin.Api.Helpers responseHeaders.Add( "contentFeatures.dlna.org", - new ContentFeatureBuilder(profile).BuildVideoHeader(state.OutputContainer, videoCodec, audioCodec, state.OutputWidth, state.OutputHeight, state.TargetVideoBitDepth, state.OutputVideoBitrate, state.TargetTimestamp, isStaticallyStreamed, state.RunTimeTicks, state.TargetVideoProfile, state.TargetVideoLevel, state.TargetFramerate, state.TargetPacketLength, state.TranscodeSeekInfo, state.IsTargetAnamorphic, state.IsTargetInterlaced, state.TargetRefFrames, state.TargetVideoStreamCount, state.TargetAudioStreamCount, state.TargetVideoCodecTag, state.IsTargetAVC).FirstOrDefault() ?? string.Empty); + ContentFeatureBuilder.BuildVideoHeader(profile, state.OutputContainer, videoCodec, audioCodec, state.OutputWidth, state.OutputHeight, state.TargetVideoBitDepth, state.OutputVideoBitrate, state.TargetTimestamp, isStaticallyStreamed, state.RunTimeTicks, state.TargetVideoProfile, state.TargetVideoLevel, state.TargetFramerate, state.TargetPacketLength, state.TranscodeSeekInfo, state.IsTargetAnamorphic, state.IsTargetInterlaced, state.TargetRefFrames, state.TargetVideoStreamCount, state.TargetAudioStreamCount, state.TargetVideoCodecTag, state.IsTargetAVC).FirstOrDefault() ?? string.Empty); } } diff --git a/Jellyfin.Api/Helpers/TranscodingJobHelper.cs b/Jellyfin.Api/Helpers/TranscodingJobHelper.cs index 240d132b1..0879cbd18 100644 --- a/Jellyfin.Api/Helpers/TranscodingJobHelper.cs +++ b/Jellyfin.Api/Helpers/TranscodingJobHelper.cs @@ -62,8 +62,7 @@ namespace Jellyfin.Api.Helpers /// <param name="serverConfigurationManager">Instance of the <see cref="IServerConfigurationManager"/> interface.</param> /// <param name="sessionManager">Instance of the <see cref="ISessionManager"/> interface.</param> /// <param name="authorizationContext">Instance of the <see cref="IAuthorizationContext"/> interface.</param> - /// <param name="subtitleEncoder">Instance of the <see cref="ISubtitleEncoder"/> interface.</param> - /// <param name="configuration">Instance of the <see cref="IConfiguration"/> interface.</param> + /// <param name="encodingHelper">Instance of <see cref="EncodingHelper"/>.</param> /// <param name="loggerFactory">Instance of the <see cref="ILoggerFactory"/> interface.</param> public TranscodingJobHelper( ILogger<TranscodingJobHelper> logger, @@ -73,8 +72,7 @@ namespace Jellyfin.Api.Helpers IServerConfigurationManager serverConfigurationManager, ISessionManager sessionManager, IAuthorizationContext authorizationContext, - ISubtitleEncoder subtitleEncoder, - IConfiguration configuration, + EncodingHelper encodingHelper, ILoggerFactory loggerFactory) { _logger = logger; @@ -84,8 +82,8 @@ namespace Jellyfin.Api.Helpers _serverConfigurationManager = serverConfigurationManager; _sessionManager = sessionManager; _authorizationContext = authorizationContext; + _encodingHelper = encodingHelper; _loggerFactory = loggerFactory; - _encodingHelper = new EncodingHelper(mediaEncoder, fileSystem, subtitleEncoder, configuration); DeleteEncodedMediaCache(); diff --git a/Jellyfin.Api/Models/UserDtos/AuthenticateUserByName.cs b/Jellyfin.Api/Models/UserDtos/AuthenticateUserByName.cs index 393627435..41f7b169e 100644 --- a/Jellyfin.Api/Models/UserDtos/AuthenticateUserByName.cs +++ b/Jellyfin.Api/Models/UserDtos/AuthenticateUserByName.cs @@ -1,4 +1,6 @@ -namespace Jellyfin.Api.Models.UserDtos +using System; + +namespace Jellyfin.Api.Models.UserDtos { /// <summary> /// The authenticate user by name request body. @@ -18,6 +20,7 @@ /// <summary> /// Gets or sets the sha1-hashed password. /// </summary> + [Obsolete("Send password using pw field")] public string? Password { get; set; } } } diff --git a/Jellyfin.Server/Startup.cs b/Jellyfin.Server/Startup.cs index e56e61092..f75139884 100644 --- a/Jellyfin.Server/Startup.cs +++ b/Jellyfin.Server/Startup.cs @@ -1,5 +1,9 @@ +using System; +using System.Net; +using System.Net.Http; using System.Net.Http.Headers; using System.Net.Mime; +using System.Text; using Jellyfin.Networking.Configuration; using Jellyfin.Server.Extensions; using Jellyfin.Server.Implementations; @@ -67,6 +71,12 @@ namespace Jellyfin.Server var acceptJsonHeader = new MediaTypeWithQualityHeaderValue(MediaTypeNames.Application.Json, 1.0); var acceptXmlHeader = new MediaTypeWithQualityHeaderValue(MediaTypeNames.Application.Xml, 0.9); var acceptAnyHeader = new MediaTypeWithQualityHeaderValue("*/*", 0.8); + Func<IServiceProvider, HttpMessageHandler> defaultHttpClientHandlerDelegate = (_) => new SocketsHttpHandler() + { + AutomaticDecompression = DecompressionMethods.All, + RequestHeaderEncodingSelector = (_, _) => Encoding.UTF8 + }; + services .AddHttpClient(NamedClient.Default, c => { @@ -75,7 +85,7 @@ namespace Jellyfin.Server c.DefaultRequestHeaders.Accept.Add(acceptXmlHeader); c.DefaultRequestHeaders.Accept.Add(acceptAnyHeader); }) - .ConfigurePrimaryHttpMessageHandler(x => new DefaultHttpClientHandler()); + .ConfigurePrimaryHttpMessageHandler(defaultHttpClientHandlerDelegate); services.AddHttpClient(NamedClient.MusicBrainz, c => { @@ -84,7 +94,7 @@ namespace Jellyfin.Server c.DefaultRequestHeaders.Accept.Add(acceptXmlHeader); c.DefaultRequestHeaders.Accept.Add(acceptAnyHeader); }) - .ConfigurePrimaryHttpMessageHandler(x => new DefaultHttpClientHandler()); + .ConfigurePrimaryHttpMessageHandler(defaultHttpClientHandlerDelegate); services.AddHealthChecks() .AddDbContextCheck<JellyfinDb>(); diff --git a/MediaBrowser.Common/Net/DefaultHttpClientHandler.cs b/MediaBrowser.Common/Net/DefaultHttpClientHandler.cs deleted file mode 100644 index f1c5f2477..000000000 --- a/MediaBrowser.Common/Net/DefaultHttpClientHandler.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System.Net; -using System.Net.Http; - -namespace MediaBrowser.Common.Net -{ - /// <summary> - /// Default http client handler. - /// </summary> - public class DefaultHttpClientHandler : HttpClientHandler - { - /// <summary> - /// Initializes a new instance of the <see cref="DefaultHttpClientHandler"/> class. - /// </summary> - public DefaultHttpClientHandler() - { - AutomaticDecompression = DecompressionMethods.All; - } - } -} diff --git a/MediaBrowser.Controller/Entities/BaseItemExtensions.cs b/MediaBrowser.Controller/Entities/BaseItemExtensions.cs index c65477d39..157ed8332 100644 --- a/MediaBrowser.Controller/Entities/BaseItemExtensions.cs +++ b/MediaBrowser.Controller/Entities/BaseItemExtensions.cs @@ -1,5 +1,7 @@ +#nullable enable #pragma warning disable CS1591 +using System; using System.Linq; using MediaBrowser.Model.Entities; using MediaBrowser.Model.IO; @@ -64,9 +66,19 @@ namespace MediaBrowser.Controller.Entities /// <param name="source">The source object.</param> /// <param name="dest">The destination object.</param> public static void DeepCopy<T, TU>(this T source, TU dest) - where T : BaseItem - where TU : BaseItem + where T : BaseItem + where TU : BaseItem { + if (source == null) + { + throw new ArgumentNullException(nameof(source)); + } + + if (dest == null) + { + throw new ArgumentNullException(nameof(dest)); + } + var destProps = typeof(TU).GetProperties().Where(x => x.CanWrite).ToList(); foreach (var sourceProp in typeof(T).GetProperties()) @@ -99,8 +111,8 @@ namespace MediaBrowser.Controller.Entities /// </summary> /// <param name="source">The source object.</param> public static TU DeepCopy<T, TU>(this T source) - where T : BaseItem - where TU : BaseItem, new() + where T : BaseItem + where TU : BaseItem, new() { var dest = new TU(); source.DeepCopy(dest); diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index bdca5c0ee..d45f8758c 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -1433,9 +1433,14 @@ namespace MediaBrowser.Controller.Entities var linkedChildren = LinkedChildren; foreach (var i in linkedChildren) { - if (i.ItemId.HasValue && i.ItemId.Value == itemId) + if (i.ItemId.HasValue) { - return true; + if (i.ItemId.Value == itemId) + { + return true; + } + + continue; } var child = GetLinkedChild(i); diff --git a/MediaBrowser.Controller/Entities/TV/Episode.cs b/MediaBrowser.Controller/Entities/TV/Episode.cs index dc12fbbea..70663ef47 100644 --- a/MediaBrowser.Controller/Entities/TV/Episode.cs +++ b/MediaBrowser.Controller/Entities/TV/Episode.cs @@ -99,7 +99,15 @@ namespace MediaBrowser.Controller.Entities.TV take--; } - list.InsertRange(0, seriesUserDataKeys.Take(take).Select(i => i + ParentIndexNumber.Value.ToString("000") + IndexNumber.Value.ToString("000"))); + var newList = seriesUserDataKeys.GetRange(0, take); + var suffix = ParentIndexNumber.Value.ToString("000", CultureInfo.InvariantCulture) + IndexNumber.Value.ToString("000", CultureInfo.InvariantCulture); + for (int i = 0; i < take; i++) + { + newList[i] = newList[i] + suffix; + } + + newList.AddRange(list); + list = newList; } return list; diff --git a/MediaBrowser.Controller/Entities/TV/Season.cs b/MediaBrowser.Controller/Entities/TV/Season.cs index 93bdd6e70..5b8168d3d 100644 --- a/MediaBrowser.Controller/Entities/TV/Season.cs +++ b/MediaBrowser.Controller/Entities/TV/Season.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using System.Text.Json.Serialization; using Jellyfin.Data.Entities; @@ -56,7 +57,15 @@ namespace MediaBrowser.Controller.Entities.TV var series = Series; if (series != null) { - list.InsertRange(0, series.GetUserDataKeys().Select(i => i + (IndexNumber ?? 0).ToString("000"))); + var newList = series.GetUserDataKeys(); + var suffix = (IndexNumber ?? 0).ToString("000", CultureInfo.InvariantCulture); + for (int i = 0; i < newList.Count; i++) + { + newList[i] = newList[i] + suffix; + } + + newList.AddRange(list); + list = newList; } return list; diff --git a/MediaBrowser.Controller/Entities/TV/Series.cs b/MediaBrowser.Controller/Entities/TV/Series.cs index a410c1b66..9f9a2ad50 100644 --- a/MediaBrowser.Controller/Entities/TV/Series.cs +++ b/MediaBrowser.Controller/Entities/TV/Series.cs @@ -169,14 +169,12 @@ namespace MediaBrowser.Controller.Entities.TV { var list = base.GetUserDataKeys(); - var key = this.GetProviderId(MetadataProvider.Imdb); - if (!string.IsNullOrEmpty(key)) + if (this.TryGetProviderId(MetadataProvider.Imdb, out var key)) { list.Insert(0, key); } - key = this.GetProviderId(MetadataProvider.Tvdb); - if (!string.IsNullOrEmpty(key)) + if (this.TryGetProviderId(MetadataProvider.Tvdb, out key)) { list.Insert(0, key); } @@ -208,7 +206,7 @@ namespace MediaBrowser.Controller.Entities.TV query.AncestorWithPresentationUniqueKey = null; query.SeriesPresentationUniqueKey = seriesKey; query.IncludeItemTypes = new[] { nameof(Season) }; - query.OrderBy = new[] { ItemSortBy.SortName }.Select(i => new ValueTuple<string, SortOrder>(i, SortOrder.Ascending)).ToArray(); + query.OrderBy = new[] { (ItemSortBy.SortName, SortOrder.Ascending) }; if (user != null && !user.DisplayMissingEpisodes) { @@ -228,7 +226,7 @@ namespace MediaBrowser.Controller.Entities.TV query.SeriesPresentationUniqueKey = seriesKey; if (query.OrderBy.Count == 0) { - query.OrderBy = new[] { ItemSortBy.SortName }.Select(i => new ValueTuple<string, SortOrder>(i, SortOrder.Ascending)).ToArray(); + query.OrderBy = new[] { (ItemSortBy.SortName, SortOrder.Ascending) }; } if (query.IncludeItemTypes.Length == 0) @@ -254,7 +252,7 @@ namespace MediaBrowser.Controller.Entities.TV AncestorWithPresentationUniqueKey = null, SeriesPresentationUniqueKey = seriesKey, IncludeItemTypes = new[] { nameof(Episode), nameof(Season) }, - OrderBy = new[] { ItemSortBy.SortName }.Select(i => new ValueTuple<string, SortOrder>(i, SortOrder.Ascending)).ToArray(), + OrderBy = new[] { (ItemSortBy.SortName, SortOrder.Ascending) }, DtoOptions = options }; @@ -365,7 +363,7 @@ namespace MediaBrowser.Controller.Entities.TV AncestorWithPresentationUniqueKey = queryFromSeries ? null : seriesKey, SeriesPresentationUniqueKey = queryFromSeries ? seriesKey : null, IncludeItemTypes = new[] { nameof(Episode) }, - OrderBy = new[] { ItemSortBy.SortName }.Select(i => new ValueTuple<string, SortOrder>(i, SortOrder.Ascending)).ToArray(), + OrderBy = new[] { (ItemSortBy.SortName, SortOrder.Ascending) }, DtoOptions = options }; if (user != null) diff --git a/MediaBrowser.Controller/Entities/UserViewBuilder.cs b/MediaBrowser.Controller/Entities/UserViewBuilder.cs index 4e33a6bbd..78a64d8c9 100644 --- a/MediaBrowser.Controller/Entities/UserViewBuilder.cs +++ b/MediaBrowser.Controller/Entities/UserViewBuilder.cs @@ -217,8 +217,7 @@ namespace MediaBrowser.Controller.Entities private QueryResult<BaseItem> GetMovieLatest(Folder parent, User user, InternalItemsQuery query) { - query.OrderBy = new[] { ItemSortBy.DateCreated, ItemSortBy.SortName }.Select(i => new ValueTuple<string, SortOrder>(i, SortOrder.Descending)).ToArray(); - + query.OrderBy = new[] { (ItemSortBy.DateCreated, SortOrder.Descending), (ItemSortBy.SortName, SortOrder.Descending) }; query.Recursive = true; query.Parent = parent; query.SetUser(user); @@ -230,7 +229,7 @@ namespace MediaBrowser.Controller.Entities private QueryResult<BaseItem> GetMovieResume(Folder parent, User user, InternalItemsQuery query) { - query.OrderBy = new[] { ItemSortBy.DatePlayed, ItemSortBy.SortName }.Select(i => new ValueTuple<string, SortOrder>(i, SortOrder.Descending)).ToArray(); + query.OrderBy = new[] { (ItemSortBy.DatePlayed, SortOrder.Descending), (ItemSortBy.SortName, SortOrder.Descending) }; query.IsResumable = true; query.Recursive = true; query.Parent = parent; @@ -327,8 +326,7 @@ namespace MediaBrowser.Controller.Entities private QueryResult<BaseItem> GetTvLatest(Folder parent, User user, InternalItemsQuery query) { - query.OrderBy = new[] { ItemSortBy.DateCreated, ItemSortBy.SortName }.Select(i => new ValueTuple<string, SortOrder>(i, SortOrder.Descending)).ToArray(); - + query.OrderBy = new[] { (ItemSortBy.DateCreated, SortOrder.Descending), (ItemSortBy.SortName, SortOrder.Descending) }; query.Recursive = true; query.Parent = parent; query.SetUser(user); @@ -356,7 +354,7 @@ namespace MediaBrowser.Controller.Entities private QueryResult<BaseItem> GetTvResume(Folder parent, User user, InternalItemsQuery query) { - query.OrderBy = new[] { ItemSortBy.DatePlayed, ItemSortBy.SortName }.Select(i => new ValueTuple<string, SortOrder>(i, SortOrder.Descending)).ToArray(); + query.OrderBy = new[] { (ItemSortBy.DatePlayed, SortOrder.Descending), (ItemSortBy.SortName, SortOrder.Descending) }; query.IsResumable = true; query.Recursive = true; query.Parent = parent; diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 1379efacb..2b5364775 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -25,9 +25,7 @@ namespace MediaBrowser.Controller.MediaEncoding private static readonly CultureInfo _usCulture = new CultureInfo("en-US"); private readonly IMediaEncoder _mediaEncoder; - private readonly IFileSystem _fileSystem; private readonly ISubtitleEncoder _subtitleEncoder; - private readonly IConfiguration _configuration; private static readonly string[] _videoProfiles = new[] { @@ -42,14 +40,10 @@ namespace MediaBrowser.Controller.MediaEncoding public EncodingHelper( IMediaEncoder mediaEncoder, - IFileSystem fileSystem, - ISubtitleEncoder subtitleEncoder, - IConfiguration configuration) + ISubtitleEncoder subtitleEncoder) { _mediaEncoder = mediaEncoder; - _fileSystem = fileSystem; _subtitleEncoder = subtitleEncoder; - _configuration = configuration; } public string GetH264Encoder(EncodingJobInfo state, EncodingOptions encodingOptions) diff --git a/MediaBrowser.Controller/Playlists/Playlist.cs b/MediaBrowser.Controller/Playlists/Playlist.cs index a5b7363fb..c9c168c4c 100644 --- a/MediaBrowser.Controller/Playlists/Playlist.cs +++ b/MediaBrowser.Controller/Playlists/Playlist.cs @@ -163,7 +163,7 @@ namespace MediaBrowser.Controller.Playlists Recursive = true, IncludeItemTypes = new[] { nameof(Audio) }, GenreIds = new[] { musicGenre.Id }, - OrderBy = new[] { ItemSortBy.AlbumArtist, ItemSortBy.Album, ItemSortBy.SortName }.Select(i => new ValueTuple<string, SortOrder>(i, SortOrder.Ascending)).ToArray(), + OrderBy = new[] { (ItemSortBy.AlbumArtist, SortOrder.Ascending), (ItemSortBy.Album, SortOrder.Ascending), (ItemSortBy.SortName, SortOrder.Ascending) }, DtoOptions = options }); } @@ -175,7 +175,7 @@ namespace MediaBrowser.Controller.Playlists Recursive = true, IncludeItemTypes = new[] { nameof(Audio) }, ArtistIds = new[] { musicArtist.Id }, - OrderBy = new[] { ItemSortBy.AlbumArtist, ItemSortBy.Album, ItemSortBy.SortName }.Select(i => new ValueTuple<string, SortOrder>(i, SortOrder.Ascending)).ToArray(), + OrderBy = new[] { (ItemSortBy.AlbumArtist, SortOrder.Ascending), (ItemSortBy.Album, SortOrder.Ascending), (ItemSortBy.SortName, SortOrder.Ascending) }, DtoOptions = options }); } diff --git a/MediaBrowser.Controller/Session/AuthenticationRequest.cs b/MediaBrowser.Controller/Session/AuthenticationRequest.cs index cc321fd22..8c3ac58f2 100644 --- a/MediaBrowser.Controller/Session/AuthenticationRequest.cs +++ b/MediaBrowser.Controller/Session/AuthenticationRequest.cs @@ -12,6 +12,7 @@ namespace MediaBrowser.Controller.Session public string Password { get; set; } + [Obsolete("Send full password in Password field")] public string PasswordSha1 { get; set; } public string App { get; set; } diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index 36bf77c84..62c0c0bb1 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -52,7 +52,6 @@ namespace MediaBrowser.MediaEncoding.Encoder private readonly IServerConfigurationManager _configurationManager; private readonly IFileSystem _fileSystem; private readonly ILocalizationManager _localization; - private readonly Lazy<EncodingHelper> _encodingHelperFactory; private readonly string _startupOptionFFmpegPath; private readonly SemaphoreSlim _thumbnailResourcePool = new SemaphoreSlim(2, 2); @@ -76,14 +75,12 @@ namespace MediaBrowser.MediaEncoding.Encoder IServerConfigurationManager configurationManager, IFileSystem fileSystem, ILocalizationManager localization, - Lazy<EncodingHelper> encodingHelperFactory, IConfiguration config) { _logger = logger; _configurationManager = configurationManager; _fileSystem = fileSystem; _localization = localization; - _encodingHelperFactory = encodingHelperFactory; _startupOptionFFmpegPath = config.GetValue<string>(Controller.Extensions.ConfigurationExtensions.FfmpegPathKey) ?? string.Empty; _jsonSerializerOptions = JsonDefaults.Options; } diff --git a/MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs b/MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs index ec106f105..600a44157 100644 --- a/MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs +++ b/MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs @@ -10,14 +10,8 @@ namespace MediaBrowser.Model.Dlna { public class ContentFeatureBuilder { - private readonly DeviceProfile _profile; - - public ContentFeatureBuilder(DeviceProfile profile) - { - _profile = profile; - } - - public string BuildImageHeader( + public static string BuildImageHeader( + DeviceProfile profile, string container, int? width, int? height, @@ -38,27 +32,31 @@ namespace MediaBrowser.Model.Dlna ";DLNA.ORG_FLAGS={0}", DlnaMaps.FlagsToString(flagValue)); - ResponseProfile mediaProfile = _profile.GetImageMediaProfile( - container, - width, - height); - if (string.IsNullOrEmpty(orgPn)) { + ResponseProfile mediaProfile = profile.GetImageMediaProfile( + container, + width, + height); + orgPn = mediaProfile?.OrgPn; + + if (string.IsNullOrEmpty(orgPn)) + { + orgPn = GetImageOrgPnValue(container, width, height); + } } if (string.IsNullOrEmpty(orgPn)) { - orgPn = GetImageOrgPnValue(container, width, height); + return orgOp.TrimStart(';') + orgCi + dlnaflags; } - string contentFeatures = string.IsNullOrEmpty(orgPn) ? string.Empty : "DLNA.ORG_PN=" + orgPn; - - return (contentFeatures + orgOp + orgCi + dlnaflags).Trim(';'); + return "DLNA.ORG_PN=" + orgPn + orgOp + orgCi + dlnaflags; } - public string BuildAudioHeader( + public static string BuildAudioHeader( + DeviceProfile profile, string container, string audioCodec, int? audioBitrate, @@ -94,7 +92,7 @@ namespace MediaBrowser.Model.Dlna ";DLNA.ORG_FLAGS={0}", DlnaMaps.FlagsToString(flagValue)); - ResponseProfile mediaProfile = _profile.GetAudioMediaProfile( + ResponseProfile mediaProfile = profile.GetAudioMediaProfile( container, audioCodec, audioChannels, @@ -109,12 +107,16 @@ namespace MediaBrowser.Model.Dlna orgPn = GetAudioOrgPnValue(container, audioBitrate, audioSampleRate, audioChannels); } - string contentFeatures = string.IsNullOrEmpty(orgPn) ? string.Empty : "DLNA.ORG_PN=" + orgPn; + if (string.IsNullOrEmpty(orgPn)) + { + return orgOp.TrimStart(';') + orgCi + dlnaflags; + } - return (contentFeatures + orgOp + orgCi + dlnaflags).Trim(';'); + return "DLNA.ORG_PN=" + orgPn + orgOp + orgCi + dlnaflags; } - public List<string> BuildVideoHeader( + public static List<string> BuildVideoHeader( + DeviceProfile profile, string container, string videoCodec, string audioCodec, @@ -163,7 +165,7 @@ namespace MediaBrowser.Model.Dlna ";DLNA.ORG_FLAGS={0}", DlnaMaps.FlagsToString(flagValue)); - ResponseProfile mediaProfile = _profile.GetVideoMediaProfile( + ResponseProfile mediaProfile = profile.GetVideoMediaProfile( container, audioCodec, videoCodec, @@ -192,9 +194,9 @@ namespace MediaBrowser.Model.Dlna } else { - foreach (string s in GetVideoOrgPnValue(container, videoCodec, audioCodec, width, height, timestamp)) + foreach (var s in GetVideoOrgPnValue(container, videoCodec, audioCodec, width, height, timestamp)) { - orgPnValues.Add(s); + orgPnValues.Add(s.ToString()); break; } } @@ -203,20 +205,20 @@ namespace MediaBrowser.Model.Dlna foreach (string orgPn in orgPnValues) { - string contentFeatures = string.IsNullOrEmpty(orgPn) ? string.Empty : "DLNA.ORG_PN=" + orgPn; - - var value = (contentFeatures + orgOp + orgCi + dlnaflags).Trim(';'); - - contentFeatureList.Add(value); + if (string.IsNullOrEmpty(orgPn)) + { + contentFeatureList.Add(orgOp.TrimStart(';') + orgCi + dlnaflags); + continue; + } + else + { + contentFeatureList.Add("DLNA.ORG_PN=" + orgPn + orgCi + dlnaflags); + } } if (orgPnValues.Count == 0) { - string contentFeatures = string.Empty; - - var value = (contentFeatures + orgOp + orgCi + dlnaflags).Trim(';'); - - contentFeatureList.Add(value); + contentFeatureList.Add(orgOp.TrimStart(';') + orgCi + dlnaflags); } return contentFeatureList; @@ -224,19 +226,14 @@ namespace MediaBrowser.Model.Dlna private static string GetImageOrgPnValue(string container, int? width, int? height) { - MediaFormatProfile? format = new MediaFormatProfileResolver() - .ResolveImageFormat( - container, - width, - height); + MediaFormatProfile? format = MediaFormatProfileResolver.ResolveImageFormat(container, width, height); return format.HasValue ? format.Value.ToString() : null; } private static string GetAudioOrgPnValue(string container, int? audioBitrate, int? audioSampleRate, int? audioChannels) { - MediaFormatProfile? format = new MediaFormatProfileResolver() - .ResolveAudioFormat( + MediaFormatProfile? format = MediaFormatProfileResolver.ResolveAudioFormat( container, audioBitrate, audioSampleRate, @@ -245,9 +242,9 @@ namespace MediaBrowser.Model.Dlna return format.HasValue ? format.Value.ToString() : null; } - private static string[] GetVideoOrgPnValue(string container, string videoCodec, string audioCodec, int? width, int? height, TransportStreamTimestamp timestamp) + private static MediaFormatProfile[] GetVideoOrgPnValue(string container, string videoCodec, string audioCodec, int? width, int? height, TransportStreamTimestamp timestamp) { - return new MediaFormatProfileResolver().ResolveVideoFormat(container, videoCodec, audioCodec, width, height, timestamp); + return MediaFormatProfileResolver.ResolveVideoFormat(container, videoCodec, audioCodec, width, height, timestamp); } } } diff --git a/MediaBrowser.Model/Dlna/MediaFormatProfileResolver.cs b/MediaBrowser.Model/Dlna/MediaFormatProfileResolver.cs index f61b8d59e..7ce248509 100644 --- a/MediaBrowser.Model/Dlna/MediaFormatProfileResolver.cs +++ b/MediaBrowser.Model/Dlna/MediaFormatProfileResolver.cs @@ -9,16 +9,9 @@ using MediaBrowser.Model.MediaInfo; namespace MediaBrowser.Model.Dlna { - public class MediaFormatProfileResolver + public static class MediaFormatProfileResolver { - public string[] ResolveVideoFormat(string container, string videoCodec, string audioCodec, int? width, int? height, TransportStreamTimestamp timestampType) - { - return ResolveVideoFormatInternal(container, videoCodec, audioCodec, width, height, timestampType) - .Select(i => i.ToString()) - .ToArray(); - } - - private MediaFormatProfile[] ResolveVideoFormatInternal(string container, string videoCodec, string audioCodec, int? width, int? height, TransportStreamTimestamp timestampType) + public static MediaFormatProfile[] ResolveVideoFormat(string container, string videoCodec, string audioCodec, int? width, int? height, TransportStreamTimestamp timestampType) { if (string.Equals(container, "asf", StringComparison.OrdinalIgnoreCase)) { @@ -84,7 +77,7 @@ namespace MediaBrowser.Model.Dlna return Array.Empty<MediaFormatProfile>(); } - private MediaFormatProfile[] ResolveVideoMPEG2TSFormat(string videoCodec, string audioCodec, int? width, int? height, TransportStreamTimestamp timestampType) + private static MediaFormatProfile[] ResolveVideoMPEG2TSFormat(string videoCodec, string audioCodec, int? width, int? height, TransportStreamTimestamp timestampType) { string suffix = string.Empty; @@ -209,12 +202,12 @@ namespace MediaBrowser.Model.Dlna return Array.Empty<MediaFormatProfile>(); } - private MediaFormatProfile ValueOf(string value) + private static MediaFormatProfile ValueOf(string value) { return (MediaFormatProfile)Enum.Parse(typeof(MediaFormatProfile), value, true); } - private MediaFormatProfile? ResolveVideoMP4Format(string videoCodec, string audioCodec, int? width, int? height) + private static MediaFormatProfile? ResolveVideoMP4Format(string videoCodec, string audioCodec, int? width, int? height) { if (string.Equals(videoCodec, "h264", StringComparison.OrdinalIgnoreCase)) { @@ -287,7 +280,7 @@ namespace MediaBrowser.Model.Dlna return null; } - private MediaFormatProfile? ResolveVideo3GPFormat(string videoCodec, string audioCodec) + private static MediaFormatProfile? ResolveVideo3GPFormat(string videoCodec, string audioCodec) { if (string.Equals(videoCodec, "h264", StringComparison.OrdinalIgnoreCase)) { @@ -317,7 +310,7 @@ namespace MediaBrowser.Model.Dlna return null; } - private MediaFormatProfile? ResolveVideoASFFormat(string videoCodec, string audioCodec, int? width, int? height) + private static MediaFormatProfile? ResolveVideoASFFormat(string videoCodec, string audioCodec, int? width, int? height) { if (string.Equals(videoCodec, "wmv", StringComparison.OrdinalIgnoreCase) && (string.IsNullOrEmpty(audioCodec) || string.Equals(audioCodec, "wma", StringComparison.OrdinalIgnoreCase) || string.Equals(videoCodec, "wmapro", StringComparison.OrdinalIgnoreCase))) @@ -371,7 +364,7 @@ namespace MediaBrowser.Model.Dlna return null; } - public MediaFormatProfile? ResolveAudioFormat(string container, int? bitrate, int? frequency, int? channels) + public static MediaFormatProfile? ResolveAudioFormat(string container, int? bitrate, int? frequency, int? channels) { if (string.Equals(container, "asf", StringComparison.OrdinalIgnoreCase)) { @@ -413,7 +406,7 @@ namespace MediaBrowser.Model.Dlna return null; } - private MediaFormatProfile ResolveAudioASFFormat(int? bitrate) + private static MediaFormatProfile ResolveAudioASFFormat(int? bitrate) { if (bitrate.HasValue && bitrate.Value <= 193) { @@ -423,7 +416,7 @@ namespace MediaBrowser.Model.Dlna return MediaFormatProfile.WMA_FULL; } - private MediaFormatProfile? ResolveAudioLPCMFormat(int? frequency, int? channels) + private static MediaFormatProfile? ResolveAudioLPCMFormat(int? frequency, int? channels) { if (frequency.HasValue && channels.HasValue) { @@ -453,7 +446,7 @@ namespace MediaBrowser.Model.Dlna return MediaFormatProfile.LPCM16_48_STEREO; } - private MediaFormatProfile ResolveAudioMP4Format(int? bitrate) + private static MediaFormatProfile ResolveAudioMP4Format(int? bitrate) { if (bitrate.HasValue && bitrate.Value <= 320) { @@ -463,7 +456,7 @@ namespace MediaBrowser.Model.Dlna return MediaFormatProfile.AAC_ISO; } - private MediaFormatProfile ResolveAudioADTSFormat(int? bitrate) + private static MediaFormatProfile ResolveAudioADTSFormat(int? bitrate) { if (bitrate.HasValue && bitrate.Value <= 320) { @@ -473,7 +466,7 @@ namespace MediaBrowser.Model.Dlna return MediaFormatProfile.AAC_ADTS; } - public MediaFormatProfile? ResolveImageFormat(string container, int? width, int? height) + public static MediaFormatProfile? ResolveImageFormat(string container, int? width, int? height) { if (string.Equals(container, "jpeg", StringComparison.OrdinalIgnoreCase) || string.Equals(container, "jpg", StringComparison.OrdinalIgnoreCase)) @@ -499,7 +492,7 @@ namespace MediaBrowser.Model.Dlna return null; } - private MediaFormatProfile ResolveImageJPGFormat(int? width, int? height) + private static MediaFormatProfile ResolveImageJPGFormat(int? width, int? height) { if (width.HasValue && height.HasValue) { @@ -524,7 +517,7 @@ namespace MediaBrowser.Model.Dlna return MediaFormatProfile.JPEG_SM; } - private MediaFormatProfile ResolveImagePNGFormat(int? width, int? height) + private static MediaFormatProfile ResolveImagePNGFormat(int? width, int? height) { if (width.HasValue && height.HasValue) { diff --git a/MediaBrowser.Providers/Manager/ProviderManager.cs b/MediaBrowser.Providers/Manager/ProviderManager.cs index 3bb2c6f0b..08c92e15a 100644 --- a/MediaBrowser.Providers/Manager/ProviderManager.cs +++ b/MediaBrowser.Providers/Manager/ProviderManager.cs @@ -1021,26 +1021,26 @@ namespace MediaBrowser.Providers.Manager // TODO: Need to hunt down the conditions for this happening _activeRefreshes.AddOrUpdate( id, - (_) => throw new Exception( + (_) => throw new InvalidOperationException( string.Format( CultureInfo.InvariantCulture, "Cannot update refresh progress of item '{0}' ({1}) because a refresh for this item is not running", item.GetType().Name, item.Id.ToString("N", CultureInfo.InvariantCulture))), - (_, __) => progress); + (_, _) => progress); RefreshProgress?.Invoke(this, new GenericEventArgs<Tuple<BaseItem, double>>(new Tuple<BaseItem, double>(item, progress))); } /// <inheritdoc/> - public void QueueRefresh(Guid id, MetadataRefreshOptions options, RefreshPriority priority) + public void QueueRefresh(Guid itemId, MetadataRefreshOptions options, RefreshPriority priority) { if (_disposed) { return; } - _refreshQueue.Enqueue(new Tuple<Guid, MetadataRefreshOptions>(id, options), (int)priority); + _refreshQueue.Enqueue(new Tuple<Guid, MetadataRefreshOptions>(itemId, options), (int)priority); lock (_refreshQueueLock) { @@ -1073,17 +1073,16 @@ namespace MediaBrowser.Providers.Manager try { var item = libraryManager.GetItemById(refreshItem.Item1); - if (item != null) + if (item == null) { - // Try to throttle this a little bit. - await Task.Delay(100, cancellationToken).ConfigureAwait(false); + continue; + } - var task = item is MusicArtist artist - ? RefreshArtist(artist, refreshItem.Item2, cancellationToken) - : RefreshItem(item, refreshItem.Item2, cancellationToken); + var task = item is MusicArtist artist + ? RefreshArtist(artist, refreshItem.Item2, cancellationToken) + : RefreshItem(item, refreshItem.Item2, cancellationToken); - await task.ConfigureAwait(false); - } + await task.ConfigureAwait(false); } catch (OperationCanceledException) { diff --git a/MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonImageProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonImageProvider.cs index 3f57c4bc4..bf42ceade 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonImageProvider.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonImageProvider.cs @@ -49,37 +49,36 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.People public async Task<IEnumerable<RemoteImageInfo>> GetImages(BaseItem item, CancellationToken cancellationToken) { var person = (Person)item; - var personTmdbId = Convert.ToInt32(person.GetProviderId(MetadataProvider.Tmdb), CultureInfo.InvariantCulture); - if (personTmdbId > 0) + if (!person.TryGetProviderId(MetadataProvider.Tmdb, out var personTmdbId)) { - var personResult = await _tmdbClientManager.GetPersonAsync(personTmdbId, cancellationToken).ConfigureAwait(false); - if (personResult?.Images?.Profiles == null) - { - return Enumerable.Empty<RemoteImageInfo>(); - } + return Enumerable.Empty<RemoteImageInfo>(); + } - var remoteImages = new List<RemoteImageInfo>(); - var language = item.GetPreferredMetadataLanguage(); + var personResult = await _tmdbClientManager.GetPersonAsync(int.Parse(personTmdbId, CultureInfo.InvariantCulture), cancellationToken).ConfigureAwait(false); + if (personResult?.Images?.Profiles == null) + { + return Enumerable.Empty<RemoteImageInfo>(); + } - for (var i = 0; i < personResult.Images.Profiles.Count; i++) - { - var image = personResult.Images.Profiles[i]; - remoteImages.Add(new RemoteImageInfo - { - ProviderName = Name, - Type = ImageType.Primary, - Width = image.Width, - Height = image.Height, - Language = TmdbUtils.AdjustImageLanguage(image.Iso_639_1, language), - Url = _tmdbClientManager.GetProfileUrl(image.FilePath) - }); - } + var remoteImages = new RemoteImageInfo[personResult.Images.Profiles.Count]; + var language = item.GetPreferredMetadataLanguage(); - return remoteImages.OrderByLanguageDescending(language); + for (var i = 0; i < personResult.Images.Profiles.Count; i++) + { + var image = personResult.Images.Profiles[i]; + remoteImages[i] = new RemoteImageInfo + { + ProviderName = Name, + Type = ImageType.Primary, + Width = image.Width, + Height = image.Height, + Language = TmdbUtils.AdjustImageLanguage(image.Iso_639_1, language), + Url = _tmdbClientManager.GetProfileUrl(image.FilePath) + }; } - return Enumerable.Empty<RemoteImageInfo>(); + return remoteImages.OrderByLanguageDescending(language); } public Task<HttpResponseMessage> GetImageResponse(string url, CancellationToken cancellationToken) diff --git a/MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonProvider.cs index 4384c203e..1757c8267 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonProvider.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonProvider.cs @@ -30,11 +30,9 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.People public async Task<IEnumerable<RemoteSearchResult>> GetSearchResults(PersonLookupInfo searchInfo, CancellationToken cancellationToken) { - var personTmdbId = Convert.ToInt32(searchInfo.GetProviderId(MetadataProvider.Tmdb), CultureInfo.InvariantCulture); - - if (personTmdbId <= 0) + if (searchInfo.TryGetProviderId(MetadataProvider.Tmdb, out var personTmdbId)) { - var personResult = await _tmdbClientManager.GetPersonAsync(personTmdbId, cancellationToken).ConfigureAwait(false); + var personResult = await _tmdbClientManager.GetPersonAsync(int.Parse(personTmdbId, CultureInfo.InvariantCulture), cancellationToken).ConfigureAwait(false); if (personResult != null) { @@ -51,19 +49,15 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.People } result.SetProviderId(MetadataProvider.Tmdb, personResult.Id.ToString(CultureInfo.InvariantCulture)); - result.SetProviderId(MetadataProvider.Imdb, personResult.ExternalIds.ImdbId); + if (!string.IsNullOrEmpty(personResult.ExternalIds.ImdbId)) + { + result.SetProviderId(MetadataProvider.Imdb, personResult.ExternalIds.ImdbId); + } return new[] { result }; } } - // TODO why? Because of the old rate limit? - if (searchInfo.IsAutomated) - { - // Don't hammer moviedb searching by name - return Enumerable.Empty<RemoteSearchResult>(); - } - var personSearchResult = await _tmdbClientManager.SearchPersonAsync(searchInfo.Name, cancellationToken).ConfigureAwait(false); var remoteSearchResults = new List<RemoteSearchResult>(); diff --git a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeProvider.cs index 36e7fe91a..8ec8f6464 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeProvider.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeProvider.cs @@ -121,9 +121,20 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV CommunityRating = Convert.ToSingle(episodeResult.VoteAverage) }; - if (!string.IsNullOrEmpty(episodeResult.ExternalIds?.TvdbId)) + var externalIds = episodeResult.ExternalIds; + if (!string.IsNullOrEmpty(externalIds?.TvdbId)) { - item.SetProviderId(MetadataProvider.Tvdb, episodeResult.ExternalIds.TvdbId); + item.SetProviderId(MetadataProvider.Tvdb, externalIds.TvdbId); + } + + if (!string.IsNullOrEmpty(externalIds?.ImdbId)) + { + item.SetProviderId(MetadataProvider.Imdb, externalIds.ImdbId); + } + + if (!string.IsNullOrEmpty(externalIds?.TvrageId)) + { + item.SetProviderId(MetadataProvider.TvRage, externalIds.TvrageId); } if (episodeResult.Videos?.Results != null) |
