diff options
Diffstat (limited to 'MediaBrowser.Controller')
23 files changed, 186 insertions, 276 deletions
diff --git a/MediaBrowser.Controller/Channels/Channel.cs b/MediaBrowser.Controller/Channels/Channel.cs index 85a99d62c..94418683b 100644 --- a/MediaBrowser.Controller/Channels/Channel.cs +++ b/MediaBrowser.Controller/Channels/Channel.cs @@ -77,11 +77,6 @@ namespace MediaBrowser.Controller.Channels return false; } - protected override bool IsAllowTagFilterEnforced() - { - return false; - } - internal static bool IsChannelVisible(BaseItem channelItem, User user) { var channel = ChannelManager.GetChannel(channelItem.ChannelId.ToString(string.Empty)); diff --git a/MediaBrowser.Controller/Entities/AggregateFolder.cs b/MediaBrowser.Controller/Entities/AggregateFolder.cs index 9589f5245..77a857b78 100644 --- a/MediaBrowser.Controller/Entities/AggregateFolder.cs +++ b/MediaBrowser.Controller/Entities/AggregateFolder.cs @@ -187,14 +187,14 @@ namespace MediaBrowser.Controller.Entities /// <exception cref="ArgumentNullException">The id is empty.</exception> public BaseItem FindVirtualChild(Guid id) { - if (id.Equals(Guid.Empty)) + if (id.Equals(default)) { throw new ArgumentNullException(nameof(id)); } foreach (var child in _virtualChildren) { - if (child.Id == id) + if (child.Id.Equals(id)) { return child; } diff --git a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs index 11b95b94b..0f2d7e62d 100644 --- a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs +++ b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs @@ -24,7 +24,7 @@ namespace MediaBrowser.Controller.Entities.Audio public class MusicArtist : Folder, IItemByName, IHasMusicGenres, IHasDualAccess, IHasLookupInfo<ArtistInfo> { [JsonIgnore] - public bool IsAccessedByName => ParentId.Equals(Guid.Empty); + public bool IsAccessedByName => ParentId.Equals(default); [JsonIgnore] public override bool IsFolder => !IsAccessedByName; diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index 0f62e8e1e..2bb966d2c 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -231,7 +231,7 @@ namespace MediaBrowser.Controller.Entities { get { - if (!ChannelId.Equals(Guid.Empty)) + if (!ChannelId.Equals(default)) { return SourceType.Channel; } @@ -521,7 +521,7 @@ namespace MediaBrowser.Controller.Entities get { var id = DisplayParentId; - if (id.Equals(Guid.Empty)) + if (id.Equals(default)) { return null; } @@ -737,7 +737,7 @@ namespace MediaBrowser.Controller.Entities public virtual bool StopRefreshIfLocalMetadataFound => true; [JsonIgnore] - protected virtual bool SupportsOwnedItems => !ParentId.Equals(Guid.Empty) && IsFileProtocol; + protected virtual bool SupportsOwnedItems => !ParentId.Equals(default) && IsFileProtocol; [JsonIgnore] public virtual bool SupportsPeople => false; @@ -848,7 +848,7 @@ namespace MediaBrowser.Controller.Entities public BaseItem GetOwner() { var ownerId = OwnerId; - return ownerId.Equals(Guid.Empty) ? null : LibraryManager.GetItemById(ownerId); + return ownerId.Equals(default) ? null : LibraryManager.GetItemById(ownerId); } public bool CanDelete(User user, List<Folder> allCollectionFolders) @@ -878,16 +878,13 @@ namespace MediaBrowser.Controller.Entities return CanDownload() && IsAuthorizedToDownload(user); } - /// <summary> - /// Returns a <see cref="string" /> that represents this instance. - /// </summary> - /// <returns>A <see cref="string" /> that represents this instance.</returns> + /// <inheritdoc /> public override string ToString() { return Name; } - public string GetInternalMetadataPath() + public virtual string GetInternalMetadataPath() { var basePath = ConfigurationManager.ApplicationPaths.InternalMetadataPath; @@ -984,12 +981,12 @@ namespace MediaBrowser.Controller.Entities public BaseItem GetParent() { var parentId = ParentId; - if (!parentId.Equals(Guid.Empty)) + if (parentId.Equals(default)) { - return LibraryManager.GetItemById(parentId); + return null; } - return null; + return LibraryManager.GetItemById(parentId); } public IEnumerable<BaseItem> GetParents() @@ -1397,7 +1394,7 @@ namespace MediaBrowser.Controller.Entities var tasks = extras.Select(i => { var subOptions = new MetadataRefreshOptions(options); - if (i.OwnerId != ownerId || i.ParentId != Guid.Empty) + if (!i.OwnerId.Equals(ownerId) || !i.ParentId.Equals(default)) { i.OwnerId = ownerId; i.ParentId = Guid.Empty; @@ -1595,23 +1592,6 @@ namespace MediaBrowser.Controller.Entities return value.Value <= maxAllowedRating.Value; } - public int? GetParentalRatingValue() - { - var rating = CustomRating; - - if (string.IsNullOrEmpty(rating)) - { - rating = OfficialRating; - } - - if (string.IsNullOrEmpty(rating)) - { - return null; - } - - return LocalizationManager.GetRatingLevel(rating); - } - public int? GetInheritedParentalRatingValue() { var rating = CustomRatingForComparison; @@ -1652,11 +1632,6 @@ namespace MediaBrowser.Controller.Entities return true; } - protected virtual bool IsAllowTagFilterEnforced() - { - return true; - } - public virtual UnratedItem GetBlockUnratedType() { if (SourceType == SourceType.Channel) @@ -1736,7 +1711,7 @@ namespace MediaBrowser.Controller.Entities // First get using the cached Id if (info.ItemId.HasValue) { - if (info.ItemId.Value.Equals(Guid.Empty)) + if (info.ItemId.Value.Equals(default)) { return null; } @@ -2657,7 +2632,7 @@ namespace MediaBrowser.Controller.Entities } /// <inheritdoc /> - public bool Equals(BaseItem other) => Id == other?.Id; + public bool Equals(BaseItem other) => other is not null && other.Id.Equals(Id); /// <inheritdoc /> public override int GetHashCode() => HashCode.Combine(Id); diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index 4d9aac6f9..b6983b73e 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -189,21 +189,6 @@ namespace MediaBrowser.Controller.Entities return baseResult; } - protected override bool IsAllowTagFilterEnforced() - { - if (this is ICollectionFolder) - { - return false; - } - - if (this is UserView) - { - return false; - } - - return true; - } - /// <summary> /// Adds the child. /// </summary> @@ -213,7 +198,7 @@ namespace MediaBrowser.Controller.Entities { item.SetParent(this); - if (item.Id.Equals(Guid.Empty)) + if (item.Id.Equals(default)) { item.Id = LibraryManager.GetNewItemId(item.Path, item.GetType()); } @@ -730,7 +715,9 @@ namespace MediaBrowser.Controller.Entities return PostFilterAndSort(items, query, true); } - if (this is not UserRootFolder && this is not AggregateFolder && query.ParentId == Guid.Empty) + if (this is not UserRootFolder + && this is not AggregateFolder + && query.ParentId.Equals(default)) { query.Parent = this; } @@ -848,6 +835,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) { @@ -1492,7 +1491,7 @@ namespace MediaBrowser.Controller.Entities { if (i.ItemId.HasValue) { - if (i.ItemId.Value == itemId) + if (i.ItemId.Value.Equals(itemId)) { return true; } @@ -1502,7 +1501,7 @@ namespace MediaBrowser.Controller.Entities var child = GetLinkedChild(i); - if (child != null && child.Id == itemId) + if (child != null && child.Id.Equals(itemId)) { return true; } diff --git a/MediaBrowser.Controller/Entities/TV/Episode.cs b/MediaBrowser.Controller/Entities/TV/Episode.cs index c8a0e21eb..15b721fe6 100644 --- a/MediaBrowser.Controller/Entities/TV/Episode.cs +++ b/MediaBrowser.Controller/Entities/TV/Episode.cs @@ -74,12 +74,12 @@ namespace MediaBrowser.Controller.Entities.TV get { var seriesId = SeriesId; - if (seriesId.Equals(Guid.Empty)) + if (seriesId.Equals(default)) { seriesId = FindSeriesId(); } - return !seriesId.Equals(Guid.Empty) ? (LibraryManager.GetItemById(seriesId) as Series) : null; + return seriesId.Equals(default) ? null : (LibraryManager.GetItemById(seriesId) as Series); } } @@ -89,12 +89,12 @@ namespace MediaBrowser.Controller.Entities.TV get { var seasonId = SeasonId; - if (seasonId.Equals(Guid.Empty)) + if (seasonId.Equals(default)) { seasonId = FindSeasonId(); } - return !seasonId.Equals(Guid.Empty) ? (LibraryManager.GetItemById(seasonId) as Season) : null; + return seasonId.Equals(default) ? null : (LibraryManager.GetItemById(seasonId) as Season); } } @@ -271,7 +271,7 @@ namespace MediaBrowser.Controller.Entities.TV var seasonId = SeasonId; - if (!seasonId.Equals(Guid.Empty) && !list.Contains(seasonId)) + if (!seasonId.Equals(default) && !list.Contains(seasonId)) { list.Add(seasonId); } diff --git a/MediaBrowser.Controller/Entities/TV/Season.cs b/MediaBrowser.Controller/Entities/TV/Season.cs index 926c7b045..bd8df2fac 100644 --- a/MediaBrowser.Controller/Entities/TV/Season.cs +++ b/MediaBrowser.Controller/Entities/TV/Season.cs @@ -48,12 +48,12 @@ namespace MediaBrowser.Controller.Entities.TV get { var seriesId = SeriesId; - if (seriesId == Guid.Empty) + if (seriesId.Equals(default)) { seriesId = FindSeriesId(); } - return seriesId == Guid.Empty ? null : (LibraryManager.GetItemById(seriesId) as Series); + return seriesId.Equals(default) ? null : (LibraryManager.GetItemById(seriesId) as Series); } } diff --git a/MediaBrowser.Controller/Entities/UserView.cs b/MediaBrowser.Controller/Entities/UserView.cs index 5c9be7337..47432ee93 100644 --- a/MediaBrowser.Controller/Entities/UserView.cs +++ b/MediaBrowser.Controller/Entities/UserView.cs @@ -69,11 +69,11 @@ namespace MediaBrowser.Controller.Entities /// <inheritdoc /> public override IEnumerable<Guid> GetIdsForAncestorQuery() { - if (!DisplayParentId.Equals(Guid.Empty)) + if (!DisplayParentId.Equals(default)) { yield return DisplayParentId; } - else if (!ParentId.Equals(Guid.Empty)) + else if (!ParentId.Equals(default)) { yield return ParentId; } @@ -94,11 +94,11 @@ namespace MediaBrowser.Controller.Entities { var parent = this as Folder; - if (!DisplayParentId.Equals(Guid.Empty)) + if (!DisplayParentId.Equals(default)) { parent = LibraryManager.GetItemById(DisplayParentId) as Folder ?? parent; } - else if (!ParentId.Equals(Guid.Empty)) + else if (!ParentId.Equals(default)) { parent = LibraryManager.GetItemById(ParentId) as Folder ?? parent; } diff --git a/MediaBrowser.Controller/Entities/UserViewBuilder.cs b/MediaBrowser.Controller/Entities/UserViewBuilder.cs index 279206da4..2996104e7 100644 --- a/MediaBrowser.Controller/Entities/UserViewBuilder.cs +++ b/MediaBrowser.Controller/Entities/UserViewBuilder.cs @@ -988,7 +988,7 @@ namespace MediaBrowser.Controller.Entities public static IEnumerable<BaseItem> FilterForAdjacency(List<BaseItem> list, string adjacentToId) { var adjacentToIdGuid = new Guid(adjacentToId); - var adjacentToItem = list.FirstOrDefault(i => i.Id == adjacentToIdGuid); + var adjacentToItem = list.FirstOrDefault(i => i.Id.Equals(adjacentToIdGuid)); var index = list.IndexOf(adjacentToItem); @@ -1005,7 +1005,7 @@ namespace MediaBrowser.Controller.Entities nextId = list[index + 1].Id; } - return list.Where(i => i.Id == previousId || i.Id == nextId || i.Id == adjacentToIdGuid); + return list.Where(i => i.Id.Equals(previousId) || i.Id.Equals(nextId) || i.Id.Equals(adjacentToIdGuid)); } } } diff --git a/MediaBrowser.Controller/Entities/Video.cs b/MediaBrowser.Controller/Entities/Video.cs index 5ab7808c3..5de2e0f50 100644 --- a/MediaBrowser.Controller/Entities/Video.cs +++ b/MediaBrowser.Controller/Entities/Video.cs @@ -455,7 +455,7 @@ namespace MediaBrowser.Controller.Entities foreach (var child in LinkedAlternateVersions) { // Reset the cached value - if (child.ItemId.HasValue && child.ItemId.Value.Equals(Guid.Empty)) + if (child.ItemId.HasValue && child.ItemId.Value.Equals(default)) { child.ItemId = null; } diff --git a/MediaBrowser.Controller/Extensions/ConfigurationExtensions.cs b/MediaBrowser.Controller/Extensions/ConfigurationExtensions.cs index 1fedf7205..5a7110261 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 a74d1b9f0..4a9721acb 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 2b0193771..313d27ce6 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> @@ -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/LiveTv/LiveTvChannel.cs b/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs index e63874f21..335222da9 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 e76a478a5..6164e51cd 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -57,7 +57,7 @@ <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="StyleCop.Analyzers" Version="1.2.0-beta.406" PrivateAssets="All" /> <PackageReference Include="SmartAnalyzers.MultithreadingAnalyzer" Version="1.1.31" PrivateAssets="All" /> </ItemGroup> diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index bde10dbbf..633ba2d76 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)) { @@ -832,8 +842,9 @@ namespace MediaBrowser.Controller.MediaEncoding /// </summary> /// <param name="state">Encoding state.</param> /// <param name="options">Encoding options.</param> + /// <param name="segmentContainer">Segment Container.</param> /// <returns>Input arguments.</returns> - public string GetInputArgument(EncodingJobInfo state, EncodingOptions options) + public string GetInputArgument(EncodingJobInfo state, EncodingOptions options, string segmentContainer) { var arg = new StringBuilder(); var inputVidHwaccelArgs = GetInputVideoHwaccelArgs(state, options); @@ -870,7 +881,7 @@ namespace MediaBrowser.Controller.MediaEncoding } // Also seek the external subtitles stream. - var seekSubParam = GetFastSeekCommandLineParameter(state, options); + var seekSubParam = GetFastSeekCommandLineParameter(state, options, segmentContainer); if (!string.IsNullOrEmpty(seekSubParam)) { arg.Append(' ').Append(seekSubParam); @@ -887,7 +898,7 @@ namespace MediaBrowser.Controller.MediaEncoding if (state.AudioStream != null && state.AudioStream.IsExternal) { // Also seek the external audio stream. - var seekAudioParam = GetFastSeekCommandLineParameter(state, options); + var seekAudioParam = GetFastSeekCommandLineParameter(state, options, segmentContainer); if (!string.IsNullOrEmpty(seekAudioParam)) { arg.Append(' ').Append(seekAudioParam); @@ -958,6 +969,7 @@ namespace MediaBrowser.Controller.MediaEncoding // Apply aac_adtstoasc bitstream filter when media source is in mpegts. if (string.Equals(segmentFormat, "mp4", StringComparison.OrdinalIgnoreCase) && (string.Equals(mediaSourceContainer, "mpegts", StringComparison.OrdinalIgnoreCase) + || string.Equals(mediaSourceContainer, "aac", StringComparison.OrdinalIgnoreCase) || string.Equals(mediaSourceContainer, "hls", StringComparison.OrdinalIgnoreCase))) { bitStreamArgs = GetBitStreamArgs(state.AudioStream); @@ -1080,6 +1092,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 +1138,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 +1152,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 +1301,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 +1358,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 +1594,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 +1634,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; } @@ -1677,7 +1697,8 @@ namespace MediaBrowser.Controller.MediaEncoding // Source and target codecs must match if (string.IsNullOrEmpty(videoStream.Codec) - || !state.SupportedVideoCodecs.Contains(videoStream.Codec, StringComparison.OrdinalIgnoreCase)) + || (state.SupportedVideoCodecs.Length != 0 + && !state.SupportedVideoCodecs.Contains(videoStream.Codec, StringComparison.OrdinalIgnoreCase))) { return false; } @@ -1780,7 +1801,7 @@ namespace MediaBrowser.Controller.MediaEncoding return false; } - return request.EnableAutoStreamCopy; + return true; } public bool CanStreamCopyAudio(EncodingJobInfo state, MediaStream audioStream, IEnumerable<string> supportedAudioCodecs) @@ -1837,17 +1858,11 @@ namespace MediaBrowser.Controller.MediaEncoding } // Video bitrate must fall within requested value - if (request.AudioBitRate.HasValue) + if (request.AudioBitRate.HasValue + && audioStream.BitDepth.HasValue + && audioStream.BitRate.Value > request.AudioBitRate.Value) { - if (!audioStream.BitRate.HasValue || audioStream.BitRate.Value <= 0) - { - return false; - } - - if (audioStream.BitRate.Value > request.AudioBitRate.Value) - { - return false; - } + return false; } return request.EnableAutoStreamCopy; @@ -2149,9 +2164,10 @@ namespace MediaBrowser.Controller.MediaEncoding /// </summary> /// <param name="state">The state.</param> /// <param name="options">The options.</param> + /// <param name="segmentContainer">Segment Container.</param> /// <returns>System.String.</returns> /// <value>The fast seek command line parameter.</value> - public string GetFastSeekCommandLineParameter(EncodingJobInfo state, EncodingOptions options) + public string GetFastSeekCommandLineParameter(EncodingJobInfo state, EncodingOptions options, string segmentContainer) { var time = state.BaseRequest.StartTimeTicks ?? 0; var seekParam = string.Empty; @@ -2163,9 +2179,13 @@ namespace MediaBrowser.Controller.MediaEncoding if (state.IsVideoRequest) { var outputVideoCodec = GetVideoEncoder(state, options); + var segmentFormat = GetSegmentFileExtension(segmentContainer).TrimStart('.'); // Important: If this is ever re-enabled, make sure not to use it with wtv because it breaks seeking + // Disable -noaccurate_seek on mpegts container due to the timestamps issue on some clients, + // but it's still required for fMP4 container otherwise the audio can't be synced to the video. if (!string.Equals(state.InputContainer, "wtv", StringComparison.OrdinalIgnoreCase) + && !string.Equals(segmentFormat, "ts", StringComparison.OrdinalIgnoreCase) && state.TranscodingType != TranscodingJobType.Progressive && !state.EnableBreakOnNonKeyFrames(outputVideoCodec) && (state.BaseRequest.StartTimeTicks ?? 0) > 0) @@ -2695,6 +2715,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 +2744,10 @@ namespace MediaBrowser.Controller.MediaEncoding { outFormat = "nv12"; } + else if (isV4l2Encoder) + { + outFormat = "yuv420p"; + } // sw scale mainFilters.Add(swScaleFilter); @@ -2773,16 +2798,15 @@ namespace MediaBrowser.Controller.MediaEncoding var isSwDecoder = string.IsNullOrEmpty(vidDecoder); var isSwEncoder = !vidEncoder.Contains("nvenc", StringComparison.OrdinalIgnoreCase); - // legacy cuvid(resize/deint/sw) pipeline(copy-back) + // legacy cuvid pipeline(copy-back) if ((isSwDecoder && isSwEncoder) || !IsCudaFullSupported() - || !options.EnableEnhancedNvdecDecoder || !_mediaEncoder.SupportsFilter("alphasrc")) { return GetSwVidFilterChain(state, options, vidEncoder); } - // prefered nvdec + cuda filters + nvenc pipeline + // prefered nvdec/cuvid + cuda filters + nvenc pipeline return GetNvidiaVidFiltersPrefered(state, options, vidDecoder, vidEncoder); } @@ -2800,11 +2824,11 @@ namespace MediaBrowser.Controller.MediaEncoding var reqMaxH = state.BaseRequest.MaxHeight; var threeDFormat = state.MediaSource.Video3DFormat; - var isNvdecDecoder = vidDecoder.Contains("cuda", StringComparison.OrdinalIgnoreCase); + var isNvDecoder = vidDecoder.Contains("cuda", StringComparison.OrdinalIgnoreCase); var isNvencEncoder = vidEncoder.Contains("nvenc", StringComparison.OrdinalIgnoreCase); var isSwDecoder = string.IsNullOrEmpty(vidDecoder); var isSwEncoder = !isNvencEncoder; - var isCuInCuOut = isNvdecDecoder && isNvencEncoder; + var isCuInCuOut = isNvDecoder && isNvencEncoder; var doubleRateDeint = options.DeinterlaceDoubleRate && (state.VideoStream?.AverageFrameRate ?? 60) <= 30; var doDeintH264 = state.DeInterlace("h264", true) || state.DeInterlace("avc", true); @@ -2847,7 +2871,7 @@ namespace MediaBrowser.Controller.MediaEncoding } } - if (isNvdecDecoder) + if (isNvDecoder) { // INPUT cuda surface(vram) // hw deint @@ -2871,8 +2895,8 @@ namespace MediaBrowser.Controller.MediaEncoding } var memoryOutput = false; - var isUploadForOclTonemap = isSwDecoder && doCuTonemap; - if ((isNvdecDecoder && isSwEncoder) || isUploadForOclTonemap) + var isUploadForCuTonemap = isSwDecoder && doCuTonemap; + if ((isNvDecoder && isSwEncoder) || (isUploadForCuTonemap && hasSubs)) { memoryOutput = true; @@ -2882,7 +2906,7 @@ namespace MediaBrowser.Controller.MediaEncoding } // OUTPUT yuv420p surface(memory) - if (isSwDecoder && isNvencEncoder) + if (isSwDecoder && isNvencEncoder && !isUploadForCuTonemap) { memoryOutput = true; } @@ -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; @@ -4409,9 +4428,18 @@ namespace MediaBrowser.Controller.MediaEncoding // Nvidia cuda if (string.Equals(options.HardwareAccelerationType, "nvenc", StringComparison.OrdinalIgnoreCase)) { - if (options.EnableEnhancedNvdecDecoder && isCudaSupported && isCodecAvailable) + if (isCudaSupported && isCodecAvailable) { - return " -hwaccel cuda" + (outputHwSurface ? " -hwaccel_output_format cuda" : string.Empty) + (isAv1 ? " -c:v av1" : string.Empty); + if (options.EnableEnhancedNvdecDecoder) + { + // 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); + } + else + { + // cuvid decoder doesn't have threading issue. + return " -hwaccel cuda" + (outputHwSurface ? " -hwaccel_output_format cuda" : string.Empty); + } } } @@ -4521,9 +4549,7 @@ namespace MediaBrowser.Controller.MediaEncoding return null; } - var hwSurface = IsCudaFullSupported() - && options.EnableEnhancedNvdecDecoder - && _mediaEncoder.SupportsFilter("alphasrc"); + var hwSurface = IsCudaFullSupported() && _mediaEncoder.SupportsFilter("alphasrc"); var is8bitSwFormatsNvdec = string.Equals("yuv420p", videoStream.PixelFormat, StringComparison.OrdinalIgnoreCase); var is8_10bitSwFormatsNvdec = is8bitSwFormatsNvdec || string.Equals("yuv420p10le", videoStream.PixelFormat, StringComparison.OrdinalIgnoreCase); // TODO: add more 8/10/12bit and 4:4:4 formats for Nvdec after finishing the ffcheck tool @@ -4747,43 +4773,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> @@ -4848,7 +4837,7 @@ namespace MediaBrowser.Controller.MediaEncoding } } - public string GetInputModifier(EncodingJobInfo state, EncodingOptions encodingOptions) + public string GetInputModifier(EncodingJobInfo state, EncodingOptions encodingOptions, string segmentContainer) { var inputModifier = string.Empty; var probeSizeArgument = string.Empty; @@ -4884,7 +4873,7 @@ namespace MediaBrowser.Controller.MediaEncoding inputModifier = inputModifier.Trim(); - inputModifier += " " + GetFastSeekCommandLineParameter(state, encodingOptions); + inputModifier += " " + GetFastSeekCommandLineParameter(state, encodingOptions, segmentContainer); inputModifier = inputModifier.Trim(); if (state.InputProtocol == MediaProtocol.Rtsp) @@ -5191,13 +5180,13 @@ namespace MediaBrowser.Controller.MediaEncoding var threads = GetNumberOfThreads(state, encodingOptions, videoCodec); - var inputModifier = GetInputModifier(state, encodingOptions); + var inputModifier = GetInputModifier(state, encodingOptions, null); return string.Format( CultureInfo.InvariantCulture, "{0} {1}{2} {3} {4} -map_metadata -1 -map_chapters -1 -threads {5} {6}{7}{8} -y \"{9}\"", inputModifier, - GetInputArgument(state, encodingOptions), + GetInputArgument(state, encodingOptions, null), keyFrame, GetMapArgs(state), GetProgressiveVideoArguments(state, encodingOptions, videoCodec, defaultPreset), @@ -5379,13 +5368,13 @@ namespace MediaBrowser.Controller.MediaEncoding var threads = GetNumberOfThreads(state, encodingOptions, null); - var inputModifier = GetInputModifier(state, encodingOptions); + var inputModifier = GetInputModifier(state, encodingOptions, null); return string.Format( CultureInfo.InvariantCulture, "{0} {1}{7}{8} -threads {2}{3} {4} -id3v2_version 3 -write_id3v1 1{6} -y \"{5}\"", inputModifier, - GetInputArgument(state, encodingOptions), + GetInputArgument(state, encodingOptions, null), threads, " -vn", string.Join(' ', audioTranscodeParams), diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs b/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs index c4affa567..4f6743590 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs @@ -6,6 +6,7 @@ using System; using System.Collections.Generic; using System.Globalization; using System.Linq; +using System.Text.Json.Serialization; using Jellyfin.Data.Entities; using MediaBrowser.Model.Dlna; using MediaBrowser.Model.Drawing; @@ -23,7 +24,7 @@ namespace MediaBrowser.Controller.MediaEncoding public int? OutputAudioBitrate; public int? OutputAudioChannels; - private TranscodeReason[] _transcodeReasons = null; + private TranscodeReason? _transcodeReasons = null; public EncodingJobInfo(TranscodingJobType jobType) { @@ -34,25 +35,23 @@ namespace MediaBrowser.Controller.MediaEncoding SupportedSubtitleCodecs = Array.Empty<string>(); } - public TranscodeReason[] TranscodeReasons + public TranscodeReason TranscodeReason { get { - if (_transcodeReasons == null) + if (!_transcodeReasons.HasValue) { if (BaseRequest.TranscodeReasons == null) { - return Array.Empty<TranscodeReason>(); + _transcodeReasons = 0; + return 0; } - _transcodeReasons = BaseRequest.TranscodeReasons - .Split(',') - .Where(i => !string.IsNullOrEmpty(i)) - .Select(v => (TranscodeReason)Enum.Parse(typeof(TranscodeReason), v, true)) - .ToArray(); + _ = Enum.TryParse<TranscodeReason>(BaseRequest.TranscodeReasons, out var reason); + _transcodeReasons = reason; } - return _transcodeReasons; + return _transcodeReasons.Value; } } diff --git a/MediaBrowser.Controller/MediaEncoding/IAttachmentExtractor.cs b/MediaBrowser.Controller/MediaEncoding/IAttachmentExtractor.cs index 4e7e26624..09840d2ee 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,17 @@ namespace MediaBrowser.Controller.MediaEncoding string mediaSourceId, int attachmentStreamIndex, CancellationToken cancellationToken); + + Task ExtractAllAttachments( + string inputFile, + MediaSourceInfo mediaSource, + string outputPath, + CancellationToken cancellationToken); + + Task ExtractAllAttachmentsExternal( + string inputArgument, + string id, + string outputPath, + CancellationToken cancellationToken); } } diff --git a/MediaBrowser.Controller/Persistence/IItemRepository.cs b/MediaBrowser.Controller/Persistence/IItemRepository.cs index 837bf0bb2..24f7b5cd3 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 42f285076..000000000 --- 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 c43acfb6d..f2fb2826a 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/Playlists/Playlist.cs b/MediaBrowser.Controller/Playlists/Playlist.cs index 89f3bdf46..828ecb2c5 100644 --- a/MediaBrowser.Controller/Playlists/Playlist.cs +++ b/MediaBrowser.Controller/Playlists/Playlist.cs @@ -233,7 +233,7 @@ namespace MediaBrowser.Controller.Playlists return base.IsVisible(user); } - if (user.Id == OwnerUserId) + if (user.Id.Equals(OwnerUserId)) { return true; } @@ -244,8 +244,8 @@ namespace MediaBrowser.Controller.Playlists return base.IsVisible(user); } - var userId = user.Id.ToString("N", CultureInfo.InvariantCulture); - return shares.Any(share => string.Equals(share.UserId, userId, StringComparison.OrdinalIgnoreCase)); + var userId = user.Id; + return shares.Any(share => Guid.TryParse(share.UserId, out var id) && id.Equals(userId)); } public override bool IsVisibleStandalone(User user) diff --git a/MediaBrowser.Controller/Session/SessionInfo.cs b/MediaBrowser.Controller/Session/SessionInfo.cs index 6134c0cf3..c2ca23386 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; } |
