diff options
Diffstat (limited to 'MediaBrowser.Controller')
22 files changed, 152 insertions, 208 deletions
diff --git a/MediaBrowser.Controller/Channels/Channel.cs b/MediaBrowser.Controller/Channels/Channel.cs index e6923b55ca..85a99d62cc 100644 --- a/MediaBrowser.Controller/Channels/Channel.cs +++ b/MediaBrowser.Controller/Channels/Channel.cs @@ -53,7 +53,7 @@ namespace MediaBrowser.Controller.Channels query.ChannelIds = new Guid[] { Id }; // Don't blow up here because it could cause parent screens with other content to fail - return ChannelManager.GetChannelItemsInternal(query, new SimpleProgress<double>(), CancellationToken.None).Result; + return ChannelManager.GetChannelItemsInternal(query, new SimpleProgress<double>(), CancellationToken.None).GetAwaiter().GetResult(); } catch { diff --git a/MediaBrowser.Controller/Drawing/IImageEncoder.cs b/MediaBrowser.Controller/Drawing/IImageEncoder.cs index 4e67cfee4f..e5c8ebfaf9 100644 --- a/MediaBrowser.Controller/Drawing/IImageEncoder.cs +++ b/MediaBrowser.Controller/Drawing/IImageEncoder.cs @@ -74,5 +74,12 @@ namespace MediaBrowser.Controller.Drawing /// <param name="options">The options to use when creating the collage.</param> /// <param name="libraryName">Optional. </param> void CreateImageCollage(ImageCollageOptions options, string? libraryName); + + /// <summary> + /// Creates a new splashscreen image. + /// </summary> + /// <param name="posters">The list of poster paths.</param> + /// <param name="backdrops">The list of backdrop paths.</param> + void CreateSplashscreen(IReadOnlyList<string> posters, IReadOnlyList<string> backdrops); } } diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index 915971adc9..c527328583 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.Globalization; +using System.IO; using System.Linq; using System.Text; using System.Text.Json.Serialization; @@ -886,7 +887,7 @@ namespace MediaBrowser.Controller.Entities return Name; } - public string GetInternalMetadataPath() + public virtual string GetInternalMetadataPath() { var basePath = ConfigurationManager.ApplicationPaths.InternalMetadataPath; @@ -1286,7 +1287,7 @@ namespace MediaBrowser.Controller.Entities { if (IsFileProtocol) { - requiresSave = await RefreshedOwnedItems(options, GetFileSystemChildren(options.DirectoryService).ToList(), cancellationToken).ConfigureAwait(false); + requiresSave = await RefreshedOwnedItems(options, GetFileSystemChildren(options.DirectoryService), cancellationToken).ConfigureAwait(false); } await LibraryManager.UpdateImagesAsync(this).ConfigureAwait(false); // ensure all image properties in DB are fresh @@ -1363,7 +1364,7 @@ namespace MediaBrowser.Controller.Entities /// <param name="fileSystemChildren">The list of filesystem children.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns><c>true</c> if any items have changed, else <c>false</c>.</returns> - protected virtual async Task<bool> RefreshedOwnedItems(MetadataRefreshOptions options, List<FileSystemMetadata> fileSystemChildren, CancellationToken cancellationToken) + protected virtual async Task<bool> RefreshedOwnedItems(MetadataRefreshOptions options, IReadOnlyList<FileSystemMetadata> fileSystemChildren, CancellationToken cancellationToken) { if (!IsFileProtocol || !SupportsOwnedItems || IsInMixedFolder || this is ICollectionFolder or UserRootFolder or AggregateFolder || this.GetType() == typeof(Folder)) { @@ -1380,7 +1381,7 @@ namespace MediaBrowser.Controller.Entities return directoryService.GetFileSystemEntries(path); } - private async Task<bool> RefreshExtras(BaseItem item, MetadataRefreshOptions options, List<FileSystemMetadata> fileSystemChildren, CancellationToken cancellationToken) + private async Task<bool> RefreshExtras(BaseItem item, MetadataRefreshOptions options, IReadOnlyList<FileSystemMetadata> fileSystemChildren, CancellationToken cancellationToken) { var extras = LibraryManager.FindExtras(item, fileSystemChildren, options.DirectoryService).ToArray(); var newExtraIds = extras.Select(i => i.Id).ToArray(); @@ -2041,27 +2042,32 @@ namespace MediaBrowser.Controller.Entities /// <summary> /// Validates that images within the item are still on the filesystem. /// </summary> - /// <param name="directoryService">The directory service to use.</param> /// <returns><c>true</c> if the images validate, <c>false</c> if not.</returns> - public bool ValidateImages(IDirectoryService directoryService) + public bool ValidateImages() { - var allFiles = ImageInfos - .Where(i => i.IsLocalFile) - .Select(i => System.IO.Path.GetDirectoryName(i.Path)) - .Distinct(StringComparer.OrdinalIgnoreCase) - .SelectMany(path => directoryService.GetFilePaths(path)) - .ToList(); + List<ItemImageInfo> deletedImages = null; + foreach (var imageInfo in ImageInfos) + { + if (!imageInfo.IsLocalFile) + { + continue; + } - var deletedImages = ImageInfos - .Where(image => image.IsLocalFile && !allFiles.Contains(image.Path, StringComparison.OrdinalIgnoreCase)) - .ToList(); + if (File.Exists(imageInfo.Path)) + { + continue; + } + + (deletedImages ??= new List<ItemImageInfo>()).Add(imageInfo); + } - if (deletedImages.Count > 0) + var anyImagesRemoved = deletedImages?.Count > 0; + if (anyImagesRemoved) { RemoveImages(deletedImages); } - return deletedImages.Count > 0; + return anyImagesRemoved; } /// <summary> diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index 55551e70ee..cb5ff6eec5 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -783,11 +783,10 @@ namespace MediaBrowser.Controller.Entities returnItems = returnItems.Skip(startIndex.Value); } - return new QueryResult<BaseItem> - { - TotalRecordCount = totalCount, - Items = returnItems.ToArray() - }; + return new QueryResult<BaseItem>( + query.StartIndex, + totalCount, + returnItems.ToArray()); } private bool RequiresPostFiltering2(InternalItemsQuery query) @@ -849,6 +848,18 @@ namespace MediaBrowser.Controller.Entities return true; } + if (query.HasThemeSong.HasValue) + { + Logger.LogDebug("Query requires post-filtering due to HasThemeSong"); + return true; + } + + if (query.HasThemeVideo.HasValue) + { + Logger.LogDebug("Query requires post-filtering due to HasThemeVideo"); + return true; + } + // Filter by VideoType if (query.VideoTypes.Length > 0) { @@ -965,7 +976,7 @@ namespace MediaBrowser.Controller.Entities query.ChannelIds = new[] { ChannelId }; // Don't blow up here because it could cause parent screens with other content to fail - return ChannelManager.GetChannelItemsInternal(query, new SimpleProgress<double>(), CancellationToken.None).Result; + return ChannelManager.GetChannelItemsInternal(query, new SimpleProgress<double>(), CancellationToken.None).GetAwaiter().GetResult(); } catch { @@ -1586,7 +1597,7 @@ namespace MediaBrowser.Controller.Entities .Where(i => i.Item2 != null); } - protected override async Task<bool> RefreshedOwnedItems(MetadataRefreshOptions options, List<FileSystemMetadata> fileSystemChildren, CancellationToken cancellationToken) + protected override async Task<bool> RefreshedOwnedItems(MetadataRefreshOptions options, IReadOnlyList<FileSystemMetadata> fileSystemChildren, CancellationToken cancellationToken) { var changesFound = false; diff --git a/MediaBrowser.Controller/Entities/UserViewBuilder.cs b/MediaBrowser.Controller/Entities/UserViewBuilder.cs index fe44f1169e..279206da48 100644 --- a/MediaBrowser.Controller/Entities/UserViewBuilder.cs +++ b/MediaBrowser.Controller/Entities/UserViewBuilder.cs @@ -238,12 +238,7 @@ namespace MediaBrowser.Controller.Entities private QueryResult<BaseItem> ConvertToResult(List<BaseItem> items) { - var arr = items.ToArray(); - return new QueryResult<BaseItem> - { - Items = arr, - TotalRecordCount = arr.Length - }; + return new QueryResult<BaseItem>(items); } private QueryResult<BaseItem> GetMovieGenres(Folder parent, User user, InternalItemsQuery query) @@ -414,16 +409,6 @@ namespace MediaBrowser.Controller.Entities return _libraryManager.GetItemsResult(query); } - private QueryResult<BaseItem> GetResult<T>(QueryResult<T> result) - where T : BaseItem - { - return new QueryResult<BaseItem> - { - Items = result.Items, // TODO Fix The co-variant conversion between T[] and BaseItem[], this can generate runtime issues if T is not BaseItem. - TotalRecordCount = result.TotalRecordCount - }; - } - private QueryResult<BaseItem> GetResult<T>( IEnumerable<T> items, InternalItemsQuery query) @@ -483,11 +468,10 @@ namespace MediaBrowser.Controller.Entities itemsArray = itemsArray.Skip(query.StartIndex.Value).ToArray(); } - return new QueryResult<BaseItem> - { - TotalRecordCount = totalCount, - Items = itemsArray - }; + return new QueryResult<BaseItem>( + query.StartIndex, + totalCount, + itemsArray); } public static bool Filter(BaseItem item, User user, InternalItemsQuery query, IUserDataManager userDataManager, ILibraryManager libraryManager) diff --git a/MediaBrowser.Controller/Entities/Video.cs b/MediaBrowser.Controller/Entities/Video.cs index 3e125602aa..5ab7808c36 100644 --- a/MediaBrowser.Controller/Entities/Video.cs +++ b/MediaBrowser.Controller/Entities/Video.cs @@ -419,7 +419,7 @@ namespace MediaBrowser.Controller.Entities return updateType; } - protected override async Task<bool> RefreshedOwnedItems(MetadataRefreshOptions options, List<FileSystemMetadata> fileSystemChildren, CancellationToken cancellationToken) + protected override async Task<bool> RefreshedOwnedItems(MetadataRefreshOptions options, IReadOnlyList<FileSystemMetadata> fileSystemChildren, CancellationToken cancellationToken) { var hasChanges = await base.RefreshedOwnedItems(options, fileSystemChildren, cancellationToken).ConfigureAwait(false); diff --git a/MediaBrowser.Controller/Extensions/ConfigurationExtensions.cs b/MediaBrowser.Controller/Extensions/ConfigurationExtensions.cs index f9285c7682..957ce67443 100644 --- a/MediaBrowser.Controller/Extensions/ConfigurationExtensions.cs +++ b/MediaBrowser.Controller/Extensions/ConfigurationExtensions.cs @@ -15,6 +15,11 @@ namespace MediaBrowser.Controller.Extensions public const string DefaultRedirectKey = "DefaultRedirectPath"; /// <summary> + /// The key for the address override option. + /// </summary> + public const string AddressOverrideKey = "PublishedServerUrl"; + + /// <summary> /// The key for a setting that indicates whether the application should host web client content. /// </summary> public const string HostWebClientKey = "hostwebclient"; diff --git a/MediaBrowser.Controller/Library/IIntroProvider.cs b/MediaBrowser.Controller/Library/IIntroProvider.cs index a74d1b9f0b..4a9721acbe 100644 --- a/MediaBrowser.Controller/Library/IIntroProvider.cs +++ b/MediaBrowser.Controller/Library/IIntroProvider.cs @@ -24,11 +24,5 @@ namespace MediaBrowser.Controller.Library /// <param name="user">The user.</param> /// <returns>IEnumerable{System.String}.</returns> Task<IEnumerable<IntroInfo>> GetIntros(BaseItem item, Jellyfin.Data.Entities.User user); - - /// <summary> - /// Gets all intro files. - /// </summary> - /// <returns>IEnumerable{System.String}.</returns> - IEnumerable<string> GetAllIntroFiles(); } } diff --git a/MediaBrowser.Controller/Library/ILibraryManager.cs b/MediaBrowser.Controller/Library/ILibraryManager.cs index 8db5283302..313d27ce62 100644 --- a/MediaBrowser.Controller/Library/ILibraryManager.cs +++ b/MediaBrowser.Controller/Library/ILibraryManager.cs @@ -138,10 +138,10 @@ namespace MediaBrowser.Controller.Library /// Validate and refresh the People sub-set of the IBN. /// The items are stored in the db but not loaded into memory until actually requested by an operation. /// </summary> - /// <param name="cancellationToken">The cancellation token.</param> /// <param name="progress">The progress.</param> + /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task.</returns> - Task ValidatePeople(CancellationToken cancellationToken, IProgress<double> progress); + Task ValidatePeopleAsync(IProgress<double> progress, CancellationToken cancellationToken); /// <summary> /// Reloads the root media folder. @@ -151,11 +151,6 @@ namespace MediaBrowser.Controller.Library /// <returns>Task.</returns> Task ValidateMediaLibrary(IProgress<double> progress, CancellationToken cancellationToken); - /// <summary> - /// Queues the library scan. - /// </summary> - void QueueLibraryScan(); - Task UpdateImagesAsync(BaseItem item, bool forceUpdate = false); /// <summary> @@ -182,12 +177,6 @@ namespace MediaBrowser.Controller.Library Task<IEnumerable<Video>> GetIntros(BaseItem item, User user); /// <summary> - /// Gets all intro files. - /// </summary> - /// <returns>IEnumerable{System.String}.</returns> - IEnumerable<string> GetAllIntroFiles(); - - /// <summary> /// Adds the parts. /// </summary> /// <param name="rules">The rules.</param> @@ -434,7 +423,7 @@ namespace MediaBrowser.Controller.Library /// <param name="fileSystemChildren">The file system children.</param> /// <param name="directoryService">An instance of <see cref="IDirectoryService"/>.</param> /// <returns>IEnumerable<BaseItem>.</returns> - IEnumerable<BaseItem> FindExtras(BaseItem owner, List<FileSystemMetadata> fileSystemChildren, IDirectoryService directoryService); + IEnumerable<BaseItem> FindExtras(BaseItem owner, IReadOnlyList<FileSystemMetadata> fileSystemChildren, IDirectoryService directoryService); /// <summary> /// Gets the collection folders. @@ -508,15 +497,6 @@ namespace MediaBrowser.Controller.Library string GetPathAfterNetworkSubstitution(string path, BaseItem ownerItem = null); /// <summary> - /// Substitutes the path. - /// </summary> - /// <param name="path">The path.</param> - /// <param name="from">From.</param> - /// <param name="to">To.</param> - /// <returns>System.String.</returns> - string SubstitutePath(string path, string from, string to); - - /// <summary> /// Converts the image to local. /// </summary> /// <param name="item">The item.</param> @@ -587,15 +567,8 @@ namespace MediaBrowser.Controller.Library int GetCount(InternalItemsQuery query); - void AddExternalSubtitleStreams( - List<MediaStream> streams, - string videoPath, - string[] files); - Task RunMetadataSavers(BaseItem item, ItemUpdateType updateReason); - BaseItem GetParentItem(string parentId, Guid? userId); - BaseItem GetParentItem(Guid? parentId, Guid? userId); } } diff --git a/MediaBrowser.Controller/Library/IMetadataFileSaver.cs b/MediaBrowser.Controller/Library/IMetadataFileSaver.cs index 9c6f03a232..842c687d1d 100644 --- a/MediaBrowser.Controller/Library/IMetadataFileSaver.cs +++ b/MediaBrowser.Controller/Library/IMetadataFileSaver.cs @@ -13,9 +13,4 @@ namespace MediaBrowser.Controller.Library /// <returns>System.String.</returns> string GetSavePath(BaseItem item); } - - public interface IConfigurableProvider - { - bool IsEnabled { get; } - } } diff --git a/MediaBrowser.Controller/Library/IMetadataSaver.cs b/MediaBrowser.Controller/Library/IMetadataSaver.cs index d963fd2491..eed6613459 100644 --- a/MediaBrowser.Controller/Library/IMetadataSaver.cs +++ b/MediaBrowser.Controller/Library/IMetadataSaver.cs @@ -1,6 +1,5 @@ -#nullable disable - using System.Threading; +using System.Threading.Tasks; using MediaBrowser.Controller.Entities; namespace MediaBrowser.Controller.Library @@ -29,6 +28,7 @@ namespace MediaBrowser.Controller.Library /// </summary> /// <param name="item">The item.</param> /// <param name="cancellationToken">The cancellation token.</param> - void Save(BaseItem item, CancellationToken cancellationToken); + /// <returns>The task object representing the asynchronous operation.</returns> + Task SaveAsync(BaseItem item, CancellationToken cancellationToken); } } diff --git a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs index 6dc5665b24..46bdca3027 100644 --- a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs +++ b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs @@ -188,7 +188,7 @@ namespace MediaBrowser.Controller.LiveTv /// <param name="options">The options.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Recommended programs.</returns> - QueryResult<BaseItemDto> GetRecommendedPrograms(InternalItemsQuery query, DtoOptions options, CancellationToken cancellationToken); + Task<QueryResult<BaseItemDto>> GetRecommendedProgramsAsync(InternalItemsQuery query, DtoOptions options, CancellationToken cancellationToken); /// <summary> /// Gets the recommended programs internal. diff --git a/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs b/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs index e63874f21e..335222da96 100644 --- a/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs +++ b/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs @@ -134,7 +134,7 @@ namespace MediaBrowser.Controller.LiveTv { Id = Id.ToString("N", CultureInfo.InvariantCulture), Protocol = PathProtocol ?? MediaProtocol.File, - MediaStreams = new List<MediaStream>(), + MediaStreams = Array.Empty<MediaStream>(), Name = Name, Path = Path, RunTimeTicks = RunTimeTicks, diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index 432159d5d0..e76a478a53 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -52,6 +52,10 @@ <!-- Code Analyzers--> <ItemGroup Condition=" '$(Configuration)' == 'Debug' "> + <PackageReference Include="Microsoft.CodeAnalysis.BannedApiAnalyzers" Version="3.3.3"> + <PrivateAssets>all</PrivateAssets> + <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> + </PackageReference> <PackageReference Include="SerilogAnalyzer" Version="0.15.0" PrivateAssets="All" /> <PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.376" PrivateAssets="All" /> <PackageReference Include="SmartAnalyzers.MultithreadingAnalyzer" Version="1.1.31" PrivateAssets="All" /> diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index bde10dbbfc..f7248acacd 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -12,6 +12,7 @@ using System.Text.RegularExpressions; using System.Threading; using Jellyfin.Data.Enums; using Jellyfin.Extensions; +using MediaBrowser.Common.Configuration; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Dlna; using MediaBrowser.Model.Dto; @@ -28,7 +29,7 @@ namespace MediaBrowser.Controller.MediaEncoding private const string VideotoolboxAlias = "vt"; private const string OpenclAlias = "ocl"; private const string CudaAlias = "cu"; - + private readonly IApplicationPaths _appPaths; private readonly IMediaEncoder _mediaEncoder; private readonly ISubtitleEncoder _subtitleEncoder; @@ -51,9 +52,11 @@ namespace MediaBrowser.Controller.MediaEncoding }; public EncodingHelper( + IApplicationPaths appPaths, IMediaEncoder mediaEncoder, ISubtitleEncoder subtitleEncoder) { + _appPaths = appPaths; _mediaEncoder = mediaEncoder; _subtitleEncoder = subtitleEncoder; } @@ -81,7 +84,6 @@ namespace MediaBrowser.Controller.MediaEncoding { "vaapi", hwEncoder + "_vaapi" }, { "videotoolbox", hwEncoder + "_videotoolbox" }, { "v4l2m2m", hwEncoder + "_v4l2m2m" }, - { "omx", hwEncoder + "_omx" }, }; if (!string.IsNullOrEmpty(hwType) @@ -578,13 +580,13 @@ namespace MediaBrowser.Controller.MediaEncoding options); } - private string GetVaapiDeviceArgs(string renderNodePath, string kernelDriver, string driver, string alias) + private string GetVaapiDeviceArgs(string renderNodePath, string driver, string kernelDriver, string alias) { alias ??= VaapiAlias; renderNodePath = renderNodePath ?? "/dev/dri/renderD128"; - var options = string.IsNullOrEmpty(kernelDriver) || string.IsNullOrEmpty(driver) + var options = string.IsNullOrEmpty(driver) ? renderNodePath - : ",kernel_driver=" + kernelDriver + ",driver=" + driver; + : ",driver=" + driver + (string.IsNullOrEmpty(kernelDriver) ? string.Empty : ",kernel_driver=" + kernelDriver); return string.Format( CultureInfo.InvariantCulture, @@ -599,7 +601,7 @@ namespace MediaBrowser.Controller.MediaEncoding if (OperatingSystem.IsLinux()) { // derive qsv from vaapi device - return GetVaapiDeviceArgs(null, "i915", "iHD", VaapiAlias) + arg + "@" + VaapiAlias; + return GetVaapiDeviceArgs(null, "iHD", "i915", VaapiAlias) + arg + "@" + VaapiAlias; } if (OperatingSystem.IsWindows()) @@ -688,7 +690,19 @@ namespace MediaBrowser.Controller.MediaEncoding return string.Empty; } - args.Append(GetVaapiDeviceArgs(options.VaapiDevice, null, null, VaapiAlias)); + if (_mediaEncoder.IsVaapiDeviceInteliHD) + { + args.Append(GetVaapiDeviceArgs(null, "iHD", null, VaapiAlias)); + } + else if (_mediaEncoder.IsVaapiDeviceInteli965) + { + args.Append(GetVaapiDeviceArgs(null, "i965", null, VaapiAlias)); + } + else + { + args.Append(GetVaapiDeviceArgs(options.VaapiDevice, null, null, VaapiAlias)); + } + var filterDevArgs = GetFilterHwDeviceArgs(VaapiAlias); if (isHwTonemapAvailable && IsOpenclFullSupported()) @@ -768,10 +782,6 @@ namespace MediaBrowser.Controller.MediaEncoding args.Append(GetCudaDeviceArgs(0, CudaAlias)) .Append(GetFilterHwDeviceArgs(CudaAlias)); - - // workaround for "No decoder surfaces left" error, - // but will increase vram usage. https://trac.ffmpeg.org/ticket/7562 - args.Append(" -extra_hw_frames 3"); } else if (string.Equals(optHwaccelType, "amf", StringComparison.OrdinalIgnoreCase)) { @@ -1080,6 +1090,12 @@ namespace MediaBrowser.Controller.MediaEncoding var alphaParam = enableAlpha ? ":alpha=1" : string.Empty; var sub2videoParam = enableSub2video ? ":sub2video=1" : string.Empty; + var fontPath = Path.Combine(_appPaths.CachePath, "attachments", state.MediaSource.Id); + var fontParam = string.Format( + CultureInfo.InvariantCulture, + ":fontsdir='{0}'", + _mediaEncoder.EscapeSubtitleFilterPath(fontPath)); + // TODO // var fallbackFontPath = Path.Combine(_appPaths.ProgramDataPath, "fonts", "DroidSansFallback.ttf"); // string fallbackFontParam = string.Empty; @@ -1120,11 +1136,12 @@ namespace MediaBrowser.Controller.MediaEncoding // TODO: Perhaps also use original_size=1920x800 ?? return string.Format( CultureInfo.InvariantCulture, - "subtitles=f='{0}'{1}{2}{3}{4}", + "subtitles=f='{0}'{1}{2}{3}{4}{5}", _mediaEncoder.EscapeSubtitleFilterPath(subtitlePath), charsetParam, alphaParam, sub2videoParam, + fontParam, // fallbackFontParam, setPtsParam); } @@ -1133,11 +1150,12 @@ namespace MediaBrowser.Controller.MediaEncoding return string.Format( CultureInfo.InvariantCulture, - "subtitles='{0}:si={1}{2}{3}'{4}", + "subtitles=f='{0}':si={1}{2}{3}{4}{5}", _mediaEncoder.EscapeSubtitleFilterPath(mediaPath), state.InternalSubtitleStreamOffset.ToString(CultureInfo.InvariantCulture), alphaParam, sub2videoParam, + fontParam, // fallbackFontParam, setPtsParam); } @@ -1281,11 +1299,6 @@ namespace MediaBrowser.Controller.MediaEncoding param += " -low_power 1"; } - if (string.Equals(videoEncoder, "h264_v4l2m2m", StringComparison.OrdinalIgnoreCase)) - { - param += " -pix_fmt nv21"; - } - var isVc1 = string.Equals(state.VideoStream?.Codec, "vc1", StringComparison.OrdinalIgnoreCase); var isLibX265 = string.Equals(videoEncoder, "libx265", StringComparison.OrdinalIgnoreCase); @@ -1343,29 +1356,37 @@ namespace MediaBrowser.Controller.MediaEncoding switch (encodingOptions.EncoderPreset) { case "veryslow": - - param += " -preset slow"; // lossless is only supported on maxwell and newer(2014+) + param += " -preset p7"; break; case "slow": + param += " -preset p6"; + break; + case "slower": - param += " -preset slow"; + param += " -preset p5"; break; case "medium": - param += " -preset medium"; + param += " -preset p4"; break; case "fast": + param += " -preset p3"; + break; + case "faster": + param += " -preset p2"; + break; + case "veryfast": case "superfast": case "ultrafast": - param += " -preset fast"; + param += " -preset p1"; break; default: - param += " -preset default"; + param += " -preset p4"; break; } } @@ -1571,10 +1592,8 @@ namespace MediaBrowser.Controller.MediaEncoding if (!string.IsNullOrEmpty(profile)) { - if (!string.Equals(videoEncoder, "h264_omx", StringComparison.OrdinalIgnoreCase) - && !string.Equals(videoEncoder, "h264_v4l2m2m", StringComparison.OrdinalIgnoreCase)) + if (!string.Equals(videoEncoder, "h264_v4l2m2m", StringComparison.OrdinalIgnoreCase)) { - // not supported by h264_omx param += " -profile:v:0 " + profile; } } @@ -1613,8 +1632,7 @@ namespace MediaBrowser.Controller.MediaEncoding // NVENC cannot adjust the given level, just throw an error. // level option may cause corrupted frames on AMD VAAPI. } - else if (!string.Equals(videoEncoder, "h264_omx", StringComparison.OrdinalIgnoreCase) - || !string.Equals(videoEncoder, "libx265", StringComparison.OrdinalIgnoreCase)) + else if (!string.Equals(videoEncoder, "libx265", StringComparison.OrdinalIgnoreCase)) { param += " -level " + level; } @@ -2167,6 +2185,7 @@ namespace MediaBrowser.Controller.MediaEncoding // Important: If this is ever re-enabled, make sure not to use it with wtv because it breaks seeking if (!string.Equals(state.InputContainer, "wtv", StringComparison.OrdinalIgnoreCase) && state.TranscodingType != TranscodingJobType.Progressive + && state.TranscodingType != TranscodingJobType.Hls && !state.EnableBreakOnNonKeyFrames(outputVideoCodec) && (state.BaseRequest.StartTimeTicks ?? 0) > 0) { @@ -2695,6 +2714,7 @@ namespace MediaBrowser.Controller.MediaEncoding var vidDecoder = GetHardwareVideoDecoder(state, options) ?? string.Empty; var isSwDecoder = string.IsNullOrEmpty(vidDecoder); var isVaapiEncoder = vidEncoder.Contains("vaapi", StringComparison.OrdinalIgnoreCase); + var isV4l2Encoder = vidEncoder.Contains("h264_v4l2m2m", StringComparison.OrdinalIgnoreCase); var doDeintH264 = state.DeInterlace("h264", true) || state.DeInterlace("avc", true); var doDeintHevc = state.DeInterlace("h265", true) || state.DeInterlace("hevc", true); @@ -2723,6 +2743,10 @@ namespace MediaBrowser.Controller.MediaEncoding { outFormat = "nv12"; } + else if (isV4l2Encoder) + { + outFormat = "yuv420p"; + } // sw scale mainFilters.Add(swScaleFilter); @@ -4268,11 +4292,6 @@ namespace MediaBrowser.Controller.MediaEncoding { return GetVideotoolboxVidDecoder(state, options, videoStream, bitDepth); } - - if (string.Equals(options.HardwareAccelerationType, "omx", StringComparison.OrdinalIgnoreCase)) - { - return GetOmxVidDecoder(state, options, videoStream, bitDepth); - } } var whichCodec = videoStream.Codec; @@ -4411,7 +4430,8 @@ namespace MediaBrowser.Controller.MediaEncoding { if (options.EnableEnhancedNvdecDecoder && isCudaSupported && isCodecAvailable) { - return " -hwaccel cuda" + (outputHwSurface ? " -hwaccel_output_format cuda" : string.Empty) + (isAv1 ? " -c:v av1" : string.Empty); + // set -threads 1 to nvdec decoder explicitly since it doesn't implement threading support. + return " -hwaccel cuda" + (outputHwSurface ? " -hwaccel_output_format cuda" : string.Empty) + " -threads 1" + (isAv1 ? " -c:v av1" : string.Empty); } } @@ -4747,43 +4767,6 @@ namespace MediaBrowser.Controller.MediaEncoding return null; } - public string GetOmxVidDecoder(EncodingJobInfo state, EncodingOptions options, MediaStream videoStream, int bitDepth) - { - if (!OperatingSystem.IsLinux() - || !string.Equals(options.HardwareAccelerationType, "omx", StringComparison.OrdinalIgnoreCase)) - { - return null; - } - - var is8bitSwFormatsOmx = string.Equals("yuv420p", videoStream.PixelFormat, StringComparison.OrdinalIgnoreCase); - - if (is8bitSwFormatsOmx) - { - if (string.Equals("avc", videoStream.Codec, StringComparison.OrdinalIgnoreCase) - || string.Equals("h264", videoStream.Codec, StringComparison.OrdinalIgnoreCase)) - { - return GetHwDecoderName(options, "h264", "mmal", "h264", bitDepth); - } - - if (string.Equals("mpeg2video", videoStream.Codec, StringComparison.OrdinalIgnoreCase)) - { - return GetHwDecoderName(options, "mpeg2", "mmal", "mpeg2video", bitDepth); - } - - if (string.Equals("mpeg4", videoStream.Codec, StringComparison.OrdinalIgnoreCase)) - { - return GetHwDecoderName(options, "mpeg4", "mmal", "mpeg4", bitDepth); - } - - if (string.Equals("vc1", videoStream.Codec, StringComparison.OrdinalIgnoreCase)) - { - return GetHwDecoderName(options, "vc1", "mmal", "vc1", bitDepth); - } - } - - return null; - } - /// <summary> /// Gets the number of threads. /// </summary> diff --git a/MediaBrowser.Controller/MediaEncoding/IAttachmentExtractor.cs b/MediaBrowser.Controller/MediaEncoding/IAttachmentExtractor.cs index 4e7e266245..a2b6be1e6d 100644 --- a/MediaBrowser.Controller/MediaEncoding/IAttachmentExtractor.cs +++ b/MediaBrowser.Controller/MediaEncoding/IAttachmentExtractor.cs @@ -6,6 +6,7 @@ using System.IO; using System.Threading; using System.Threading.Tasks; using MediaBrowser.Controller.Entities; +using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; namespace MediaBrowser.Controller.MediaEncoding @@ -17,5 +18,10 @@ namespace MediaBrowser.Controller.MediaEncoding string mediaSourceId, int attachmentStreamIndex, CancellationToken cancellationToken); + Task ExtractAllAttachments( + string inputFile, + MediaSourceInfo mediaSource, + string outputPath, + CancellationToken cancellationToken); } } diff --git a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs index fd3eb81056..6bf3e7b469 100644 --- a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs +++ b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs @@ -26,6 +26,12 @@ namespace MediaBrowser.Controller.MediaEncoding string EncoderPath { get; } /// <summary> + /// Gets the probe path. + /// </summary> + /// <value>The probe path.</value> + string ProbePath { get; } + + /// <summary> /// Gets the version of encoder. /// </summary> /// <returns>The version of encoder.</returns> diff --git a/MediaBrowser.Controller/Persistence/IItemRepository.cs b/MediaBrowser.Controller/Persistence/IItemRepository.cs index 837bf0bb20..24f7b5cd36 100644 --- a/MediaBrowser.Controller/Persistence/IItemRepository.cs +++ b/MediaBrowser.Controller/Persistence/IItemRepository.cs @@ -15,16 +15,9 @@ namespace MediaBrowser.Controller.Persistence /// <summary> /// Provides an interface to implement an Item repository. /// </summary> - public interface IItemRepository : IRepository + public interface IItemRepository : IDisposable { /// <summary> - /// Saves an item. - /// </summary> - /// <param name="item">The item.</param> - /// <param name="cancellationToken">The cancellation token.</param> - void SaveItem(BaseItem item, CancellationToken cancellationToken); - - /// <summary> /// Deletes the item. /// </summary> /// <param name="id">The identifier.</param> @@ -81,7 +74,7 @@ namespace MediaBrowser.Controller.Persistence /// <param name="id">The identifier.</param> /// <param name="streams">The streams.</param> /// <param name="cancellationToken">The cancellation token.</param> - void SaveMediaStreams(Guid id, List<MediaStream> streams, CancellationToken cancellationToken); + void SaveMediaStreams(Guid id, IReadOnlyList<MediaStream> streams, CancellationToken cancellationToken); /// <summary> /// Gets the media attachments. @@ -99,13 +92,6 @@ namespace MediaBrowser.Controller.Persistence void SaveMediaAttachments(Guid id, IReadOnlyList<MediaAttachment> attachments, CancellationToken cancellationToken); /// <summary> - /// Gets the item ids. - /// </summary> - /// <param name="query">The query.</param> - /// <returns>IEnumerable<Guid>.</returns> - QueryResult<Guid> GetItemIds(InternalItemsQuery query); - - /// <summary> /// Gets the items. /// </summary> /// <param name="query">The query.</param> @@ -141,13 +127,6 @@ namespace MediaBrowser.Controller.Persistence List<string> GetPeopleNames(InternalPeopleQuery query); /// <summary> - /// Gets the item ids with path. - /// </summary> - /// <param name="query">The query.</param> - /// <returns>QueryResult<Tuple<Guid, System.String>>.</returns> - List<Tuple<Guid, string>> GetItemIdsWithPath(InternalItemsQuery query); - - /// <summary> /// Gets the item list. /// </summary> /// <param name="query">The query.</param> diff --git a/MediaBrowser.Controller/Persistence/IRepository.cs b/MediaBrowser.Controller/Persistence/IRepository.cs deleted file mode 100644 index 42f2850762..0000000000 --- a/MediaBrowser.Controller/Persistence/IRepository.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; - -namespace MediaBrowser.Controller.Persistence -{ - /// <summary> - /// Provides a base interface for all the repository interfaces. - /// </summary> - public interface IRepository : IDisposable - { - /// <summary> - /// Gets the name of the repository. - /// </summary> - /// <value>The name.</value> - string Name { get; } - } -} diff --git a/MediaBrowser.Controller/Persistence/IUserDataRepository.cs b/MediaBrowser.Controller/Persistence/IUserDataRepository.cs index c43acfb6de..f2fb2826a0 100644 --- a/MediaBrowser.Controller/Persistence/IUserDataRepository.cs +++ b/MediaBrowser.Controller/Persistence/IUserDataRepository.cs @@ -1,5 +1,6 @@ #nullable disable +using System; using System.Collections.Generic; using System.Threading; using MediaBrowser.Controller.Entities; @@ -9,7 +10,7 @@ namespace MediaBrowser.Controller.Persistence /// <summary> /// Provides an interface to implement a UserData repository. /// </summary> - public interface IUserDataRepository : IRepository + public interface IUserDataRepository : IDisposable { /// <summary> /// Saves the user data. diff --git a/MediaBrowser.Controller/Providers/IProviderManager.cs b/MediaBrowser.Controller/Providers/IProviderManager.cs index 9f7a76be64..44bc4a50cb 100644 --- a/MediaBrowser.Controller/Providers/IProviderManager.cs +++ b/MediaBrowser.Controller/Providers/IProviderManager.cs @@ -156,7 +156,8 @@ namespace MediaBrowser.Controller.Providers /// </summary> /// <param name="item">The item.</param> /// <param name="updateType">Type of the update.</param> - void SaveMetadata(BaseItem item, ItemUpdateType updateType); + /// <returns>The task object representing the asynchronous operation.</returns> + Task SaveMetadataAsync(BaseItem item, ItemUpdateType updateType); /// <summary> /// Saves the metadata. @@ -164,7 +165,8 @@ namespace MediaBrowser.Controller.Providers /// <param name="item">The item.</param> /// <param name="updateType">Type of the update.</param> /// <param name="savers">The metadata savers.</param> - void SaveMetadata(BaseItem item, ItemUpdateType updateType, IEnumerable<string> savers); + /// <returns>The task object representing the asynchronous operation.</returns> + Task SaveMetadataAsync(BaseItem item, ItemUpdateType updateType, IEnumerable<string> savers); /// <summary> /// Gets the metadata options. diff --git a/MediaBrowser.Controller/Session/SessionInfo.cs b/MediaBrowser.Controller/Session/SessionInfo.cs index 6134c0cf33..c2ca233868 100644 --- a/MediaBrowser.Controller/Session/SessionInfo.cs +++ b/MediaBrowser.Controller/Session/SessionInfo.cs @@ -39,6 +39,8 @@ namespace MediaBrowser.Controller.Session AdditionalUsers = Array.Empty<SessionUserInfo>(); PlayState = new PlayerStateInfo(); SessionControllers = Array.Empty<ISessionController>(); + NowPlayingQueue = Array.Empty<QueueItem>(); + NowPlayingQueueFullItems = Array.Empty<BaseItemDto>(); } public PlayerStateInfo PlayState { get; set; } @@ -219,7 +221,9 @@ namespace MediaBrowser.Controller.Session } } - public QueueItem[] NowPlayingQueue { get; set; } + public IReadOnlyList<QueueItem> NowPlayingQueue { get; set; } + + public IReadOnlyList<BaseItemDto> NowPlayingQueueFullItems { get; set; } public bool HasCustomDeviceName { get; set; } |
