From 7fa6d4c81e9d1f22fd67a7cab2d70cba27d89275 Mon Sep 17 00:00:00 2001 From: Jpuc1143 Date: Thu, 19 Jan 2023 23:28:52 -0300 Subject: Add "Allowed Tags" to Parental Controls --- MediaBrowser.Controller/Entities/BaseItem.cs | 5 +++++ MediaBrowser.Controller/Entities/InternalItemsQuery.cs | 4 ++++ 2 files changed, 9 insertions(+) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index f2c2007f7a..0cd9720549 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -1607,6 +1607,11 @@ namespace MediaBrowser.Controller.Entities return false; } + if (user.GetPreference(PreferenceKind.AllowedTags).Any() && !user.GetPreference(PreferenceKind.AllowedTags).Any(i => Tags.Contains(i, StringComparison.OrdinalIgnoreCase))) + { + return false; + } + return true; } diff --git a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs index a1e5319048..a51299284b 100644 --- a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs +++ b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs @@ -26,6 +26,7 @@ namespace MediaBrowser.Controller.Entities EnableTotalRecordCount = true; ExcludeArtistIds = Array.Empty(); ExcludeInheritedTags = Array.Empty(); + IncludeInheritedTags = Array.Empty(); ExcludeItemIds = Array.Empty(); ExcludeItemTypes = Array.Empty(); ExcludeTags = Array.Empty(); @@ -95,6 +96,8 @@ namespace MediaBrowser.Controller.Entities public string[] ExcludeInheritedTags { get; set; } + public string[] IncludeInheritedTags { get; set; } + public IReadOnlyList Genres { get; set; } public bool? IsSpecialSeason { get; set; } @@ -368,6 +371,7 @@ namespace MediaBrowser.Controller.Entities } ExcludeInheritedTags = user.GetPreference(PreferenceKind.BlockedTags); + IncludeInheritedTags = user.GetPreference(PreferenceKind.AllowedTags); User = user; } -- cgit v1.2.3 From 4f81f4daaa77ac58381a95f1fd32fecd4e0a7d2b Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Fri, 27 Jan 2023 18:41:10 -0500 Subject: Use depencency injection for ISubtitleProvider --- Emby.Server.Implementations/ApplicationHost.cs | 2 -- MediaBrowser.Controller/Subtitles/ISubtitleManager.cs | 6 ------ MediaBrowser.Providers/Subtitles/SubtitleManager.cs | 16 ++++++---------- 3 files changed, 6 insertions(+), 18 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index 2e7386bf32..be4845c29a 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -728,8 +728,6 @@ namespace Emby.Server.Implementations Resolve().AddParts(GetExports(), GetExports(), GetExports()); - Resolve().AddParts(GetExports()); - Resolve().AddParts(GetExports()); Resolve().AddParts(GetExports()); diff --git a/MediaBrowser.Controller/Subtitles/ISubtitleManager.cs b/MediaBrowser.Controller/Subtitles/ISubtitleManager.cs index 52aa44024d..841b320376 100644 --- a/MediaBrowser.Controller/Subtitles/ISubtitleManager.cs +++ b/MediaBrowser.Controller/Subtitles/ISubtitleManager.cs @@ -19,12 +19,6 @@ namespace MediaBrowser.Controller.Subtitles /// event EventHandler SubtitleDownloadFailure; - /// - /// Adds the parts. - /// - /// The subtitle providers. - void AddParts(IEnumerable subtitleProviders); - /// /// Searches the subtitles. /// diff --git a/MediaBrowser.Providers/Subtitles/SubtitleManager.cs b/MediaBrowser.Providers/Subtitles/SubtitleManager.cs index b1a26cfba3..12570f0a7e 100644 --- a/MediaBrowser.Providers/Subtitles/SubtitleManager.cs +++ b/MediaBrowser.Providers/Subtitles/SubtitleManager.cs @@ -35,33 +35,29 @@ namespace MediaBrowser.Providers.Subtitles private readonly IMediaSourceManager _mediaSourceManager; private readonly ILocalizationManager _localization; - private ISubtitleProvider[] _subtitleProviders; + private readonly ISubtitleProvider[] _subtitleProviders; public SubtitleManager( ILogger logger, IFileSystem fileSystem, ILibraryMonitor monitor, IMediaSourceManager mediaSourceManager, - ILocalizationManager localizationManager) + ILocalizationManager localizationManager, + IEnumerable subtitleProviders) { _logger = logger; _fileSystem = fileSystem; _monitor = monitor; _mediaSourceManager = mediaSourceManager; _localization = localizationManager; - } - - /// - public event EventHandler SubtitleDownloadFailure; - - /// - public void AddParts(IEnumerable subtitleProviders) - { _subtitleProviders = subtitleProviders .OrderBy(i => i is IHasOrder hasOrder ? hasOrder.Order : 0) .ToArray(); } + /// + public event EventHandler SubtitleDownloadFailure; + /// public async Task SearchSubtitles(SubtitleSearchRequest request, CancellationToken cancellationToken) { -- cgit v1.2.3 From f7ec85d7a0d30619721d13064437993d2f3a86d4 Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Fri, 27 Jan 2023 18:46:54 -0500 Subject: Use dependency injection for IChannel --- Emby.Server.Implementations/ApplicationHost.cs | 2 -- Emby.Server.Implementations/Channels/ChannelManager.cs | 13 +++++-------- MediaBrowser.Controller/Channels/IChannelManager.cs | 6 ------ 3 files changed, 5 insertions(+), 16 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index be4845c29a..3527e40480 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -728,8 +728,6 @@ namespace Emby.Server.Implementations Resolve().AddParts(GetExports(), GetExports(), GetExports()); - Resolve().AddParts(GetExports()); - Resolve().AddParts(GetExports()); Resolve().AddParts(GetExports(), GetExports()); diff --git a/Emby.Server.Implementations/Channels/ChannelManager.cs b/Emby.Server.Implementations/Channels/ChannelManager.cs index 85ccbc0284..84ba194648 100644 --- a/Emby.Server.Implementations/Channels/ChannelManager.cs +++ b/Emby.Server.Implementations/Channels/ChannelManager.cs @@ -66,6 +66,7 @@ namespace Emby.Server.Implementations.Channels /// The user data manager. /// The provider manager. /// The memory cache. + /// The channels. public ChannelManager( IUserManager userManager, IDtoService dtoService, @@ -75,7 +76,8 @@ namespace Emby.Server.Implementations.Channels IFileSystem fileSystem, IUserDataManager userDataManager, IProviderManager providerManager, - IMemoryCache memoryCache) + IMemoryCache memoryCache, + IEnumerable channels) { _userManager = userManager; _dtoService = dtoService; @@ -86,18 +88,13 @@ namespace Emby.Server.Implementations.Channels _userDataManager = userDataManager; _providerManager = providerManager; _memoryCache = memoryCache; + Channels = channels.ToArray(); } - internal IChannel[] Channels { get; private set; } + internal IChannel[] Channels { get; } private static TimeSpan CacheLength => TimeSpan.FromHours(3); - /// - public void AddParts(IEnumerable channels) - { - Channels = channels.ToArray(); - } - /// public bool EnableMediaSourceDisplay(BaseItem item) { diff --git a/MediaBrowser.Controller/Channels/IChannelManager.cs b/MediaBrowser.Controller/Channels/IChannelManager.cs index 49be897ef3..e392a3493e 100644 --- a/MediaBrowser.Controller/Channels/IChannelManager.cs +++ b/MediaBrowser.Controller/Channels/IChannelManager.cs @@ -15,12 +15,6 @@ namespace MediaBrowser.Controller.Channels { public interface IChannelManager { - /// - /// Adds the parts. - /// - /// The channels. - void AddParts(IEnumerable channels); - /// /// Gets the channel features. /// -- cgit v1.2.3 From abffd160c304486e9efbb8007fbd71a7e9b84449 Mon Sep 17 00:00:00 2001 From: Cody Robibero Date: Sat, 28 Jan 2023 07:43:13 -0700 Subject: Remove ability to add a played indicator to images (#9186) --- Jellyfin.Api/Controllers/ImageController.cs | 45 --------- .../Drawing/ImageProcessingOptions.cs | 3 - MediaBrowser.Model/Dto/ImageOptions.cs | 111 --------------------- src/Jellyfin.Drawing.Skia/PlayedIndicatorDrawer.cs | 47 --------- src/Jellyfin.Drawing.Skia/SkiaEncoder.cs | 8 +- src/Jellyfin.Drawing/ImageProcessor.cs | 9 -- 6 files changed, 2 insertions(+), 221 deletions(-) delete mode 100644 MediaBrowser.Model/Dto/ImageOptions.cs delete mode 100644 src/Jellyfin.Drawing.Skia/PlayedIndicatorDrawer.cs (limited to 'MediaBrowser.Controller') diff --git a/Jellyfin.Api/Controllers/ImageController.cs b/Jellyfin.Api/Controllers/ImageController.cs index f866655c0b..996dc08196 100644 --- a/Jellyfin.Api/Controllers/ImageController.cs +++ b/Jellyfin.Api/Controllers/ImageController.cs @@ -505,7 +505,6 @@ namespace Jellyfin.Api.Controllers /// Optional. Supply the cache tag from the item object to receive strong caching headers. /// Optional. Specify if whitespace should be cropped out of the image. True/False. If unspecified, whitespace will be cropped from logos and clear art. /// Optional. The of the returned image. - /// Optional. Add a played indicator. /// Optional. Percent to render for the percent played overlay. /// Optional. Unplayed count overlay to render. /// Optional. Blur image. @@ -536,7 +535,6 @@ namespace Jellyfin.Api.Controllers [FromQuery] string? tag, [FromQuery, ParameterObsolete] bool? cropWhitespace, [FromQuery] ImageFormat? format, - [FromQuery] bool? addPlayedIndicator, [FromQuery] double? percentPlayed, [FromQuery] int? unplayedCount, [FromQuery] int? blur, @@ -565,7 +563,6 @@ namespace Jellyfin.Api.Controllers quality, fillWidth, fillHeight, - addPlayedIndicator, blur, backgroundColor, foregroundLayer, @@ -589,7 +586,6 @@ namespace Jellyfin.Api.Controllers /// Optional. Supply the cache tag from the item object to receive strong caching headers. /// Optional. Specify if whitespace should be cropped out of the image. True/False. If unspecified, whitespace will be cropped from logos and clear art. /// Optional. The of the returned image. - /// Optional. Add a played indicator. /// Optional. Percent to render for the percent played overlay. /// Optional. Unplayed count overlay to render. /// Optional. Blur image. @@ -620,7 +616,6 @@ namespace Jellyfin.Api.Controllers [FromQuery] string? tag, [FromQuery, ParameterObsolete] bool? cropWhitespace, [FromQuery] ImageFormat? format, - [FromQuery] bool? addPlayedIndicator, [FromQuery] double? percentPlayed, [FromQuery] int? unplayedCount, [FromQuery] int? blur, @@ -648,7 +643,6 @@ namespace Jellyfin.Api.Controllers quality, fillWidth, fillHeight, - addPlayedIndicator, blur, backgroundColor, foregroundLayer, @@ -671,7 +665,6 @@ namespace Jellyfin.Api.Controllers /// Optional. Supply the cache tag from the item object to receive strong caching headers. /// Optional. Specify if whitespace should be cropped out of the image. True/False. If unspecified, whitespace will be cropped from logos and clear art. /// Determines the output format of the image - original,gif,jpg,png. - /// Optional. Add a played indicator. /// Optional. Percent to render for the percent played overlay. /// Optional. Unplayed count overlay to render. /// Optional. Blur image. @@ -702,7 +695,6 @@ namespace Jellyfin.Api.Controllers [FromRoute, Required] string tag, [FromQuery, ParameterObsolete] bool? cropWhitespace, [FromRoute, Required] ImageFormat format, - [FromQuery] bool? addPlayedIndicator, [FromRoute, Required] double percentPlayed, [FromRoute, Required] int unplayedCount, [FromQuery] int? blur, @@ -731,7 +723,6 @@ namespace Jellyfin.Api.Controllers quality, fillWidth, fillHeight, - addPlayedIndicator, blur, backgroundColor, foregroundLayer, @@ -756,7 +747,6 @@ namespace Jellyfin.Api.Controllers /// Width of box to fill. /// Height of box to fill. /// Optional. Specify if whitespace should be cropped out of the image. True/False. If unspecified, whitespace will be cropped from logos and clear art. - /// Optional. Add a played indicator. /// Optional. Blur image. /// Optional. Apply a background color for transparent images. /// Optional. Apply a foreground layer on top of the image. @@ -787,7 +777,6 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? fillWidth, [FromQuery] int? fillHeight, [FromQuery, ParameterObsolete] bool? cropWhitespace, - [FromQuery] bool? addPlayedIndicator, [FromQuery] int? blur, [FromQuery] string? backgroundColor, [FromQuery] string? foregroundLayer, @@ -814,7 +803,6 @@ namespace Jellyfin.Api.Controllers quality, fillWidth, fillHeight, - addPlayedIndicator, blur, backgroundColor, foregroundLayer, @@ -839,7 +827,6 @@ namespace Jellyfin.Api.Controllers /// Width of box to fill. /// Height of box to fill. /// Optional. Specify if whitespace should be cropped out of the image. True/False. If unspecified, whitespace will be cropped from logos and clear art. - /// Optional. Add a played indicator. /// Optional. Blur image. /// Optional. Apply a background color for transparent images. /// Optional. Apply a foreground layer on top of the image. @@ -870,7 +857,6 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? fillWidth, [FromQuery] int? fillHeight, [FromQuery, ParameterObsolete] bool? cropWhitespace, - [FromQuery] bool? addPlayedIndicator, [FromQuery] int? blur, [FromQuery] string? backgroundColor, [FromQuery] string? foregroundLayer, @@ -897,7 +883,6 @@ namespace Jellyfin.Api.Controllers quality, fillWidth, fillHeight, - addPlayedIndicator, blur, backgroundColor, foregroundLayer, @@ -923,7 +908,6 @@ namespace Jellyfin.Api.Controllers /// Width of box to fill. /// Height of box to fill. /// Optional. Specify if whitespace should be cropped out of the image. True/False. If unspecified, whitespace will be cropped from logos and clear art. - /// Optional. Add a played indicator. /// Optional. Blur image. /// Optional. Apply a background color for transparent images. /// Optional. Apply a foreground layer on top of the image. @@ -954,7 +938,6 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? fillWidth, [FromQuery] int? fillHeight, [FromQuery, ParameterObsolete] bool? cropWhitespace, - [FromQuery] bool? addPlayedIndicator, [FromQuery] int? blur, [FromQuery] string? backgroundColor, [FromQuery] string? foregroundLayer) @@ -980,7 +963,6 @@ namespace Jellyfin.Api.Controllers quality, fillWidth, fillHeight, - addPlayedIndicator, blur, backgroundColor, foregroundLayer, @@ -1005,7 +987,6 @@ namespace Jellyfin.Api.Controllers /// Width of box to fill. /// Height of box to fill. /// Optional. Specify if whitespace should be cropped out of the image. True/False. If unspecified, whitespace will be cropped from logos and clear art. - /// Optional. Add a played indicator. /// Optional. Blur image. /// Optional. Apply a background color for transparent images. /// Optional. Apply a foreground layer on top of the image. @@ -1036,7 +1017,6 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? fillWidth, [FromQuery] int? fillHeight, [FromQuery, ParameterObsolete] bool? cropWhitespace, - [FromQuery] bool? addPlayedIndicator, [FromQuery] int? blur, [FromQuery] string? backgroundColor, [FromQuery] string? foregroundLayer, @@ -1063,7 +1043,6 @@ namespace Jellyfin.Api.Controllers quality, fillWidth, fillHeight, - addPlayedIndicator, blur, backgroundColor, foregroundLayer, @@ -1089,7 +1068,6 @@ namespace Jellyfin.Api.Controllers /// Width of box to fill. /// Height of box to fill. /// Optional. Specify if whitespace should be cropped out of the image. True/False. If unspecified, whitespace will be cropped from logos and clear art. - /// Optional. Add a played indicator. /// Optional. Blur image. /// Optional. Apply a background color for transparent images. /// Optional. Apply a foreground layer on top of the image. @@ -1120,7 +1098,6 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? fillWidth, [FromQuery] int? fillHeight, [FromQuery, ParameterObsolete] bool? cropWhitespace, - [FromQuery] bool? addPlayedIndicator, [FromQuery] int? blur, [FromQuery] string? backgroundColor, [FromQuery] string? foregroundLayer) @@ -1146,7 +1123,6 @@ namespace Jellyfin.Api.Controllers quality, fillWidth, fillHeight, - addPlayedIndicator, blur, backgroundColor, foregroundLayer, @@ -1171,7 +1147,6 @@ namespace Jellyfin.Api.Controllers /// Width of box to fill. /// Height of box to fill. /// Optional. Specify if whitespace should be cropped out of the image. True/False. If unspecified, whitespace will be cropped from logos and clear art. - /// Optional. Add a played indicator. /// Optional. Blur image. /// Optional. Apply a background color for transparent images. /// Optional. Apply a foreground layer on top of the image. @@ -1202,7 +1177,6 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? fillWidth, [FromQuery] int? fillHeight, [FromQuery, ParameterObsolete] bool? cropWhitespace, - [FromQuery] bool? addPlayedIndicator, [FromQuery] int? blur, [FromQuery] string? backgroundColor, [FromQuery] string? foregroundLayer, @@ -1229,7 +1203,6 @@ namespace Jellyfin.Api.Controllers quality, fillWidth, fillHeight, - addPlayedIndicator, blur, backgroundColor, foregroundLayer, @@ -1255,7 +1228,6 @@ namespace Jellyfin.Api.Controllers /// Width of box to fill. /// Height of box to fill. /// Optional. Specify if whitespace should be cropped out of the image. True/False. If unspecified, whitespace will be cropped from logos and clear art. - /// Optional. Add a played indicator. /// Optional. Blur image. /// Optional. Apply a background color for transparent images. /// Optional. Apply a foreground layer on top of the image. @@ -1286,7 +1258,6 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? fillWidth, [FromQuery] int? fillHeight, [FromQuery, ParameterObsolete] bool? cropWhitespace, - [FromQuery] bool? addPlayedIndicator, [FromQuery] int? blur, [FromQuery] string? backgroundColor, [FromQuery] string? foregroundLayer) @@ -1312,7 +1283,6 @@ namespace Jellyfin.Api.Controllers quality, fillWidth, fillHeight, - addPlayedIndicator, blur, backgroundColor, foregroundLayer, @@ -1337,7 +1307,6 @@ namespace Jellyfin.Api.Controllers /// Width of box to fill. /// Height of box to fill. /// Optional. Specify if whitespace should be cropped out of the image. True/False. If unspecified, whitespace will be cropped from logos and clear art. - /// Optional. Add a played indicator. /// Optional. Blur image. /// Optional. Apply a background color for transparent images. /// Optional. Apply a foreground layer on top of the image. @@ -1368,7 +1337,6 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? fillWidth, [FromQuery] int? fillHeight, [FromQuery, ParameterObsolete] bool? cropWhitespace, - [FromQuery] bool? addPlayedIndicator, [FromQuery] int? blur, [FromQuery] string? backgroundColor, [FromQuery] string? foregroundLayer, @@ -1395,7 +1363,6 @@ namespace Jellyfin.Api.Controllers quality, fillWidth, fillHeight, - addPlayedIndicator, blur, backgroundColor, foregroundLayer, @@ -1421,7 +1388,6 @@ namespace Jellyfin.Api.Controllers /// Width of box to fill. /// Height of box to fill. /// Optional. Specify if whitespace should be cropped out of the image. True/False. If unspecified, whitespace will be cropped from logos and clear art. - /// Optional. Add a played indicator. /// Optional. Blur image. /// Optional. Apply a background color for transparent images. /// Optional. Apply a foreground layer on top of the image. @@ -1452,7 +1418,6 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? fillWidth, [FromQuery] int? fillHeight, [FromQuery, ParameterObsolete] bool? cropWhitespace, - [FromQuery] bool? addPlayedIndicator, [FromQuery] int? blur, [FromQuery] string? backgroundColor, [FromQuery] string? foregroundLayer) @@ -1478,7 +1443,6 @@ namespace Jellyfin.Api.Controllers quality, fillWidth, fillHeight, - addPlayedIndicator, blur, backgroundColor, foregroundLayer, @@ -1503,7 +1467,6 @@ namespace Jellyfin.Api.Controllers /// Width of box to fill. /// Height of box to fill. /// Optional. Specify if whitespace should be cropped out of the image. True/False. If unspecified, whitespace will be cropped from logos and clear art. - /// Optional. Add a played indicator. /// Optional. Blur image. /// Optional. Apply a background color for transparent images. /// Optional. Apply a foreground layer on top of the image. @@ -1534,7 +1497,6 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? fillWidth, [FromQuery] int? fillHeight, [FromQuery, ParameterObsolete] bool? cropWhitespace, - [FromQuery] bool? addPlayedIndicator, [FromQuery] int? blur, [FromQuery] string? backgroundColor, [FromQuery] string? foregroundLayer, @@ -1578,7 +1540,6 @@ namespace Jellyfin.Api.Controllers quality, fillWidth, fillHeight, - addPlayedIndicator, blur, backgroundColor, foregroundLayer, @@ -1605,7 +1566,6 @@ namespace Jellyfin.Api.Controllers /// Width of box to fill. /// Height of box to fill. /// Optional. Specify if whitespace should be cropped out of the image. True/False. If unspecified, whitespace will be cropped from logos and clear art. - /// Optional. Add a played indicator. /// Optional. Blur image. /// Optional. Apply a background color for transparent images. /// Optional. Apply a foreground layer on top of the image. @@ -1636,7 +1596,6 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? fillWidth, [FromQuery] int? fillHeight, [FromQuery, ParameterObsolete] bool? cropWhitespace, - [FromQuery] bool? addPlayedIndicator, [FromQuery] int? blur, [FromQuery] string? backgroundColor, [FromQuery] string? foregroundLayer) @@ -1679,7 +1638,6 @@ namespace Jellyfin.Api.Controllers quality, fillWidth, fillHeight, - addPlayedIndicator, blur, backgroundColor, foregroundLayer, @@ -1924,7 +1882,6 @@ namespace Jellyfin.Api.Controllers int? quality, int? fillWidth, int? fillHeight, - bool? addPlayedIndicator, int? blur, string? backgroundColor, string? foregroundLayer, @@ -1940,7 +1897,6 @@ namespace Jellyfin.Api.Controllers else if (percentPlayed.Value >= 100) { percentPlayed = null; - addPlayedIndicator = true; } } @@ -1997,7 +1953,6 @@ namespace Jellyfin.Api.Controllers FillWidth = fillWidth, Quality = quality ?? 100, Width = width, - AddPlayedIndicator = addPlayedIndicator ?? false, PercentPlayed = percentPlayed ?? 0, UnplayedCount = unplayedCount, Blur = blur, diff --git a/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs b/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs index 11e6633011..7912c5e87e 100644 --- a/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs +++ b/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs @@ -42,8 +42,6 @@ namespace MediaBrowser.Controller.Drawing public IReadOnlyCollection SupportedOutputFormats { get; set; } - public bool AddPlayedIndicator { get; set; } - public int? UnplayedCount { get; set; } public int? Blur { get; set; } @@ -111,7 +109,6 @@ namespace MediaBrowser.Controller.Drawing { return (Quality >= 90) && IsFormatSupported(originalImagePath) && - !AddPlayedIndicator && PercentPlayed.Equals(0) && !UnplayedCount.HasValue && !Blur.HasValue && diff --git a/MediaBrowser.Model/Dto/ImageOptions.cs b/MediaBrowser.Model/Dto/ImageOptions.cs deleted file mode 100644 index 3f4405f1e5..0000000000 --- a/MediaBrowser.Model/Dto/ImageOptions.cs +++ /dev/null @@ -1,111 +0,0 @@ -#nullable disable -using MediaBrowser.Model.Drawing; -using MediaBrowser.Model.Entities; - -namespace MediaBrowser.Model.Dto -{ - /// - /// Class ImageOptions. - /// - public class ImageOptions - { - /// - /// Initializes a new instance of the class. - /// - public ImageOptions() - { - EnableImageEnhancers = true; - } - - /// - /// Gets or sets the type of the image. - /// - /// The type of the image. - public ImageType ImageType { get; set; } - - /// - /// Gets or sets the index of the image. - /// - /// The index of the image. - public int? ImageIndex { get; set; } - - /// - /// Gets or sets the width. - /// - /// The width. - public int? Width { get; set; } - - /// - /// Gets or sets the height. - /// - /// The height. - public int? Height { get; set; } - - /// - /// Gets or sets the width of the max. - /// - /// The width of the max. - public int? MaxWidth { get; set; } - - /// - /// Gets or sets the height of the max. - /// - /// The height of the max. - public int? MaxHeight { get; set; } - - /// - /// Gets or sets the quality. - /// - /// The quality. - public int? Quality { get; set; } - - /// - /// Gets or sets the image tag. - /// If set this will result in strong, unconditional response caching. - /// - /// The hash. - public string Tag { get; set; } - - /// - /// Gets or sets a value indicating whether [crop whitespace]. - /// - /// null if [crop whitespace] contains no value, true if [crop whitespace]; otherwise, false. - public bool? CropWhitespace { get; set; } - - /// - /// Gets or sets a value indicating whether [enable image enhancers]. - /// - /// true if [enable image enhancers]; otherwise, false. - public bool EnableImageEnhancers { get; set; } - - /// - /// Gets or sets the format. - /// - /// The format. - public ImageFormat? Format { get; set; } - - /// - /// Gets or sets a value indicating whether [add played indicator]. - /// - /// true if [add played indicator]; otherwise, false. - public bool AddPlayedIndicator { get; set; } - - /// - /// Gets or sets the percent played. - /// - /// The percent played. - public int? PercentPlayed { get; set; } - - /// - /// Gets or sets the un played count. - /// - /// The un played count. - public int? UnPlayedCount { get; set; } - - /// - /// Gets or sets the color of the background. - /// - /// The color of the background. - public string BackgroundColor { get; set; } - } -} diff --git a/src/Jellyfin.Drawing.Skia/PlayedIndicatorDrawer.cs b/src/Jellyfin.Drawing.Skia/PlayedIndicatorDrawer.cs deleted file mode 100644 index 5bb42fb99e..0000000000 --- a/src/Jellyfin.Drawing.Skia/PlayedIndicatorDrawer.cs +++ /dev/null @@ -1,47 +0,0 @@ -using MediaBrowser.Model.Drawing; -using SkiaSharp; - -namespace Jellyfin.Drawing.Skia; - -/// -/// Static helper class for drawing 'played' indicators. -/// -public static class PlayedIndicatorDrawer -{ - private const int OffsetFromTopRightCorner = 38; - - /// - /// Draw a 'played' indicator in the top right corner of a canvas. - /// - /// The canvas to draw the indicator on. - /// - /// The dimensions of the image to draw the indicator on. The width is used to determine the x-position of the - /// indicator. - /// - public static void DrawPlayedIndicator(SKCanvas canvas, ImageDimensions imageSize) - { - var x = imageSize.Width - OffsetFromTopRightCorner; - - using var paint = new SKPaint - { - Color = SKColor.Parse("#CC00A4DC"), - Style = SKPaintStyle.Fill - }; - - canvas.DrawCircle(x, OffsetFromTopRightCorner, 20, paint); - - paint.Color = new SKColor(255, 255, 255, 255); - paint.TextSize = 30; - paint.IsAntialias = true; - - // or: - // var emojiChar = 0x1F680; - const string Text = "✔️"; - var emojiChar = StringUtilities.GetUnicodeCharacterCode(Text, SKTextEncoding.Utf32); - - // ask the font manager for a font with that character - paint.Typeface = SKFontManager.Default.MatchCharacter(emojiChar); - - canvas.DrawText(Text, (float)x - 12, OffsetFromTopRightCorner + 12, paint); - } -} diff --git a/src/Jellyfin.Drawing.Skia/SkiaEncoder.cs b/src/Jellyfin.Drawing.Skia/SkiaEncoder.cs index ddb8a98d4d..6da77ad959 100644 --- a/src/Jellyfin.Drawing.Skia/SkiaEncoder.cs +++ b/src/Jellyfin.Drawing.Skia/SkiaEncoder.cs @@ -399,7 +399,7 @@ public class SkiaEncoder : IImageEncoder var hasBackgroundColor = !string.IsNullOrWhiteSpace(options.BackgroundColor); var hasForegroundColor = !string.IsNullOrWhiteSpace(options.ForegroundLayer); var blur = options.Blur ?? 0; - var hasIndicator = options.AddPlayedIndicator || options.UnplayedCount.HasValue || !options.PercentPlayed.Equals(0); + var hasIndicator = options.UnplayedCount.HasValue || !options.PercentPlayed.Equals(0); using var bitmap = GetBitmap(inputPath, autoOrient, orientation); if (bitmap is null) @@ -522,11 +522,7 @@ public class SkiaEncoder : IImageEncoder { var currentImageSize = new ImageDimensions(imageWidth, imageHeight); - if (options.AddPlayedIndicator) - { - PlayedIndicatorDrawer.DrawPlayedIndicator(canvas, currentImageSize); - } - else if (options.UnplayedCount.HasValue) + if (options.UnplayedCount.HasValue) { UnplayedCountIndicator.DrawUnplayedCountIndicator(canvas, currentImageSize, options.UnplayedCount.Value); } diff --git a/src/Jellyfin.Drawing/ImageProcessor.cs b/src/Jellyfin.Drawing/ImageProcessor.cs index 353a27b254..533baba4fa 100644 --- a/src/Jellyfin.Drawing/ImageProcessor.cs +++ b/src/Jellyfin.Drawing/ImageProcessor.cs @@ -38,7 +38,6 @@ public sealed class ImageProcessor : IImageProcessor, IDisposable private readonly IFileSystem _fileSystem; private readonly IServerApplicationPaths _appPaths; private readonly IImageEncoder _imageEncoder; - private readonly IMediaEncoder _mediaEncoder; private readonly SemaphoreSlim _parallelEncodingLimit; @@ -64,7 +63,6 @@ public sealed class ImageProcessor : IImageProcessor, IDisposable _logger = logger; _fileSystem = fileSystem; _imageEncoder = imageEncoder; - _mediaEncoder = mediaEncoder; _appPaths = appPaths; var semaphoreCount = config.Configuration.ParallelImageEncodingLimit; @@ -202,7 +200,6 @@ public sealed class ImageProcessor : IImageProcessor, IDisposable quality, dateModified, outputFormat, - options.AddPlayedIndicator, options.PercentPlayed, options.UnplayedCount, options.Blur, @@ -295,7 +292,6 @@ public sealed class ImageProcessor : IImageProcessor, IDisposable int quality, DateTime dateModified, ImageFormat format, - bool addPlayedIndicator, double percentPlayed, int? unwatchedCount, int? blur, @@ -350,11 +346,6 @@ public sealed class ImageProcessor : IImageProcessor, IDisposable filename.Append(fillHeight.Value); } - if (addPlayedIndicator) - { - filename.Append(",pl=true"); - } - if (percentPlayed > 0) { filename.Append(",p="); -- cgit v1.2.3 From fec23de427fe1c46e4ce1aaf31f1695c90232059 Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Sat, 28 Jan 2023 09:43:55 -0500 Subject: Remove Emby.Notifications (#9147) --- Emby.Notifications/CoreNotificationTypes.cs | 123 -------- Emby.Notifications/Emby.Notifications.csproj | 35 --- .../NotificationConfigurationFactory.cs | 23 -- Emby.Notifications/NotificationEntryPoint.cs | 314 --------------------- Emby.Notifications/NotificationManager.cs | 224 --------------- Emby.Notifications/Properties/AssemblyInfo.cs | 21 -- Emby.Server.Implementations/ApplicationHost.cs | 9 - .../Emby.Server.Implementations.csproj | 1 - .../Controllers/NotificationsController.cs | 53 ---- Jellyfin.sln | 6 - .../Notifications/INotificationManager.cs | 43 --- .../Notifications/INotificationService.cs | 34 --- .../Notifications/INotificationTypeFactory.cs | 16 -- .../Notifications/UserNotification.cs | 25 -- .../Notifications/NotificationLevel.cs | 11 - .../Notifications/NotificationOption.cs | 55 ---- .../Notifications/NotificationOptions.cs | 131 --------- .../Notifications/NotificationRequest.cs | 35 --- .../Notifications/NotificationTypeInfo.cs | 18 -- MediaBrowser.Model/Notifications/SendToUserType.cs | 11 - 20 files changed, 1188 deletions(-) delete mode 100644 Emby.Notifications/CoreNotificationTypes.cs delete mode 100644 Emby.Notifications/Emby.Notifications.csproj delete mode 100644 Emby.Notifications/NotificationConfigurationFactory.cs delete mode 100644 Emby.Notifications/NotificationEntryPoint.cs delete mode 100644 Emby.Notifications/NotificationManager.cs delete mode 100644 Emby.Notifications/Properties/AssemblyInfo.cs delete mode 100644 Jellyfin.Api/Controllers/NotificationsController.cs delete mode 100644 MediaBrowser.Controller/Notifications/INotificationManager.cs delete mode 100644 MediaBrowser.Controller/Notifications/INotificationService.cs delete mode 100644 MediaBrowser.Controller/Notifications/INotificationTypeFactory.cs delete mode 100644 MediaBrowser.Controller/Notifications/UserNotification.cs delete mode 100644 MediaBrowser.Model/Notifications/NotificationLevel.cs delete mode 100644 MediaBrowser.Model/Notifications/NotificationOption.cs delete mode 100644 MediaBrowser.Model/Notifications/NotificationOptions.cs delete mode 100644 MediaBrowser.Model/Notifications/NotificationRequest.cs delete mode 100644 MediaBrowser.Model/Notifications/NotificationTypeInfo.cs delete mode 100644 MediaBrowser.Model/Notifications/SendToUserType.cs (limited to 'MediaBrowser.Controller') diff --git a/Emby.Notifications/CoreNotificationTypes.cs b/Emby.Notifications/CoreNotificationTypes.cs deleted file mode 100644 index 35aac3a11c..0000000000 --- a/Emby.Notifications/CoreNotificationTypes.cs +++ /dev/null @@ -1,123 +0,0 @@ -#pragma warning disable CS1591 - -using System; -using System.Collections.Generic; -using System.Linq; -using MediaBrowser.Controller.Notifications; -using MediaBrowser.Model.Globalization; -using MediaBrowser.Model.Notifications; - -namespace Emby.Notifications -{ - public class CoreNotificationTypes : INotificationTypeFactory - { - private readonly ILocalizationManager _localization; - - public CoreNotificationTypes(ILocalizationManager localization) - { - _localization = localization; - } - - public IEnumerable GetNotificationTypes() - { - var knownTypes = new NotificationTypeInfo[] - { - new NotificationTypeInfo - { - Type = nameof(NotificationType.ApplicationUpdateInstalled) - }, - new NotificationTypeInfo - { - Type = nameof(NotificationType.InstallationFailed) - }, - new NotificationTypeInfo - { - Type = nameof(NotificationType.PluginInstalled) - }, - new NotificationTypeInfo - { - Type = nameof(NotificationType.PluginError) - }, - new NotificationTypeInfo - { - Type = nameof(NotificationType.PluginUninstalled) - }, - new NotificationTypeInfo - { - Type = nameof(NotificationType.PluginUpdateInstalled) - }, - new NotificationTypeInfo - { - Type = nameof(NotificationType.ServerRestartRequired) - }, - new NotificationTypeInfo - { - Type = nameof(NotificationType.TaskFailed) - }, - new NotificationTypeInfo - { - Type = nameof(NotificationType.NewLibraryContent) - }, - new NotificationTypeInfo - { - Type = nameof(NotificationType.AudioPlayback) - }, - new NotificationTypeInfo - { - Type = nameof(NotificationType.VideoPlayback) - }, - new NotificationTypeInfo - { - Type = nameof(NotificationType.AudioPlaybackStopped) - }, - new NotificationTypeInfo - { - Type = nameof(NotificationType.VideoPlaybackStopped) - }, - new NotificationTypeInfo - { - Type = nameof(NotificationType.UserLockedOut) - }, - new NotificationTypeInfo - { - Type = nameof(NotificationType.ApplicationUpdateAvailable) - } - }; - - foreach (var type in knownTypes) - { - Update(type); - } - - var systemName = _localization.GetLocalizedString("System"); - - return knownTypes.OrderByDescending(i => string.Equals(i.Category, systemName, StringComparison.OrdinalIgnoreCase)) - .ThenBy(i => i.Category) - .ThenBy(i => i.Name); - } - - private void Update(NotificationTypeInfo note) - { - note.Name = _localization.GetLocalizedString("NotificationOption" + note.Type); - - note.IsBasedOnUserEvent = note.Type.IndexOf("Playback", StringComparison.OrdinalIgnoreCase) != -1; - - if (note.Type.IndexOf("Playback", StringComparison.OrdinalIgnoreCase) != -1) - { - note.Category = _localization.GetLocalizedString("User"); - } - else if (note.Type.IndexOf("Plugin", StringComparison.OrdinalIgnoreCase) != -1) - { - note.Category = _localization.GetLocalizedString("Plugin"); - } - else if (note.Type.IndexOf("UserLockedOut", StringComparison.OrdinalIgnoreCase) != -1) - { - note.Category = _localization.GetLocalizedString("User"); - } - else - { - note.Category = _localization.GetLocalizedString("System"); - } - } - } -} diff --git a/Emby.Notifications/Emby.Notifications.csproj b/Emby.Notifications/Emby.Notifications.csproj deleted file mode 100644 index eb269183e9..0000000000 --- a/Emby.Notifications/Emby.Notifications.csproj +++ /dev/null @@ -1,35 +0,0 @@ - - - - - {2E030C33-6923-4530-9E54-FA29FA6AD1A9} - - - - net7.0 - false - true - - - - - - - - - - - - - - - - all - runtime; build; native; contentfiles; analyzers - - - - - - - diff --git a/Emby.Notifications/NotificationConfigurationFactory.cs b/Emby.Notifications/NotificationConfigurationFactory.cs deleted file mode 100644 index 3fb3553d0e..0000000000 --- a/Emby.Notifications/NotificationConfigurationFactory.cs +++ /dev/null @@ -1,23 +0,0 @@ -#pragma warning disable CS1591 - -using System.Collections.Generic; -using MediaBrowser.Common.Configuration; -using MediaBrowser.Model.Notifications; - -namespace Emby.Notifications -{ - public class NotificationConfigurationFactory : IConfigurationFactory - { - public IEnumerable GetConfigurations() - { - return new ConfigurationStore[] - { - new ConfigurationStore - { - Key = "notifications", - ConfigurationType = typeof(NotificationOptions) - } - }; - } - } -} diff --git a/Emby.Notifications/NotificationEntryPoint.cs b/Emby.Notifications/NotificationEntryPoint.cs deleted file mode 100644 index 3763b1e922..0000000000 --- a/Emby.Notifications/NotificationEntryPoint.cs +++ /dev/null @@ -1,314 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using Jellyfin.Data.Events; -using Jellyfin.Extensions; -using MediaBrowser.Common.Configuration; -using MediaBrowser.Controller; -using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Entities.Audio; -using MediaBrowser.Controller.Entities.TV; -using MediaBrowser.Controller.Library; -using MediaBrowser.Controller.Notifications; -using MediaBrowser.Controller.Plugins; -using MediaBrowser.Model.Activity; -using MediaBrowser.Model.Globalization; -using MediaBrowser.Model.Notifications; -using Microsoft.Extensions.Logging; - -namespace Emby.Notifications -{ - /// - /// Creates notifications for various system events. - /// - public class NotificationEntryPoint : IServerEntryPoint - { - private readonly ILogger _logger; - private readonly IActivityManager _activityManager; - private readonly ILocalizationManager _localization; - private readonly INotificationManager _notificationManager; - private readonly ILibraryManager _libraryManager; - private readonly IServerApplicationHost _appHost; - private readonly IConfigurationManager _config; - - private readonly object _libraryChangedSyncLock = new object(); - private readonly List _itemsAdded = new List(); - - private Timer? _libraryUpdateTimer; - - private string[] _coreNotificationTypes; - - private bool _disposed = false; - - /// - /// Initializes a new instance of the class. - /// - /// The logger. - /// The activity manager. - /// The localization manager. - /// The notification manager. - /// The library manager. - /// The application host. - /// The configuration manager. - public NotificationEntryPoint( - ILogger logger, - IActivityManager activityManager, - ILocalizationManager localization, - INotificationManager notificationManager, - ILibraryManager libraryManager, - IServerApplicationHost appHost, - IConfigurationManager config) - { - _logger = logger; - _activityManager = activityManager; - _localization = localization; - _notificationManager = notificationManager; - _libraryManager = libraryManager; - _appHost = appHost; - _config = config; - - _coreNotificationTypes = new CoreNotificationTypes(localization).GetNotificationTypes().Select(i => i.Type).ToArray(); - } - - /// - public Task RunAsync() - { - _libraryManager.ItemAdded += OnLibraryManagerItemAdded; - _appHost.HasPendingRestartChanged += OnAppHostHasPendingRestartChanged; - _activityManager.EntryCreated += OnActivityManagerEntryCreated; - - return Task.CompletedTask; - } - - private async void OnAppHostHasPendingRestartChanged(object? sender, EventArgs e) - { - var type = NotificationType.ServerRestartRequired.ToString(); - - var notification = new NotificationRequest - { - NotificationType = type, - Name = string.Format( - CultureInfo.InvariantCulture, - _localization.GetLocalizedString("ServerNameNeedsToBeRestarted"), - _appHost.Name) - }; - - await SendNotification(notification, null).ConfigureAwait(false); - } - - private async void OnActivityManagerEntryCreated(object? sender, GenericEventArgs e) - { - var entry = e.Argument; - - var type = entry.Type; - - if (string.IsNullOrEmpty(type) || !_coreNotificationTypes.Contains(type, StringComparison.OrdinalIgnoreCase)) - { - return; - } - - var userId = e.Argument.UserId; - - if (!userId.Equals(default) && !GetOptions().IsEnabledToMonitorUser(type, userId)) - { - return; - } - - var notification = new NotificationRequest - { - NotificationType = type, - Name = entry.Name, - Description = entry.Overview - }; - - await SendNotification(notification, null).ConfigureAwait(false); - } - - private NotificationOptions GetOptions() - { - return _config.GetConfiguration("notifications"); - } - - private void OnLibraryManagerItemAdded(object? sender, ItemChangeEventArgs e) - { - if (!FilterItem(e.Item)) - { - return; - } - - lock (_libraryChangedSyncLock) - { - if (_libraryUpdateTimer is null) - { - _libraryUpdateTimer = new Timer( - LibraryUpdateTimerCallback, - null, - 5000, - Timeout.Infinite); - } - else - { - _libraryUpdateTimer.Change(5000, Timeout.Infinite); - } - - _itemsAdded.Add(e.Item); - } - } - - private bool FilterItem(BaseItem item) - { - if (item.IsFolder) - { - return false; - } - - if (!item.HasPathProtocol) - { - return false; - } - - if (item is IItemByName) - { - return false; - } - - return item.SourceType == SourceType.Library; - } - - private async void LibraryUpdateTimerCallback(object? state) - { - List items; - - lock (_libraryChangedSyncLock) - { - items = _itemsAdded.ToList(); - _itemsAdded.Clear(); - _libraryUpdateTimer!.Dispose(); // Shouldn't be null as it just set off this callback - _libraryUpdateTimer = null; - } - - if (items.Count > 10) - { - items = items.GetRange(0, 10); - } - - foreach (var item in items) - { - var notification = new NotificationRequest - { - NotificationType = NotificationType.NewLibraryContent.ToString(), - Name = string.Format( - CultureInfo.InvariantCulture, - _localization.GetLocalizedString("ValueHasBeenAddedToLibrary"), - GetItemName(item)), - Description = item.Overview - }; - - await SendNotification(notification, item).ConfigureAwait(false); - } - } - - /// - /// Creates a human readable name for the item. - /// - /// The item. - /// A human readable name for the item. - public static string GetItemName(BaseItem item) - { - var name = item.Name; - if (item is Episode episode) - { - if (episode.IndexNumber.HasValue) - { - name = string.Format( - CultureInfo.InvariantCulture, - "Ep{0} - {1}", - episode.IndexNumber.Value, - name); - } - - if (episode.ParentIndexNumber.HasValue) - { - name = string.Format( - CultureInfo.InvariantCulture, - "S{0}, {1}", - episode.ParentIndexNumber.Value, - name); - } - } - - if (item is IHasSeries hasSeries) - { - name = hasSeries.SeriesName + " - " + name; - } - - if (item is IHasAlbumArtist hasAlbumArtist) - { - var artists = hasAlbumArtist.AlbumArtists; - - if (artists.Count > 0) - { - name = artists[0] + " - " + name; - } - } - else if (item is IHasArtist hasArtist) - { - var artists = hasArtist.Artists; - - if (artists.Count > 0) - { - name = artists[0] + " - " + name; - } - } - - return name; - } - - private async Task SendNotification(NotificationRequest notification, BaseItem? relatedItem) - { - try - { - await _notificationManager.SendNotification(notification, relatedItem, CancellationToken.None).ConfigureAwait(false); - } - catch (Exception ex) - { - _logger.LogError(ex, "Error sending notification"); - } - } - - /// - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - /// - /// Releases unmanaged and optionally managed resources. - /// - /// true to release both managed and unmanaged resources; false to release only unmanaged resources. - protected virtual void Dispose(bool disposing) - { - if (_disposed) - { - return; - } - - if (disposing) - { - _libraryUpdateTimer?.Dispose(); - } - - _libraryUpdateTimer = null; - - _libraryManager.ItemAdded -= OnLibraryManagerItemAdded; - _appHost.HasPendingRestartChanged -= OnAppHostHasPendingRestartChanged; - _activityManager.EntryCreated -= OnActivityManagerEntryCreated; - - _disposed = true; - } - } -} diff --git a/Emby.Notifications/NotificationManager.cs b/Emby.Notifications/NotificationManager.cs deleted file mode 100644 index a5a76b2af7..0000000000 --- a/Emby.Notifications/NotificationManager.cs +++ /dev/null @@ -1,224 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using Jellyfin.Data.Entities; -using Jellyfin.Data.Enums; -using MediaBrowser.Common.Configuration; -using MediaBrowser.Common.Extensions; -using MediaBrowser.Controller.Configuration; -using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Library; -using MediaBrowser.Controller.Notifications; -using MediaBrowser.Model.Dto; -using MediaBrowser.Model.Notifications; -using Microsoft.Extensions.Logging; - -namespace Emby.Notifications -{ - /// - /// NotificationManager class. - /// - public class NotificationManager : INotificationManager - { - private readonly ILogger _logger; - private readonly IUserManager _userManager; - private readonly IServerConfigurationManager _config; - - private INotificationService[] _services = Array.Empty(); - private INotificationTypeFactory[] _typeFactories = Array.Empty(); - - /// - /// Initializes a new instance of the class. - /// - /// The logger. - /// The user manager. - /// The server configuration manager. - public NotificationManager( - ILogger logger, - IUserManager userManager, - IServerConfigurationManager config) - { - _logger = logger; - _userManager = userManager; - _config = config; - } - - private NotificationOptions GetConfiguration() - { - return _config.GetConfiguration("notifications"); - } - - /// - public Task SendNotification(NotificationRequest request, CancellationToken cancellationToken) - { - return SendNotification(request, null, cancellationToken); - } - - /// - public Task SendNotification(NotificationRequest request, BaseItem? relatedItem, CancellationToken cancellationToken) - { - var notificationType = request.NotificationType; - - var options = string.IsNullOrEmpty(notificationType) ? - null : - GetConfiguration().GetOptions(notificationType); - - var users = GetUserIds(request, options) - .Select(i => _userManager.GetUserById(i)) - .Where(i => relatedItem is null || relatedItem.IsVisibleStandalone(i)) - .ToArray(); - - var title = request.Name; - var description = request.Description; - - var tasks = _services.Where(i => IsEnabled(i, notificationType)) - .Select(i => SendNotification(request, i, users, title, description, cancellationToken)); - - return Task.WhenAll(tasks); - } - - private Task SendNotification( - NotificationRequest request, - INotificationService service, - IEnumerable users, - string title, - string description, - CancellationToken cancellationToken) - { - users = users.Where(i => IsEnabledForUser(service, i)); - - var tasks = users.Select(i => SendNotification(request, service, title, description, i, cancellationToken)); - - return Task.WhenAll(tasks); - } - - private IEnumerable GetUserIds(NotificationRequest request, NotificationOption? options) - { - if (request.SendToUserMode.HasValue) - { - switch (request.SendToUserMode.Value) - { - case SendToUserType.Admins: - return _userManager.Users.Where(i => i.HasPermission(PermissionKind.IsAdministrator)) - .Select(i => i.Id); - case SendToUserType.All: - return _userManager.UsersIds; - case SendToUserType.Custom: - return request.UserIds; - default: - throw new ArgumentException("Unrecognized SendToUserMode: " + request.SendToUserMode.Value); - } - } - - if (options is not null && !string.IsNullOrEmpty(request.NotificationType)) - { - var config = GetConfiguration(); - - return _userManager.Users - .Where(i => config.IsEnabledToSendToUser(request.NotificationType, i.Id.ToString("N", CultureInfo.InvariantCulture), i)) - .Select(i => i.Id); - } - - return request.UserIds; - } - - private async Task SendNotification( - NotificationRequest request, - INotificationService service, - string title, - string description, - User user, - CancellationToken cancellationToken) - { - var notification = new UserNotification - { - Date = request.Date, - Description = description, - Level = request.Level, - Name = title, - Url = request.Url, - User = user - }; - - _logger.LogDebug("Sending notification via {0} to user {1}", service.Name, user.Username); - - try - { - await service.SendNotification(notification, cancellationToken).ConfigureAwait(false); - } - catch (Exception ex) - { - _logger.LogError(ex, "Error sending notification to {0}", service.Name); - } - } - - private bool IsEnabledForUser(INotificationService service, User user) - { - try - { - return service.IsEnabledForUser(user); - } - catch (Exception ex) - { - _logger.LogError(ex, "Error in IsEnabledForUser"); - return false; - } - } - - private bool IsEnabled(INotificationService service, string notificationType) - { - if (string.IsNullOrEmpty(notificationType)) - { - return true; - } - - return GetConfiguration().IsServiceEnabled(service.Name, notificationType); - } - - /// - public void AddParts(IEnumerable services, IEnumerable notificationTypeFactories) - { - _services = services.ToArray(); - _typeFactories = notificationTypeFactories.ToArray(); - } - - /// - public List GetNotificationTypes() - { - var list = _typeFactories.Select(i => - { - try - { - return i.GetNotificationTypes().ToList(); - } - catch (Exception ex) - { - _logger.LogError(ex, "Error in GetNotificationTypes"); - return new List(); - } - }).SelectMany(i => i).ToList(); - - var config = GetConfiguration(); - - foreach (var i in list) - { - i.Enabled = config.IsEnabled(i.Type); - } - - return list; - } - - /// - public IEnumerable GetNotificationServices() - { - return _services.Select(i => new NameIdPair - { - Name = i.Name, - Id = i.Name.GetMD5().ToString("N", CultureInfo.InvariantCulture) - }).OrderBy(i => i.Name); - } - } -} diff --git a/Emby.Notifications/Properties/AssemblyInfo.cs b/Emby.Notifications/Properties/AssemblyInfo.cs deleted file mode 100644 index 5c82c90c47..0000000000 --- a/Emby.Notifications/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System.Reflection; -using System.Resources; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("Emby.Notifications")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("Jellyfin Project")] -[assembly: AssemblyProduct("Jellyfin Server")] -[assembly: AssemblyCopyright("Copyright © 2019 Jellyfin Contributors. Code released under the GNU General Public License")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] -[assembly: NeutralResourcesLanguage("en")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index 560ba7d10d..07b0807b72 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -19,7 +19,6 @@ using Emby.Dlna; using Emby.Dlna.Main; using Emby.Dlna.Ssdp; using Emby.Naming.Common; -using Emby.Notifications; using Emby.Photos; using Emby.Server.Implementations.Channels; using Emby.Server.Implementations.Collections; @@ -70,7 +69,6 @@ using MediaBrowser.Controller.LiveTv; using MediaBrowser.Controller.Lyrics; using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.Controller.Net; -using MediaBrowser.Controller.Notifications; using MediaBrowser.Controller.Persistence; using MediaBrowser.Controller.Playlists; using MediaBrowser.Controller.Plugins; @@ -615,8 +613,6 @@ namespace Emby.Server.Implementations serviceCollection.AddSingleton(); - serviceCollection.AddSingleton(); - serviceCollection.AddSingleton(); serviceCollection.AddSingleton(); @@ -791,8 +787,6 @@ namespace Emby.Server.Implementations Resolve().AddParts(GetExports()); Resolve().AddParts(GetExports()); - - Resolve().AddParts(GetExports(), GetExports()); } /// @@ -991,9 +985,6 @@ namespace Emby.Server.Implementations // Local metadata yield return typeof(BoxSetXmlSaver).Assembly; - // Notifications - yield return typeof(NotificationManager).Assembly; - // Xbmc yield return typeof(ArtistNfoProvider).Assembly; diff --git a/Emby.Server.Implementations/Emby.Server.Implementations.csproj b/Emby.Server.Implementations/Emby.Server.Implementations.csproj index 7eaef094b5..1b5c879beb 100644 --- a/Emby.Server.Implementations/Emby.Server.Implementations.csproj +++ b/Emby.Server.Implementations/Emby.Server.Implementations.csproj @@ -7,7 +7,6 @@ - diff --git a/Jellyfin.Api/Controllers/NotificationsController.cs b/Jellyfin.Api/Controllers/NotificationsController.cs deleted file mode 100644 index a285564760..0000000000 --- a/Jellyfin.Api/Controllers/NotificationsController.cs +++ /dev/null @@ -1,53 +0,0 @@ -using System.Collections.Generic; -using Jellyfin.Api.Constants; -using MediaBrowser.Controller.Notifications; -using MediaBrowser.Model.Dto; -using MediaBrowser.Model.Notifications; -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Mvc; - -namespace Jellyfin.Api.Controllers -{ - /// - /// The notification controller. - /// - [Authorize(Policy = Policies.DefaultAuthorization)] - public class NotificationsController : BaseJellyfinApiController - { - private readonly INotificationManager _notificationManager; - - /// - /// Initializes a new instance of the class. - /// - /// The notification manager. - public NotificationsController(INotificationManager notificationManager) - { - _notificationManager = notificationManager; - } - - /// - /// Gets notification types. - /// - /// All notification types returned. - /// An containing a list of all notification types. - [HttpGet("Types")] - [ProducesResponseType(StatusCodes.Status200OK)] - public IEnumerable GetNotificationTypes() - { - return _notificationManager.GetNotificationTypes(); - } - - /// - /// Gets notification services. - /// - /// All notification services returned. - /// An containing a list of all notification services. - [HttpGet("Services")] - [ProducesResponseType(StatusCodes.Status200OK)] - public IEnumerable GetNotificationServices() - { - return _notificationManager.GetNotificationServices(); - } - } -} diff --git a/Jellyfin.sln b/Jellyfin.sln index f3fb7efa98..cad23fc5ee 100644 --- a/Jellyfin.sln +++ b/Jellyfin.sln @@ -27,8 +27,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RSSDP", "RSSDP\RSSDP.csproj EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Emby.Dlna", "Emby.Dlna\Emby.Dlna.csproj", "{805844AB-E92F-45E6-9D99-4F6D48D129A5}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Emby.Notifications", "Emby.Notifications\Emby.Notifications.csproj", "{2E030C33-6923-4530-9E54-FA29FA6AD1A9}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Emby.Naming", "Emby.Naming\Emby.Naming.csproj", "{E5AF7B26-2239-4CE0-B477-0AA2018EDAA2}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MediaBrowser.MediaEncoding", "MediaBrowser.MediaEncoding\MediaBrowser.MediaEncoding.csproj", "{960295EE-4AF4-4440-A525-B4C295B01A61}" @@ -149,10 +147,6 @@ Global {805844AB-E92F-45E6-9D99-4F6D48D129A5}.Debug|Any CPU.Build.0 = Debug|Any CPU {805844AB-E92F-45E6-9D99-4F6D48D129A5}.Release|Any CPU.ActiveCfg = Release|Any CPU {805844AB-E92F-45E6-9D99-4F6D48D129A5}.Release|Any CPU.Build.0 = Release|Any CPU - {2E030C33-6923-4530-9E54-FA29FA6AD1A9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {2E030C33-6923-4530-9E54-FA29FA6AD1A9}.Debug|Any CPU.Build.0 = Debug|Any CPU - {2E030C33-6923-4530-9E54-FA29FA6AD1A9}.Release|Any CPU.ActiveCfg = Release|Any CPU - {2E030C33-6923-4530-9E54-FA29FA6AD1A9}.Release|Any CPU.Build.0 = Release|Any CPU {E5AF7B26-2239-4CE0-B477-0AA2018EDAA2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {E5AF7B26-2239-4CE0-B477-0AA2018EDAA2}.Debug|Any CPU.Build.0 = Debug|Any CPU {E5AF7B26-2239-4CE0-B477-0AA2018EDAA2}.Release|Any CPU.ActiveCfg = Release|Any CPU diff --git a/MediaBrowser.Controller/Notifications/INotificationManager.cs b/MediaBrowser.Controller/Notifications/INotificationManager.cs deleted file mode 100644 index 7caba1097a..0000000000 --- a/MediaBrowser.Controller/Notifications/INotificationManager.cs +++ /dev/null @@ -1,43 +0,0 @@ -#pragma warning disable CS1591 - -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; -using MediaBrowser.Controller.Entities; -using MediaBrowser.Model.Dto; -using MediaBrowser.Model.Notifications; - -namespace MediaBrowser.Controller.Notifications -{ - public interface INotificationManager - { - /// - /// Sends the notification. - /// - /// The request. - /// The cancellation token. - /// Task. - Task SendNotification(NotificationRequest request, CancellationToken cancellationToken); - - Task SendNotification(NotificationRequest request, BaseItem? relatedItem, CancellationToken cancellationToken); - - /// - /// Adds the parts. - /// - /// The services. - /// The notification type factories. - void AddParts(IEnumerable services, IEnumerable notificationTypeFactories); - - /// - /// Gets the notification types. - /// - /// IEnumerable{NotificationTypeInfo}. - List GetNotificationTypes(); - - /// - /// Gets the notification services. - /// - /// IEnumerable{NotificationServiceInfo}. - IEnumerable GetNotificationServices(); - } -} diff --git a/MediaBrowser.Controller/Notifications/INotificationService.cs b/MediaBrowser.Controller/Notifications/INotificationService.cs deleted file mode 100644 index 535c08795b..0000000000 --- a/MediaBrowser.Controller/Notifications/INotificationService.cs +++ /dev/null @@ -1,34 +0,0 @@ -#nullable disable - -#pragma warning disable CS1591 - -using System.Threading; -using System.Threading.Tasks; -using Jellyfin.Data.Entities; - -namespace MediaBrowser.Controller.Notifications -{ - public interface INotificationService - { - /// - /// Gets the name. - /// - /// The name. - string Name { get; } - - /// - /// Sends the notification. - /// - /// The request. - /// The cancellation token. - /// Task. - Task SendNotification(UserNotification request, CancellationToken cancellationToken); - - /// - /// Determines whether [is enabled for user] [the specified user identifier]. - /// - /// The user. - /// true if [is enabled for user] [the specified user identifier]; otherwise, false. - bool IsEnabledForUser(User user); - } -} diff --git a/MediaBrowser.Controller/Notifications/INotificationTypeFactory.cs b/MediaBrowser.Controller/Notifications/INotificationTypeFactory.cs deleted file mode 100644 index 52a3e120b5..0000000000 --- a/MediaBrowser.Controller/Notifications/INotificationTypeFactory.cs +++ /dev/null @@ -1,16 +0,0 @@ -#pragma warning disable CS1591 - -using System.Collections.Generic; -using MediaBrowser.Model.Notifications; - -namespace MediaBrowser.Controller.Notifications -{ - public interface INotificationTypeFactory - { - /// - /// Gets the notification types. - /// - /// IEnumerable{NotificationTypeInfo}. - IEnumerable GetNotificationTypes(); - } -} diff --git a/MediaBrowser.Controller/Notifications/UserNotification.cs b/MediaBrowser.Controller/Notifications/UserNotification.cs deleted file mode 100644 index 4be0e09ae7..0000000000 --- a/MediaBrowser.Controller/Notifications/UserNotification.cs +++ /dev/null @@ -1,25 +0,0 @@ -#nullable disable - -#pragma warning disable CS1591 - -using System; -using Jellyfin.Data.Entities; -using MediaBrowser.Model.Notifications; - -namespace MediaBrowser.Controller.Notifications -{ - public class UserNotification - { - public string Name { get; set; } - - public string Description { get; set; } - - public string Url { get; set; } - - public NotificationLevel Level { get; set; } - - public DateTime Date { get; set; } - - public User User { get; set; } - } -} diff --git a/MediaBrowser.Model/Notifications/NotificationLevel.cs b/MediaBrowser.Model/Notifications/NotificationLevel.cs deleted file mode 100644 index 14fead3f01..0000000000 --- a/MediaBrowser.Model/Notifications/NotificationLevel.cs +++ /dev/null @@ -1,11 +0,0 @@ -#pragma warning disable CS1591 - -namespace MediaBrowser.Model.Notifications -{ - public enum NotificationLevel - { - Normal = 0, - Warning = 1, - Error = 2 - } -} diff --git a/MediaBrowser.Model/Notifications/NotificationOption.cs b/MediaBrowser.Model/Notifications/NotificationOption.cs deleted file mode 100644 index 58aecb3d35..0000000000 --- a/MediaBrowser.Model/Notifications/NotificationOption.cs +++ /dev/null @@ -1,55 +0,0 @@ -#pragma warning disable CA1819 // Properties should not return arrays -#pragma warning disable CS1591 - -using System; - -namespace MediaBrowser.Model.Notifications -{ - public class NotificationOption - { - public NotificationOption(string type) - { - Type = type; - DisabledServices = Array.Empty(); - DisabledMonitorUsers = Array.Empty(); - SendToUsers = Array.Empty(); - } - - public NotificationOption() - { - DisabledServices = Array.Empty(); - DisabledMonitorUsers = Array.Empty(); - SendToUsers = Array.Empty(); - } - - public string? Type { get; set; } - - /// - /// Gets or sets user Ids to not monitor (it's opt out). - /// - public string[] DisabledMonitorUsers { get; set; } - - /// - /// Gets or sets user Ids to send to (if SendToUserMode == Custom). - /// - public string[] SendToUsers { get; set; } - - /// - /// Gets or sets a value indicating whether this is enabled. - /// - /// true if enabled; otherwise, false. - public bool Enabled { get; set; } - - /// - /// Gets or sets the disabled services. - /// - /// The disabled services. - public string[] DisabledServices { get; set; } - - /// - /// Gets or sets the send to user mode. - /// - /// The send to user mode. - public SendToUserType SendToUserMode { get; set; } - } -} diff --git a/MediaBrowser.Model/Notifications/NotificationOptions.cs b/MediaBrowser.Model/Notifications/NotificationOptions.cs deleted file mode 100644 index 804f51e166..0000000000 --- a/MediaBrowser.Model/Notifications/NotificationOptions.cs +++ /dev/null @@ -1,131 +0,0 @@ -#nullable disable -#pragma warning disable CS1591 - -using System; -using Jellyfin.Data.Entities; -using Jellyfin.Data.Enums; -using Jellyfin.Extensions; - -namespace MediaBrowser.Model.Notifications -{ - public class NotificationOptions - { - public NotificationOptions() - { - Options = new[] - { - new NotificationOption(NotificationType.TaskFailed.ToString()) - { - Enabled = true, - SendToUserMode = SendToUserType.Admins - }, - new NotificationOption(NotificationType.ServerRestartRequired.ToString()) - { - Enabled = true, - SendToUserMode = SendToUserType.Admins - }, - new NotificationOption(NotificationType.ApplicationUpdateAvailable.ToString()) - { - Enabled = true, - SendToUserMode = SendToUserType.Admins - }, - new NotificationOption(NotificationType.ApplicationUpdateInstalled.ToString()) - { - Enabled = true, - SendToUserMode = SendToUserType.Admins - }, - new NotificationOption(NotificationType.PluginUpdateInstalled.ToString()) - { - Enabled = true, - SendToUserMode = SendToUserType.Admins - }, - new NotificationOption(NotificationType.PluginUninstalled.ToString()) - { - Enabled = true, - SendToUserMode = SendToUserType.Admins - }, - new NotificationOption(NotificationType.InstallationFailed.ToString()) - { - Enabled = true, - SendToUserMode = SendToUserType.Admins - }, - new NotificationOption(NotificationType.PluginInstalled.ToString()) - { - Enabled = true, - SendToUserMode = SendToUserType.Admins - }, - new NotificationOption(NotificationType.PluginError.ToString()) - { - Enabled = true, - SendToUserMode = SendToUserType.Admins - }, - new NotificationOption(NotificationType.UserLockedOut.ToString()) - { - Enabled = true, - SendToUserMode = SendToUserType.Admins - } - }; - } - - public NotificationOption[] Options { get; set; } - - public NotificationOption GetOptions(string type) - { - foreach (NotificationOption i in Options) - { - if (string.Equals(type, i.Type, StringComparison.OrdinalIgnoreCase)) - { - return i; - } - } - - return null; - } - - public bool IsEnabled(string type) - { - NotificationOption opt = GetOptions(type); - - return opt is not null && opt.Enabled; - } - - public bool IsServiceEnabled(string service, string notificationType) - { - NotificationOption opt = GetOptions(notificationType); - - return opt is null - || !opt.DisabledServices.Contains(service, StringComparison.OrdinalIgnoreCase); - } - - public bool IsEnabledToMonitorUser(string type, Guid userId) - { - NotificationOption opt = GetOptions(type); - - return opt is not null - && opt.Enabled - && !opt.DisabledMonitorUsers.Contains(userId.ToString("N"), StringComparison.OrdinalIgnoreCase); - } - - public bool IsEnabledToSendToUser(string type, string userId, User user) - { - NotificationOption opt = GetOptions(type); - - if (opt is not null && opt.Enabled) - { - if (opt.SendToUserMode == SendToUserType.All) - { - return true; - } - - if (opt.SendToUserMode == SendToUserType.Admins && user.HasPermission(PermissionKind.IsAdministrator)) - { - return true; - } - - return opt.SendToUsers.Contains(userId, StringComparison.OrdinalIgnoreCase); - } - - return false; - } - } -} diff --git a/MediaBrowser.Model/Notifications/NotificationRequest.cs b/MediaBrowser.Model/Notifications/NotificationRequest.cs deleted file mode 100644 index 622c50cd88..0000000000 --- a/MediaBrowser.Model/Notifications/NotificationRequest.cs +++ /dev/null @@ -1,35 +0,0 @@ -#nullable disable -#pragma warning disable CS1591 - -using System; - -namespace MediaBrowser.Model.Notifications -{ - public class NotificationRequest - { - public NotificationRequest() - { - UserIds = Array.Empty(); - Date = DateTime.UtcNow; - } - - public string Name { get; set; } - - public string Description { get; set; } - - public string Url { get; set; } - - public NotificationLevel Level { get; set; } - - public Guid[] UserIds { get; set; } - - public DateTime Date { get; set; } - - /// - /// Gets or sets the corresponding type name used in configuration. Not for display. - /// - public string NotificationType { get; set; } - - public SendToUserType? SendToUserMode { get; set; } - } -} diff --git a/MediaBrowser.Model/Notifications/NotificationTypeInfo.cs b/MediaBrowser.Model/Notifications/NotificationTypeInfo.cs deleted file mode 100644 index 402fbe81a0..0000000000 --- a/MediaBrowser.Model/Notifications/NotificationTypeInfo.cs +++ /dev/null @@ -1,18 +0,0 @@ -#nullable disable -#pragma warning disable CS1591 - -namespace MediaBrowser.Model.Notifications -{ - public class NotificationTypeInfo - { - public string Type { get; set; } - - public string Name { get; set; } - - public bool Enabled { get; set; } - - public string Category { get; set; } - - public bool IsBasedOnUserEvent { get; set; } - } -} diff --git a/MediaBrowser.Model/Notifications/SendToUserType.cs b/MediaBrowser.Model/Notifications/SendToUserType.cs deleted file mode 100644 index 65fc4e1abd..0000000000 --- a/MediaBrowser.Model/Notifications/SendToUserType.cs +++ /dev/null @@ -1,11 +0,0 @@ -#pragma warning disable CS1591 - -namespace MediaBrowser.Model.Notifications -{ - public enum SendToUserType - { - All = 0, - Admins = 1, - Custom = 2 - } -} -- cgit v1.2.3 From 29c1f54b572ceb1a09be7744f4ab2fbb5224a8a7 Mon Sep 17 00:00:00 2001 From: James Harvey <44349936+jmshrv@users.noreply.github.com> Date: Thu, 2 Feb 2023 13:54:05 +0000 Subject: Fix audio codec not being used in UniversalAudio (#9192) --- MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 9f7be977ff..a844e64433 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -5762,6 +5762,11 @@ namespace MediaBrowser.Controller.MediaEncoding audioTranscodeParams.Add("-ac " + state.OutputAudioChannels.Value.ToString(CultureInfo.InvariantCulture)); } + if (!string.IsNullOrEmpty(state.OutputAudioCodec)) + { + audioTranscodeParams.Add("-acodec " + GetAudioEncoder(state)); + } + if (!string.Equals(state.OutputAudioCodec, "opus", StringComparison.OrdinalIgnoreCase)) { // opus only supports specific sampling rates -- cgit v1.2.3 From c70508b08984d62d3b62d233f6ce4078f2a75bb1 Mon Sep 17 00:00:00 2001 From: James Harvey <44349936+jmshrv@users.noreply.github.com> Date: Sat, 4 Feb 2023 01:56:14 +0000 Subject: Add movflags to mp4 audio encoding --- MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index a844e64433..d08a5116a0 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -5786,6 +5786,22 @@ namespace MediaBrowser.Controller.MediaEncoding } } + // Copy the movflags from GetProgressiveVideoFullCommandLine + // See # for explanation on why this is needed + var mp4ContainerNames = new HashSet { + "mp4", + "m4a", + "m4p", + "m4b", + "m4r", + "m4v", + }; + + if (mp4ContainerNames.Contains(state.OutputContainer.ToLower())) + { + audioTranscodeParams.Add("-movflags frag_keyframe+empty_moov+delay_moov"); + } + var threads = GetNumberOfThreads(state, encodingOptions, null); var inputModifier = GetInputModifier(state, encodingOptions, null); -- cgit v1.2.3 From f2cc0e70693d134d163ab056cd412a151c1055fc Mon Sep 17 00:00:00 2001 From: James Harvey <44349936+jmshrv@users.noreply.github.com> Date: Sat, 4 Feb 2023 02:17:36 +0000 Subject: Fill in issue/PR comment --- MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index d08a5116a0..33ecaf3bf1 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -5787,7 +5787,7 @@ namespace MediaBrowser.Controller.MediaEncoding } // Copy the movflags from GetProgressiveVideoFullCommandLine - // See # for explanation on why this is needed + // See #9248 and the associated PR for why this is needed var mp4ContainerNames = new HashSet { "mp4", "m4a", -- cgit v1.2.3 From a3f41bbc0cf2b2009005ef5bb1d449002ff7017c Mon Sep 17 00:00:00 2001 From: James Harvey <44349936+jmshrv@users.noreply.github.com> Date: Sat, 4 Feb 2023 02:29:21 +0000 Subject: Remove frag_keyframe as it is not relevant for audio --- MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 33ecaf3bf1..21cfac00a4 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -5581,7 +5581,7 @@ namespace MediaBrowser.Controller.MediaEncoding && state.BaseRequest.Context == EncodingContext.Streaming) { // Comparison: https://github.com/jansmolders86/mediacenterjs/blob/master/lib/transcoding/desktop.js - format = " -f mp4 -movflags frag_keyframe+empty_moov+delay_moov"; + format = " -f mp4 -movflags empty_moov+delay_moov"; } var threads = GetNumberOfThreads(state, encodingOptions, videoCodec); -- cgit v1.2.3 From 83ae6fcdb466b2bee17af07ac415f6e5892ff3c7 Mon Sep 17 00:00:00 2001 From: James Harvey <44349936+jmshrv@users.noreply.github.com> Date: Sat, 4 Feb 2023 02:45:24 +0000 Subject: Fix Braces for multi-line statements should not share line --- MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 21cfac00a4..c335320a75 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -5788,7 +5788,8 @@ namespace MediaBrowser.Controller.MediaEncoding // Copy the movflags from GetProgressiveVideoFullCommandLine // See #9248 and the associated PR for why this is needed - var mp4ContainerNames = new HashSet { + var mp4ContainerNames = new HashSet + { "mp4", "m4a", "m4p", -- cgit v1.2.3 From c9627f8839dbb0956df2fdb6ab8258710d837b11 Mon Sep 17 00:00:00 2001 From: James Harvey <44349936+jmshrv@users.noreply.github.com> Date: Sat, 4 Feb 2023 02:46:14 +0000 Subject: Fix Use built-in type alias --- MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index c335320a75..e530cba2c5 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -5788,7 +5788,7 @@ namespace MediaBrowser.Controller.MediaEncoding // Copy the movflags from GetProgressiveVideoFullCommandLine // See #9248 and the associated PR for why this is needed - var mp4ContainerNames = new HashSet + var mp4ContainerNames = new HashSet { "mp4", "m4a", -- cgit v1.2.3 From 42b4ef45294833efc2cca381e555a792729889b0 Mon Sep 17 00:00:00 2001 From: James Harvey <44349936+jmshrv@users.noreply.github.com> Date: Sat, 4 Feb 2023 03:59:35 +0000 Subject: Remove frag_keyframe on audio, not video --- MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index e530cba2c5..d6ab27b037 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -5581,7 +5581,7 @@ namespace MediaBrowser.Controller.MediaEncoding && state.BaseRequest.Context == EncodingContext.Streaming) { // Comparison: https://github.com/jansmolders86/mediacenterjs/blob/master/lib/transcoding/desktop.js - format = " -f mp4 -movflags empty_moov+delay_moov"; + format = " -f mp4 -movflags frag_keyframe+empty_moov+delay_moov"; } var threads = GetNumberOfThreads(state, encodingOptions, videoCodec); @@ -5800,7 +5800,7 @@ namespace MediaBrowser.Controller.MediaEncoding if (mp4ContainerNames.Contains(state.OutputContainer.ToLower())) { - audioTranscodeParams.Add("-movflags frag_keyframe+empty_moov+delay_moov"); + audioTranscodeParams.Add("-movflags empty_moov+delay_moov"); } var threads = GetNumberOfThreads(state, encodingOptions, null); -- cgit v1.2.3 From e0519189b25bc4605889e46d9583fea9aef41732 Mon Sep 17 00:00:00 2001 From: Zoltan Csizmadia Date: Sat, 4 Feb 2023 11:15:08 -0600 Subject: Use Directory.Packages.props (#9135) Co-authored-by: Zoltan Csizmadia --- Directory.Packages.props | 90 ++++++++++++++++++++++ Emby.Dlna/Emby.Dlna.csproj | 10 +-- Emby.Naming/Emby.Naming.csproj | 10 +-- Emby.Photos/Emby.Photos.csproj | 10 +-- .../Emby.Server.Implementations.csproj | 30 ++++---- Jellyfin.Api/Jellyfin.Api.csproj | 16 ++-- Jellyfin.Data/Jellyfin.Data.csproj | 12 +-- Jellyfin.Networking/Jellyfin.Networking.csproj | 8 +- .../Jellyfin.Server.Implementations.csproj | 20 ++--- Jellyfin.Server/Jellyfin.Server.csproj | 38 ++++----- MediaBrowser.Common/MediaBrowser.Common.csproj | 14 ++-- .../MediaBrowser.Controller.csproj | 16 ++-- .../MediaBrowser.LocalMetadata.csproj | 8 +- .../MediaBrowser.MediaEncoding.csproj | 16 ++-- MediaBrowser.Model/MediaBrowser.Model.csproj | 18 ++--- .../MediaBrowser.Providers.csproj | 26 +++---- .../MediaBrowser.XbmcMetadata.csproj | 8 +- .../Emby.Server.Implementations.Fuzz.csproj | 8 +- .../Jellyfin.Server.Fuzz.csproj | 2 +- .../Jellyfin.Drawing.Skia.csproj | 18 ++--- src/Jellyfin.Drawing/Jellyfin.Drawing.csproj | 8 +- src/Jellyfin.Extensions/Jellyfin.Extensions.csproj | 10 +-- .../Jellyfin.MediaEncoding.Hls.csproj | 10 +-- .../Jellyfin.MediaEncoding.Keyframes.csproj | 12 +-- tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj | 28 +++---- .../Jellyfin.Common.Tests.csproj | 18 ++--- .../Jellyfin.Controller.Tests.csproj | 18 ++--- .../Jellyfin.Dlna.Tests/Jellyfin.Dlna.Tests.csproj | 18 ++--- .../Jellyfin.Extensions.Tests.csproj | 18 ++--- .../Jellyfin.MediaEncoding.Hls.Tests.csproj | 16 ++-- .../Jellyfin.MediaEncoding.Keyframes.Tests.csproj | 16 ++-- .../Jellyfin.MediaEncoding.Tests.csproj | 24 +++--- .../Jellyfin.Model.Tests.csproj | 20 ++--- .../Jellyfin.Naming.Tests.csproj | 18 ++--- .../Jellyfin.Networking.Tests.csproj | 20 ++--- .../Jellyfin.Providers.Tests.csproj | 18 ++--- .../Jellyfin.Server.Implementations.Tests.csproj | 24 +++--- .../Jellyfin.Server.Integration.Tests.csproj | 30 ++++---- .../Jellyfin.Server.Tests.csproj | 28 +++---- .../Jellyfin.XbmcMetadata.Tests.csproj | 18 ++--- 40 files changed, 420 insertions(+), 330 deletions(-) create mode 100644 Directory.Packages.props (limited to 'MediaBrowser.Controller') diff --git a/Directory.Packages.props b/Directory.Packages.props new file mode 100644 index 0000000000..26f0692115 --- /dev/null +++ b/Directory.Packages.props @@ -0,0 +1,90 @@ + + + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Emby.Dlna/Emby.Dlna.csproj b/Emby.Dlna/Emby.Dlna.csproj index 60e6dd644d..aca2399644 100644 --- a/Emby.Dlna/Emby.Dlna.csproj +++ b/Emby.Dlna/Emby.Dlna.csproj @@ -28,13 +28,13 @@ - + all runtime; build; native; contentfiles; analyzers - - - + + + @@ -80,7 +80,7 @@ - + diff --git a/Emby.Naming/Emby.Naming.csproj b/Emby.Naming/Emby.Naming.csproj index 3106e22465..f3973dad95 100644 --- a/Emby.Naming/Emby.Naming.csproj +++ b/Emby.Naming/Emby.Naming.csproj @@ -42,18 +42,18 @@ - + - + all runtime; build; native; contentfiles; analyzers - - - + + + diff --git a/Emby.Photos/Emby.Photos.csproj b/Emby.Photos/Emby.Photos.csproj index ae6bc2db1f..0f97a06867 100644 --- a/Emby.Photos/Emby.Photos.csproj +++ b/Emby.Photos/Emby.Photos.csproj @@ -15,7 +15,7 @@ - + @@ -26,13 +26,13 @@ - + all runtime; build; native; contentfiles; analyzers - - - + + + diff --git a/Emby.Server.Implementations/Emby.Server.Implementations.csproj b/Emby.Server.Implementations/Emby.Server.Implementations.csproj index 1b5c879beb..b8655c7600 100644 --- a/Emby.Server.Implementations/Emby.Server.Implementations.csproj +++ b/Emby.Server.Implementations/Emby.Server.Implementations.csproj @@ -22,17 +22,17 @@ - - - - - - - - - - - + + + + + + + + + + + @@ -53,13 +53,13 @@ - + all runtime; build; native; contentfiles; analyzers - - - + + + diff --git a/Jellyfin.Api/Jellyfin.Api.csproj b/Jellyfin.Api/Jellyfin.Api.csproj index 45725ec3e6..a8a44fd3e0 100644 --- a/Jellyfin.Api/Jellyfin.Api.csproj +++ b/Jellyfin.Api/Jellyfin.Api.csproj @@ -13,10 +13,10 @@ - - - - + + + + @@ -27,13 +27,13 @@ - + all runtime; build; native; contentfiles; analyzers - - - + + + diff --git a/Jellyfin.Data/Jellyfin.Data.csproj b/Jellyfin.Data/Jellyfin.Data.csproj index 540534e1ba..1bc5d8bf91 100644 --- a/Jellyfin.Data/Jellyfin.Data.csproj +++ b/Jellyfin.Data/Jellyfin.Data.csproj @@ -24,22 +24,22 @@ - + - + all runtime; build; native; contentfiles; analyzers - - - + + + - + diff --git a/Jellyfin.Networking/Jellyfin.Networking.csproj b/Jellyfin.Networking/Jellyfin.Networking.csproj index 2c153d88b5..4cff5927fd 100644 --- a/Jellyfin.Networking/Jellyfin.Networking.csproj +++ b/Jellyfin.Networking/Jellyfin.Networking.csproj @@ -11,13 +11,13 @@ - + all runtime; build; native; contentfiles; analyzers - - - + + + diff --git a/Jellyfin.Server.Implementations/Jellyfin.Server.Implementations.csproj b/Jellyfin.Server.Implementations/Jellyfin.Server.Implementations.csproj index 1c53274e23..390ed58b3b 100644 --- a/Jellyfin.Server.Implementations/Jellyfin.Server.Implementations.csproj +++ b/Jellyfin.Server.Implementations/Jellyfin.Server.Implementations.csproj @@ -8,13 +8,13 @@ - + all runtime; build; native; contentfiles; analyzers - - - + + + @@ -22,15 +22,15 @@ - - - - - + + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/Jellyfin.Server/Jellyfin.Server.csproj b/Jellyfin.Server/Jellyfin.Server.csproj index 9ea8508f24..146de3ae13 100644 --- a/Jellyfin.Server/Jellyfin.Server.csproj +++ b/Jellyfin.Server/Jellyfin.Server.csproj @@ -24,31 +24,31 @@ - + all runtime; build; native; contentfiles; analyzers - - - + + + - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + diff --git a/MediaBrowser.Common/MediaBrowser.Common.csproj b/MediaBrowser.Common/MediaBrowser.Common.csproj index 1b0ff27d98..3f1a098e45 100644 --- a/MediaBrowser.Common/MediaBrowser.Common.csproj +++ b/MediaBrowser.Common/MediaBrowser.Common.csproj @@ -19,9 +19,9 @@ - - - + + + @@ -49,13 +49,13 @@ - + all runtime; build; native; contentfiles; analyzers - - - + + + diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index 20909c9d57..69c0d26b6b 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -18,10 +18,10 @@ - - - - + + + + @@ -51,13 +51,13 @@ - + all runtime; build; native; contentfiles; analyzers - - - + + + diff --git a/MediaBrowser.LocalMetadata/MediaBrowser.LocalMetadata.csproj b/MediaBrowser.LocalMetadata/MediaBrowser.LocalMetadata.csproj index 039127f9e3..71cdea5298 100644 --- a/MediaBrowser.LocalMetadata/MediaBrowser.LocalMetadata.csproj +++ b/MediaBrowser.LocalMetadata/MediaBrowser.LocalMetadata.csproj @@ -22,13 +22,13 @@ - + all runtime; build; native; contentfiles; analyzers - - - + + + diff --git a/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj b/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj index 93177298f9..f4438fe194 100644 --- a/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj +++ b/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj @@ -22,21 +22,21 @@ - - - - + + + + - + all runtime; build; native; contentfiles; analyzers - - - + + + diff --git a/MediaBrowser.Model/MediaBrowser.Model.csproj b/MediaBrowser.Model/MediaBrowser.Model.csproj index 521ba0f107..9a58044853 100644 --- a/MediaBrowser.Model/MediaBrowser.Model.csproj +++ b/MediaBrowser.Model/MediaBrowser.Model.csproj @@ -33,14 +33,14 @@ - - - + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - - + + @@ -49,13 +49,13 @@ - + all runtime; build; native; contentfiles; analyzers - - - + + + diff --git a/MediaBrowser.Providers/MediaBrowser.Providers.csproj b/MediaBrowser.Providers/MediaBrowser.Providers.csproj index 9e238e9f3a..6a40833d7f 100644 --- a/MediaBrowser.Providers/MediaBrowser.Providers.csproj +++ b/MediaBrowser.Providers/MediaBrowser.Providers.csproj @@ -15,15 +15,15 @@ - - - - - - - - - + + + + + + + + + @@ -35,13 +35,13 @@ - + all runtime; build; native; contentfiles; analyzers - - - + + + diff --git a/MediaBrowser.XbmcMetadata/MediaBrowser.XbmcMetadata.csproj b/MediaBrowser.XbmcMetadata/MediaBrowser.XbmcMetadata.csproj index c25932a5a1..8072349152 100644 --- a/MediaBrowser.XbmcMetadata/MediaBrowser.XbmcMetadata.csproj +++ b/MediaBrowser.XbmcMetadata/MediaBrowser.XbmcMetadata.csproj @@ -22,13 +22,13 @@ - + all runtime; build; native; contentfiles; analyzers - - - + + + diff --git a/fuzz/Emby.Server.Implementations.Fuzz/Emby.Server.Implementations.Fuzz.csproj b/fuzz/Emby.Server.Implementations.Fuzz/Emby.Server.Implementations.Fuzz.csproj index 51df09a210..1e3f8a0482 100644 --- a/fuzz/Emby.Server.Implementations.Fuzz/Emby.Server.Implementations.Fuzz.csproj +++ b/fuzz/Emby.Server.Implementations.Fuzz/Emby.Server.Implementations.Fuzz.csproj @@ -16,10 +16,10 @@ - - - - + + + + diff --git a/fuzz/Jellyfin.Server.Fuzz/Jellyfin.Server.Fuzz.csproj b/fuzz/Jellyfin.Server.Fuzz/Jellyfin.Server.Fuzz.csproj index 226ab60daa..20bc4c7244 100644 --- a/fuzz/Jellyfin.Server.Fuzz/Jellyfin.Server.Fuzz.csproj +++ b/fuzz/Jellyfin.Server.Fuzz/Jellyfin.Server.Fuzz.csproj @@ -16,7 +16,7 @@ - + diff --git a/src/Jellyfin.Drawing.Skia/Jellyfin.Drawing.Skia.csproj b/src/Jellyfin.Drawing.Skia/Jellyfin.Drawing.Skia.csproj index a62ebf78c7..3b03332994 100644 --- a/src/Jellyfin.Drawing.Skia/Jellyfin.Drawing.Skia.csproj +++ b/src/Jellyfin.Drawing.Skia/Jellyfin.Drawing.Skia.csproj @@ -16,11 +16,11 @@ - - - - - + + + + + @@ -31,13 +31,13 @@ - + all runtime; build; native; contentfiles; analyzers - - - + + + diff --git a/src/Jellyfin.Drawing/Jellyfin.Drawing.csproj b/src/Jellyfin.Drawing/Jellyfin.Drawing.csproj index 7aa9945033..e0963ac34e 100644 --- a/src/Jellyfin.Drawing/Jellyfin.Drawing.csproj +++ b/src/Jellyfin.Drawing/Jellyfin.Drawing.csproj @@ -23,13 +23,13 @@ - + all runtime; build; native; contentfiles; analyzers - - - + + + diff --git a/src/Jellyfin.Extensions/Jellyfin.Extensions.csproj b/src/Jellyfin.Extensions/Jellyfin.Extensions.csproj index d7c05ea576..15261bb65e 100644 --- a/src/Jellyfin.Extensions/Jellyfin.Extensions.csproj +++ b/src/Jellyfin.Extensions/Jellyfin.Extensions.csproj @@ -29,18 +29,18 @@ - + - + all runtime; build; native; contentfiles; analyzers - - - + + + diff --git a/src/Jellyfin.MediaEncoding.Hls/Jellyfin.MediaEncoding.Hls.csproj b/src/Jellyfin.MediaEncoding.Hls/Jellyfin.MediaEncoding.Hls.csproj index 9a025d5586..f489d6fd0a 100644 --- a/src/Jellyfin.MediaEncoding.Hls/Jellyfin.MediaEncoding.Hls.csproj +++ b/src/Jellyfin.MediaEncoding.Hls/Jellyfin.MediaEncoding.Hls.csproj @@ -7,13 +7,13 @@ - + all runtime; build; native; contentfiles; analyzers - - - + + + @@ -23,7 +23,7 @@ - + diff --git a/src/Jellyfin.MediaEncoding.Keyframes/Jellyfin.MediaEncoding.Keyframes.csproj b/src/Jellyfin.MediaEncoding.Keyframes/Jellyfin.MediaEncoding.Keyframes.csproj index fe4e576937..3801a1cc33 100644 --- a/src/Jellyfin.MediaEncoding.Keyframes/Jellyfin.MediaEncoding.Keyframes.csproj +++ b/src/Jellyfin.MediaEncoding.Keyframes/Jellyfin.MediaEncoding.Keyframes.csproj @@ -6,22 +6,22 @@ - + - + all runtime; build; native; contentfiles; analyzers - - - + + + - + diff --git a/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj b/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj index 6966d81d46..6202f83dcf 100644 --- a/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj +++ b/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj @@ -12,30 +12,30 @@ - - - - - - - - + + + + + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - - + + - + all runtime; build; native; contentfiles; analyzers - - - + + + diff --git a/tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj b/tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj index 5110d59176..699c12217c 100644 --- a/tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj +++ b/tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj @@ -12,25 +12,25 @@ - - - + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - - + + - + all runtime; build; native; contentfiles; analyzers - - - + + + diff --git a/tests/Jellyfin.Controller.Tests/Jellyfin.Controller.Tests.csproj b/tests/Jellyfin.Controller.Tests/Jellyfin.Controller.Tests.csproj index 97350fedad..1e729a46a4 100644 --- a/tests/Jellyfin.Controller.Tests/Jellyfin.Controller.Tests.csproj +++ b/tests/Jellyfin.Controller.Tests/Jellyfin.Controller.Tests.csproj @@ -12,25 +12,25 @@ - - - - + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - + - + all runtime; build; native; contentfiles; analyzers - - - + + + diff --git a/tests/Jellyfin.Dlna.Tests/Jellyfin.Dlna.Tests.csproj b/tests/Jellyfin.Dlna.Tests/Jellyfin.Dlna.Tests.csproj index a2ecd60838..2be5da2c2c 100644 --- a/tests/Jellyfin.Dlna.Tests/Jellyfin.Dlna.Tests.csproj +++ b/tests/Jellyfin.Dlna.Tests/Jellyfin.Dlna.Tests.csproj @@ -7,25 +7,25 @@ - - - - + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - + - + all runtime; build; native; contentfiles; analyzers - - - + + + diff --git a/tests/Jellyfin.Extensions.Tests/Jellyfin.Extensions.Tests.csproj b/tests/Jellyfin.Extensions.Tests/Jellyfin.Extensions.Tests.csproj index 313192b241..dbbb61cc45 100644 --- a/tests/Jellyfin.Extensions.Tests/Jellyfin.Extensions.Tests.csproj +++ b/tests/Jellyfin.Extensions.Tests/Jellyfin.Extensions.Tests.csproj @@ -7,28 +7,28 @@ - - - + + + runtime; build; native; contentfiles; analyzers; buildtransitive all - + runtime; build; native; contentfiles; analyzers; buildtransitive all - + - + all runtime; build; native; contentfiles; analyzers - - - + + + diff --git a/tests/Jellyfin.MediaEncoding.Hls.Tests/Jellyfin.MediaEncoding.Hls.Tests.csproj b/tests/Jellyfin.MediaEncoding.Hls.Tests/Jellyfin.MediaEncoding.Hls.Tests.csproj index 22b0c417b0..10c1418731 100644 --- a/tests/Jellyfin.MediaEncoding.Hls.Tests/Jellyfin.MediaEncoding.Hls.Tests.csproj +++ b/tests/Jellyfin.MediaEncoding.Hls.Tests/Jellyfin.MediaEncoding.Hls.Tests.csproj @@ -7,13 +7,13 @@ - - - + + + runtime; build; native; contentfiles; analyzers; buildtransitive all - + runtime; build; native; contentfiles; analyzers; buildtransitive all @@ -21,13 +21,13 @@ - + all runtime; build; native; contentfiles; analyzers - - - + + + diff --git a/tests/Jellyfin.MediaEncoding.Keyframes.Tests/Jellyfin.MediaEncoding.Keyframes.Tests.csproj b/tests/Jellyfin.MediaEncoding.Keyframes.Tests/Jellyfin.MediaEncoding.Keyframes.Tests.csproj index 373a54504e..4910a041a3 100644 --- a/tests/Jellyfin.MediaEncoding.Keyframes.Tests/Jellyfin.MediaEncoding.Keyframes.Tests.csproj +++ b/tests/Jellyfin.MediaEncoding.Keyframes.Tests/Jellyfin.MediaEncoding.Keyframes.Tests.csproj @@ -8,13 +8,13 @@ - - - + + + runtime; build; native; contentfiles; analyzers; buildtransitive all - + runtime; build; native; contentfiles; analyzers; buildtransitive all @@ -22,13 +22,13 @@ - + all runtime; build; native; contentfiles; analyzers - - - + + + diff --git a/tests/Jellyfin.MediaEncoding.Tests/Jellyfin.MediaEncoding.Tests.csproj b/tests/Jellyfin.MediaEncoding.Tests/Jellyfin.MediaEncoding.Tests.csproj index a9a0dbc226..077466b6e6 100644 --- a/tests/Jellyfin.MediaEncoding.Tests/Jellyfin.MediaEncoding.Tests.csproj +++ b/tests/Jellyfin.MediaEncoding.Tests/Jellyfin.MediaEncoding.Tests.csproj @@ -18,14 +18,14 @@ - - - - - - - - + + + + + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive @@ -33,13 +33,13 @@ - + all runtime; build; native; contentfiles; analyzers - - - + + + diff --git a/tests/Jellyfin.Model.Tests/Jellyfin.Model.Tests.csproj b/tests/Jellyfin.Model.Tests/Jellyfin.Model.Tests.csproj index 9858623f82..cffd7bc0bb 100644 --- a/tests/Jellyfin.Model.Tests/Jellyfin.Model.Tests.csproj +++ b/tests/Jellyfin.Model.Tests/Jellyfin.Model.Tests.csproj @@ -7,15 +7,15 @@ - - - - + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - - + + @@ -26,13 +26,13 @@ - + all runtime; build; native; contentfiles; analyzers - - - + + + diff --git a/tests/Jellyfin.Naming.Tests/Jellyfin.Naming.Tests.csproj b/tests/Jellyfin.Naming.Tests/Jellyfin.Naming.Tests.csproj index 920f490ed0..c5e93f0bbe 100644 --- a/tests/Jellyfin.Naming.Tests/Jellyfin.Naming.Tests.csproj +++ b/tests/Jellyfin.Naming.Tests/Jellyfin.Naming.Tests.csproj @@ -12,14 +12,14 @@ - - - - + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - + @@ -28,13 +28,13 @@ - + all runtime; build; native; contentfiles; analyzers - - - + + + diff --git a/tests/Jellyfin.Networking.Tests/Jellyfin.Networking.Tests.csproj b/tests/Jellyfin.Networking.Tests/Jellyfin.Networking.Tests.csproj index 74bf7cb0e0..e245699269 100644 --- a/tests/Jellyfin.Networking.Tests/Jellyfin.Networking.Tests.csproj +++ b/tests/Jellyfin.Networking.Tests/Jellyfin.Networking.Tests.csproj @@ -12,26 +12,26 @@ - - - + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - - - + + + - + all runtime; build; native; contentfiles; analyzers - - - + + + diff --git a/tests/Jellyfin.Providers.Tests/Jellyfin.Providers.Tests.csproj b/tests/Jellyfin.Providers.Tests/Jellyfin.Providers.Tests.csproj index d3292c38eb..27151c8479 100644 --- a/tests/Jellyfin.Providers.Tests/Jellyfin.Providers.Tests.csproj +++ b/tests/Jellyfin.Providers.Tests/Jellyfin.Providers.Tests.csproj @@ -13,14 +13,14 @@ - - - - + + + + runtime; build; native; contentfiles; analyzers; buildtransitive all - + runtime; build; native; contentfiles; analyzers; buildtransitive all @@ -28,13 +28,13 @@ - + all runtime; build; native; contentfiles; analyzers - - - + + + diff --git a/tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj b/tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj index b796e07d1a..2150520e5f 100644 --- a/tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj +++ b/tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj @@ -19,28 +19,28 @@ - - - - - - + + + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - - + + - + all runtime; build; native; contentfiles; analyzers - - - + + + diff --git a/tests/Jellyfin.Server.Integration.Tests/Jellyfin.Server.Integration.Tests.csproj b/tests/Jellyfin.Server.Integration.Tests/Jellyfin.Server.Integration.Tests.csproj index c40f6942b1..26b2cd2395 100644 --- a/tests/Jellyfin.Server.Integration.Tests/Jellyfin.Server.Integration.Tests.csproj +++ b/tests/Jellyfin.Server.Integration.Tests/Jellyfin.Server.Integration.Tests.csproj @@ -6,20 +6,20 @@ - - - - - - - - + + + + + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - - - + + + @@ -31,13 +31,13 @@ - + all runtime; build; native; contentfiles; analyzers - - - + + + diff --git a/tests/Jellyfin.Server.Tests/Jellyfin.Server.Tests.csproj b/tests/Jellyfin.Server.Tests/Jellyfin.Server.Tests.csproj index a72a6f1855..d47f70cffa 100644 --- a/tests/Jellyfin.Server.Tests/Jellyfin.Server.Tests.csproj +++ b/tests/Jellyfin.Server.Tests/Jellyfin.Server.Tests.csproj @@ -7,30 +7,30 @@ - - - - - - - - + + + + + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - - + + - + all runtime; build; native; contentfiles; analyzers - - - + + + diff --git a/tests/Jellyfin.XbmcMetadata.Tests/Jellyfin.XbmcMetadata.Tests.csproj b/tests/Jellyfin.XbmcMetadata.Tests/Jellyfin.XbmcMetadata.Tests.csproj index dc5b5b9e6b..fb7864cd13 100644 --- a/tests/Jellyfin.XbmcMetadata.Tests/Jellyfin.XbmcMetadata.Tests.csproj +++ b/tests/Jellyfin.XbmcMetadata.Tests/Jellyfin.XbmcMetadata.Tests.csproj @@ -13,25 +13,25 @@ - - - - + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - + - + all runtime; build; native; contentfiles; analyzers - - - + + + -- cgit v1.2.3 From 4a2245fe1e97c7d450557fd1269be8584a58c478 Mon Sep 17 00:00:00 2001 From: James Harvey <44349936+jmshrv@users.noreply.github.com> Date: Sat, 4 Feb 2023 18:52:35 +0000 Subject: Move mp4 container names to class and use StringComparer.OrdinalIgnoreCase --- .../MediaEncoding/EncodingHelper.cs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index d6ab27b037..9b5edabc06 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -61,6 +61,16 @@ namespace MediaBrowser.Controller.MediaEncoding "Main10" }; + private static readonly HashSet _mp4ContainerNames = new(StringComparer.OrdinalIgnoreCase) + { + "mp4", + "m4a", + "m4p", + "m4b", + "m4r", + "m4v", + }; + public EncodingHelper( IApplicationPaths appPaths, IMediaEncoder mediaEncoder, @@ -5788,17 +5798,7 @@ namespace MediaBrowser.Controller.MediaEncoding // Copy the movflags from GetProgressiveVideoFullCommandLine // See #9248 and the associated PR for why this is needed - var mp4ContainerNames = new HashSet - { - "mp4", - "m4a", - "m4p", - "m4b", - "m4r", - "m4v", - }; - - if (mp4ContainerNames.Contains(state.OutputContainer.ToLower())) + if (_mp4ContainerNames.Contains(state.OutputContainer)) { audioTranscodeParams.Add("-movflags empty_moov+delay_moov"); } -- cgit v1.2.3 From 52230d1c30b76f34132c8c3ad21a09deea72d9d8 Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Sat, 4 Feb 2023 17:56:12 +0100 Subject: Return NotFound when itemId isn't found --- .../SyncPlayAccessPolicy/SyncPlayAccessHandler.cs | 5 + Jellyfin.Api/Controllers/ImageController.cs | 14 ++- Jellyfin.Api/Controllers/ItemsController.cs | 5 + Jellyfin.Api/Controllers/LibraryController.cs | 4 + Jellyfin.Api/Controllers/LiveTvController.cs | 2 +- Jellyfin.Api/Controllers/MusicGenresController.cs | 5 + Jellyfin.Api/Controllers/PlaystateController.cs | 20 ++++ Jellyfin.Api/Controllers/SessionController.cs | 4 + Jellyfin.Api/Controllers/UserController.cs | 25 +++- Jellyfin.Api/Controllers/UserLibraryController.cs | 41 +++++++ Jellyfin.Api/Controllers/VideosController.cs | 7 +- Jellyfin.Api/Helpers/MediaInfoHelper.cs | 2 +- Jellyfin.Api/Helpers/RequestHelpers.cs | 7 +- Jellyfin.Api/Models/UserDtos/CreateUserByName.cs | 7 +- Jellyfin.Api/Models/UserDtos/ForgotPasswordDto.cs | 2 +- .../Models/UserDtos/ForgotPasswordPinDto.cs | 2 +- .../Devices/DeviceManager.cs | 5 + MediaBrowser.Controller/Dto/IDtoService.cs | 7 +- MediaBrowser.Controller/Library/IUserManager.cs | 10 +- .../Library/LibraryManagerExtensions.cs | 4 +- .../AuthHelper.cs | 28 +++++ .../Controllers/MusicGenreControllerTests.cs | 26 +++++ .../Controllers/UserControllerTests.cs | 12 +- .../Controllers/UserLibraryControllerTests.cs | 129 +++++++++++++++++++++ .../Controllers/VideosControllerTests.cs | 27 +++++ 25 files changed, 370 insertions(+), 30 deletions(-) create mode 100644 tests/Jellyfin.Server.Integration.Tests/Controllers/MusicGenreControllerTests.cs create mode 100644 tests/Jellyfin.Server.Integration.Tests/Controllers/UserLibraryControllerTests.cs create mode 100644 tests/Jellyfin.Server.Integration.Tests/Controllers/VideosControllerTests.cs (limited to 'MediaBrowser.Controller') diff --git a/Jellyfin.Api/Auth/SyncPlayAccessPolicy/SyncPlayAccessHandler.cs b/Jellyfin.Api/Auth/SyncPlayAccessPolicy/SyncPlayAccessHandler.cs index cdd7d8a52b..2ef244a0ad 100644 --- a/Jellyfin.Api/Auth/SyncPlayAccessPolicy/SyncPlayAccessHandler.cs +++ b/Jellyfin.Api/Auth/SyncPlayAccessPolicy/SyncPlayAccessHandler.cs @@ -2,6 +2,7 @@ using Jellyfin.Api.Extensions; using Jellyfin.Api.Helpers; using Jellyfin.Data.Enums; +using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Net; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.SyncPlay; @@ -47,6 +48,10 @@ namespace Jellyfin.Api.Auth.SyncPlayAccessPolicy var userId = context.User.GetUserId(); var user = _userManager.GetUserById(userId); + if (user is null) + { + throw new ResourceNotFoundException(); + } if (requirement.RequiredAccess == SyncPlayAccessRequirementType.HasAccess) { diff --git a/Jellyfin.Api/Controllers/ImageController.cs b/Jellyfin.Api/Controllers/ImageController.cs index cc824c65ab..7261c47e95 100644 --- a/Jellyfin.Api/Controllers/ImageController.cs +++ b/Jellyfin.Api/Controllers/ImageController.cs @@ -99,12 +99,17 @@ public class ImageController : BaseJellyfinApiController [FromRoute, Required] ImageType imageType, [FromQuery] int? index = null) { + var user = _userManager.GetUserById(userId); + if (user is null) + { + return NotFound(); + } + if (!RequestHelpers.AssertCanUpdateUser(_userManager, HttpContext.User, userId, true)) { return StatusCode(StatusCodes.Status403Forbidden, "User is not allowed to update the image."); } - var user = _userManager.GetUserById(userId); var memoryStream = await GetMemoryStream(Request.Body).ConfigureAwait(false); await using (memoryStream.ConfigureAwait(false)) { @@ -148,12 +153,17 @@ public class ImageController : BaseJellyfinApiController [FromRoute, Required] ImageType imageType, [FromRoute] int index) { + var user = _userManager.GetUserById(userId); + if (user is null) + { + return NotFound(); + } + if (!RequestHelpers.AssertCanUpdateUser(_userManager, HttpContext.User, userId, true)) { return StatusCode(StatusCodes.Status403Forbidden, "User is not allowed to update the image."); } - var user = _userManager.GetUserById(userId); var memoryStream = await GetMemoryStream(Request.Body).ConfigureAwait(false); await using (memoryStream.ConfigureAwait(false)) { diff --git a/Jellyfin.Api/Controllers/ItemsController.cs b/Jellyfin.Api/Controllers/ItemsController.cs index 134974dbe0..1bfc111af7 100644 --- a/Jellyfin.Api/Controllers/ItemsController.cs +++ b/Jellyfin.Api/Controllers/ItemsController.cs @@ -815,6 +815,11 @@ public class ItemsController : BaseJellyfinApiController [FromQuery] bool excludeActiveSessions = false) { var user = _userManager.GetUserById(userId); + if (user is null) + { + return NotFound(); + } + var parentIdGuid = parentId ?? Guid.Empty; var dtoOptions = new DtoOptions { Fields = fields } .AddClientFields(User) diff --git a/Jellyfin.Api/Controllers/LibraryController.cs b/Jellyfin.Api/Controllers/LibraryController.cs index 830f84849e..a311554b4d 100644 --- a/Jellyfin.Api/Controllers/LibraryController.cs +++ b/Jellyfin.Api/Controllers/LibraryController.cs @@ -452,6 +452,10 @@ public class LibraryController : BaseJellyfinApiController if (user is not null) { parent = TranslateParentItem(parent, user); + if (parent is null) + { + break; + } } baseItemDtos.Add(_dtoService.GetBaseItemDto(parent, dtoOptions, user)); diff --git a/Jellyfin.Api/Controllers/LiveTvController.cs b/Jellyfin.Api/Controllers/LiveTvController.cs index 21b4243464..1aa1d8a100 100644 --- a/Jellyfin.Api/Controllers/LiveTvController.cs +++ b/Jellyfin.Api/Controllers/LiveTvController.cs @@ -1211,7 +1211,7 @@ public class LiveTvController : BaseJellyfinApiController private async Task AssertUserCanManageLiveTv() { - var user = _userManager.GetUserById(User.GetUserId()); + var user = _userManager.GetUserById(User.GetUserId()) ?? throw new ResourceNotFoundException(); var session = await _sessionManager.LogSessionActivity( User.GetClient(), User.GetVersion(), diff --git a/Jellyfin.Api/Controllers/MusicGenresController.cs b/Jellyfin.Api/Controllers/MusicGenresController.cs index 302f138ebc..b08c8c4470 100644 --- a/Jellyfin.Api/Controllers/MusicGenresController.cs +++ b/Jellyfin.Api/Controllers/MusicGenresController.cs @@ -158,6 +158,11 @@ public class MusicGenresController : BaseJellyfinApiController item = _libraryManager.GetMusicGenre(genreName); } + if (item is null) + { + return NotFound(); + } + if (userId.HasValue && !userId.Value.Equals(default)) { var user = _userManager.GetUserById(userId.Value); diff --git a/Jellyfin.Api/Controllers/PlaystateController.cs b/Jellyfin.Api/Controllers/PlaystateController.cs index 18d6ebf1e0..ea8a59cfdf 100644 --- a/Jellyfin.Api/Controllers/PlaystateController.cs +++ b/Jellyfin.Api/Controllers/PlaystateController.cs @@ -77,6 +77,11 @@ public class PlaystateController : BaseJellyfinApiController [FromQuery, ModelBinder(typeof(LegacyDateTimeModelBinder))] DateTime? datePlayed) { var user = _userManager.GetUserById(userId); + if (user is null) + { + return NotFound(); + } + var session = await RequestHelpers.GetSession(_sessionManager, _userManager, HttpContext).ConfigureAwait(false); var item = _libraryManager.GetItemById(itemId); @@ -89,6 +94,11 @@ public class PlaystateController : BaseJellyfinApiController foreach (var additionalUserInfo in session.AdditionalUsers) { var additionalUser = _userManager.GetUserById(additionalUserInfo.UserId); + if (additionalUser is null) + { + return NotFound(); + } + UpdatePlayedStatus(additionalUser, item, true, datePlayed); } @@ -109,6 +119,11 @@ public class PlaystateController : BaseJellyfinApiController public async Task> MarkUnplayedItem([FromRoute, Required] Guid userId, [FromRoute, Required] Guid itemId) { var user = _userManager.GetUserById(userId); + if (user is null) + { + return NotFound(); + } + var session = await RequestHelpers.GetSession(_sessionManager, _userManager, HttpContext).ConfigureAwait(false); var item = _libraryManager.GetItemById(itemId); @@ -121,6 +136,11 @@ public class PlaystateController : BaseJellyfinApiController foreach (var additionalUserInfo in session.AdditionalUsers) { var additionalUser = _userManager.GetUserById(additionalUserInfo.UserId); + if (additionalUser is null) + { + return NotFound(); + } + UpdatePlayedStatus(additionalUser, item, false, null); } diff --git a/Jellyfin.Api/Controllers/SessionController.cs b/Jellyfin.Api/Controllers/SessionController.cs index ef33644785..782fcadbb8 100644 --- a/Jellyfin.Api/Controllers/SessionController.cs +++ b/Jellyfin.Api/Controllers/SessionController.cs @@ -75,6 +75,10 @@ public class SessionController : BaseJellyfinApiController result = result.Where(i => i.SupportsRemoteControl); var user = _userManager.GetUserById(controllableByUserId.Value); + if (user is null) + { + return NotFound(); + } if (!user.HasPermission(PermissionKind.EnableRemoteControlOfOtherUsers)) { diff --git a/Jellyfin.Api/Controllers/UserController.cs b/Jellyfin.Api/Controllers/UserController.cs index 7f184f31e7..911e501321 100644 --- a/Jellyfin.Api/Controllers/UserController.cs +++ b/Jellyfin.Api/Controllers/UserController.cs @@ -147,6 +147,11 @@ public class UserController : BaseJellyfinApiController public async Task DeleteUser([FromRoute, Required] Guid userId) { var user = _userManager.GetUserById(userId); + if (user is null) + { + return NotFound(); + } + await _sessionManager.RevokeUserTokens(user.Id, null).ConfigureAwait(false); await _userManager.DeleteUserAsync(userId).ConfigureAwait(false); return NoContent(); @@ -281,8 +286,8 @@ public class UserController : BaseJellyfinApiController { var success = await _userManager.AuthenticateUser( user.Username, - request.CurrentPw, - request.CurrentPw, + request.CurrentPw ?? string.Empty, + request.CurrentPw ?? string.Empty, HttpContext.GetNormalizedRemoteIp().ToString(), false).ConfigureAwait(false); @@ -292,7 +297,7 @@ public class UserController : BaseJellyfinApiController } } - await _userManager.ChangePassword(user, request.NewPw).ConfigureAwait(false); + await _userManager.ChangePassword(user, request.NewPw ?? string.Empty).ConfigureAwait(false); var currentToken = User.GetToken(); @@ -338,7 +343,7 @@ public class UserController : BaseJellyfinApiController } else { - await _userManager.ChangeEasyPassword(user, request.NewPw, request.NewPassword).ConfigureAwait(false); + await _userManager.ChangeEasyPassword(user, request.NewPw ?? string.Empty, request.NewPassword ?? string.Empty).ConfigureAwait(false); } return NoContent(); @@ -362,13 +367,17 @@ public class UserController : BaseJellyfinApiController [FromRoute, Required] Guid userId, [FromBody, Required] UserDto updateUser) { + var user = _userManager.GetUserById(userId); + if (user is null) + { + return NotFound(); + } + if (!RequestHelpers.AssertCanUpdateUser(_userManager, User, userId, true)) { return StatusCode(StatusCodes.Status403Forbidden, "User update not allowed."); } - var user = _userManager.GetUserById(userId); - if (!string.Equals(user.Username, updateUser.Name, StringComparison.Ordinal)) { await _userManager.RenameUser(user, updateUser.Name).ConfigureAwait(false); @@ -398,6 +407,10 @@ public class UserController : BaseJellyfinApiController [FromBody, Required] UserPolicy newPolicy) { var user = _userManager.GetUserById(userId); + if (user is null) + { + return NotFound(); + } // If removing admin access if (!newPolicy.IsAdministrator && user.HasPermission(PermissionKind.IsAdministrator)) diff --git a/Jellyfin.Api/Controllers/UserLibraryController.cs b/Jellyfin.Api/Controllers/UserLibraryController.cs index 556cf38945..1e54a9781a 100644 --- a/Jellyfin.Api/Controllers/UserLibraryController.cs +++ b/Jellyfin.Api/Controllers/UserLibraryController.cs @@ -79,10 +79,18 @@ public class UserLibraryController : BaseJellyfinApiController public async Task> GetItem([FromRoute, Required] Guid userId, [FromRoute, Required] Guid itemId) { var user = _userManager.GetUserById(userId); + if (user is null) + { + return NotFound(); + } var item = itemId.Equals(default) ? _libraryManager.GetUserRootFolder() : _libraryManager.GetItemById(itemId); + if (item is null) + { + return NotFound(); + } await RefreshItemOnDemandIfNeeded(item).ConfigureAwait(false); @@ -102,6 +110,11 @@ public class UserLibraryController : BaseJellyfinApiController public ActionResult GetRootFolder([FromRoute, Required] Guid userId) { var user = _userManager.GetUserById(userId); + if (user is null) + { + return NotFound(); + } + var item = _libraryManager.GetUserRootFolder(); var dtoOptions = new DtoOptions().AddClientFields(User); return _dtoService.GetBaseItemDto(item, dtoOptions, user); @@ -119,10 +132,18 @@ public class UserLibraryController : BaseJellyfinApiController public async Task>> GetIntros([FromRoute, Required] Guid userId, [FromRoute, Required] Guid itemId) { var user = _userManager.GetUserById(userId); + if (user is null) + { + return NotFound(); + } var item = itemId.Equals(default) ? _libraryManager.GetUserRootFolder() : _libraryManager.GetItemById(itemId); + if (item is null) + { + return NotFound(); + } var items = await _libraryManager.GetIntros(item, user).ConfigureAwait(false); var dtoOptions = new DtoOptions().AddClientFields(User); @@ -200,10 +221,18 @@ public class UserLibraryController : BaseJellyfinApiController public ActionResult> GetLocalTrailers([FromRoute, Required] Guid userId, [FromRoute, Required] Guid itemId) { var user = _userManager.GetUserById(userId); + if (user is null) + { + return NotFound(); + } var item = itemId.Equals(default) ? _libraryManager.GetUserRootFolder() : _libraryManager.GetItemById(itemId); + if (item is null) + { + return NotFound(); + } var dtoOptions = new DtoOptions().AddClientFields(User); @@ -230,10 +259,18 @@ public class UserLibraryController : BaseJellyfinApiController public ActionResult> GetSpecialFeatures([FromRoute, Required] Guid userId, [FromRoute, Required] Guid itemId) { var user = _userManager.GetUserById(userId); + if (user is null) + { + return NotFound(); + } var item = itemId.Equals(default) ? _libraryManager.GetUserRootFolder() : _libraryManager.GetItemById(itemId); + if (item is null) + { + return NotFound(); + } var dtoOptions = new DtoOptions().AddClientFields(User); @@ -275,6 +312,10 @@ public class UserLibraryController : BaseJellyfinApiController [FromQuery] bool groupItems = true) { var user = _userManager.GetUserById(userId); + if (user is null) + { + return NotFound(); + } if (!isPlayed.HasValue) { diff --git a/Jellyfin.Api/Controllers/VideosController.cs b/Jellyfin.Api/Controllers/VideosController.cs index 01a319879a..12aa47ead6 100644 --- a/Jellyfin.Api/Controllers/VideosController.cs +++ b/Jellyfin.Api/Controllers/VideosController.cs @@ -155,7 +155,12 @@ public class VideosController : BaseJellyfinApiController if (video.LinkedAlternateVersions.Length == 0) { - video = (Video)_libraryManager.GetItemById(video.PrimaryVersionId); + video = (Video?)_libraryManager.GetItemById(video.PrimaryVersionId); + } + + if (video is null) + { + return NotFound(); } foreach (var link in video.GetLinkedAlternateVersions()) diff --git a/Jellyfin.Api/Helpers/MediaInfoHelper.cs b/Jellyfin.Api/Helpers/MediaInfoHelper.cs index df37d96c60..5910d80737 100644 --- a/Jellyfin.Api/Helpers/MediaInfoHelper.cs +++ b/Jellyfin.Api/Helpers/MediaInfoHelper.cs @@ -200,7 +200,7 @@ public class MediaInfoHelper options.SubtitleStreamIndex = subtitleStreamIndex; } - var user = _userManager.GetUserById(userId); + var user = _userManager.GetUserById(userId) ?? throw new ResourceNotFoundException(); if (!enableDirectPlay) { diff --git a/Jellyfin.Api/Helpers/RequestHelpers.cs b/Jellyfin.Api/Helpers/RequestHelpers.cs index 3ce2b834d1..0b7a4fa1ac 100644 --- a/Jellyfin.Api/Helpers/RequestHelpers.cs +++ b/Jellyfin.Api/Helpers/RequestHelpers.cs @@ -81,6 +81,11 @@ public static class RequestHelpers } var user = userManager.GetUserById(userId); + if (user is null) + { + throw new ResourceNotFoundException(); + } + return user.EnableUserPreferenceAccess; } @@ -98,7 +103,7 @@ public static class RequestHelpers if (session is null) { - throw new ArgumentException("Session not found."); + throw new ResourceNotFoundException("Session not found."); } return session; diff --git a/Jellyfin.Api/Models/UserDtos/CreateUserByName.cs b/Jellyfin.Api/Models/UserDtos/CreateUserByName.cs index 0503c5d57e..6b6d9682ba 100644 --- a/Jellyfin.Api/Models/UserDtos/CreateUserByName.cs +++ b/Jellyfin.Api/Models/UserDtos/CreateUserByName.cs @@ -1,4 +1,6 @@ -namespace Jellyfin.Api.Models.UserDtos; +using System.ComponentModel.DataAnnotations; + +namespace Jellyfin.Api.Models.UserDtos; /// /// The create user by name request body. @@ -8,7 +10,8 @@ public class CreateUserByName /// /// Gets or sets the username. /// - public string? Name { get; set; } + [Required] + required public string Name { get; set; } /// /// Gets or sets the password. diff --git a/Jellyfin.Api/Models/UserDtos/ForgotPasswordDto.cs b/Jellyfin.Api/Models/UserDtos/ForgotPasswordDto.cs index ebe9297ea6..a0631fd07b 100644 --- a/Jellyfin.Api/Models/UserDtos/ForgotPasswordDto.cs +++ b/Jellyfin.Api/Models/UserDtos/ForgotPasswordDto.cs @@ -11,5 +11,5 @@ public class ForgotPasswordDto /// Gets or sets the entered username to have its password reset. /// [Required] - public string? EnteredUsername { get; set; } + required public string EnteredUsername { get; set; } } diff --git a/Jellyfin.Api/Models/UserDtos/ForgotPasswordPinDto.cs b/Jellyfin.Api/Models/UserDtos/ForgotPasswordPinDto.cs index 2949efe29f..79b8a5d63f 100644 --- a/Jellyfin.Api/Models/UserDtos/ForgotPasswordPinDto.cs +++ b/Jellyfin.Api/Models/UserDtos/ForgotPasswordPinDto.cs @@ -11,5 +11,5 @@ public class ForgotPasswordPinDto /// Gets or sets the entered pin to have the password reset. /// [Required] - public string? Pin { get; set; } + required public string Pin { get; set; } } diff --git a/Jellyfin.Server.Implementations/Devices/DeviceManager.cs b/Jellyfin.Server.Implementations/Devices/DeviceManager.cs index 8b15d6823d..a4b4c19599 100644 --- a/Jellyfin.Server.Implementations/Devices/DeviceManager.cs +++ b/Jellyfin.Server.Implementations/Devices/DeviceManager.cs @@ -9,6 +9,7 @@ using Jellyfin.Data.Enums; using Jellyfin.Data.Events; using Jellyfin.Data.Queries; using Jellyfin.Extensions; +using MediaBrowser.Common.Extensions; using MediaBrowser.Controller.Devices; using MediaBrowser.Controller.Library; using MediaBrowser.Model.Devices; @@ -185,6 +186,10 @@ namespace Jellyfin.Server.Implementations.Devices if (userId.HasValue) { var user = _userManager.GetUserById(userId.Value); + if (user is null) + { + throw new ResourceNotFoundException(); + } sessions = sessions.Where(i => CanAccessDevice(user, i.DeviceId)); } diff --git a/MediaBrowser.Controller/Dto/IDtoService.cs b/MediaBrowser.Controller/Dto/IDtoService.cs index 89aafc84fb..22453f0f76 100644 --- a/MediaBrowser.Controller/Dto/IDtoService.cs +++ b/MediaBrowser.Controller/Dto/IDtoService.cs @@ -1,4 +1,3 @@ -#nullable disable #pragma warning disable CA1002 using System.Collections.Generic; @@ -28,7 +27,7 @@ namespace MediaBrowser.Controller.Dto /// The user. /// The owner. /// BaseItemDto. - BaseItemDto GetBaseItemDto(BaseItem item, DtoOptions options, User user = null, BaseItem owner = null); + BaseItemDto GetBaseItemDto(BaseItem item, DtoOptions options, User? user = null, BaseItem? owner = null); /// /// Gets the base item dtos. @@ -38,7 +37,7 @@ namespace MediaBrowser.Controller.Dto /// The user. /// The owner. /// The of . - IReadOnlyList GetBaseItemDtos(IReadOnlyList items, DtoOptions options, User user = null, BaseItem owner = null); + IReadOnlyList GetBaseItemDtos(IReadOnlyList items, DtoOptions options, User? user = null, BaseItem? owner = null); /// /// Gets the item by name dto. @@ -48,6 +47,6 @@ namespace MediaBrowser.Controller.Dto /// The list of tagged items. /// The user. /// The item dto. - BaseItemDto GetItemByNameDto(BaseItem item, DtoOptions options, List taggedItems, User user = null); + BaseItemDto GetItemByNameDto(BaseItem item, DtoOptions options, List? taggedItems, User? user = null); } } diff --git a/MediaBrowser.Controller/Library/IUserManager.cs b/MediaBrowser.Controller/Library/IUserManager.cs index 993e3e18f9..37b4afcf32 100644 --- a/MediaBrowser.Controller/Library/IUserManager.cs +++ b/MediaBrowser.Controller/Library/IUserManager.cs @@ -1,5 +1,3 @@ -#nullable disable - #pragma warning disable CS1591 using System; @@ -47,14 +45,14 @@ namespace MediaBrowser.Controller.Library /// The id. /// The user with the specified Id, or null if the user doesn't exist. /// id is an empty Guid. - User GetUserById(Guid id); + User? GetUserById(Guid id); /// /// Gets the name of the user by. /// /// The name. /// User. - User GetUserByName(string name); + User? GetUserByName(string name); /// /// Renames the user. @@ -128,7 +126,7 @@ namespace MediaBrowser.Controller.Library /// The user. /// The remote end point. /// UserDto. - UserDto GetUserDto(User user, string remoteEndPoint = null); + UserDto GetUserDto(User user, string? remoteEndPoint = null); /// /// Authenticates the user. @@ -139,7 +137,7 @@ namespace MediaBrowser.Controller.Library /// Remove endpoint to use. /// Specifies if a user session. /// User wrapped in awaitable task. - Task AuthenticateUser(string username, string password, string passwordSha1, string remoteEndPoint, bool isUserSession); + Task AuthenticateUser(string username, string password, string passwordSha1, string remoteEndPoint, bool isUserSession); /// /// Starts the forgot password process. diff --git a/MediaBrowser.Controller/Library/LibraryManagerExtensions.cs b/MediaBrowser.Controller/Library/LibraryManagerExtensions.cs index 7bc8fa5abd..6d2c3c3d29 100644 --- a/MediaBrowser.Controller/Library/LibraryManagerExtensions.cs +++ b/MediaBrowser.Controller/Library/LibraryManagerExtensions.cs @@ -1,5 +1,3 @@ -#nullable disable - #pragma warning disable CS1591 using System; @@ -9,7 +7,7 @@ namespace MediaBrowser.Controller.Library { public static class LibraryManagerExtensions { - public static BaseItem GetItemById(this ILibraryManager manager, string id) + public static BaseItem? GetItemById(this ILibraryManager manager, string id) { return manager.GetItemById(new Guid(id)); } diff --git a/tests/Jellyfin.Server.Integration.Tests/AuthHelper.cs b/tests/Jellyfin.Server.Integration.Tests/AuthHelper.cs index 9eb0beda44..3737fee0ac 100644 --- a/tests/Jellyfin.Server.Integration.Tests/AuthHelper.cs +++ b/tests/Jellyfin.Server.Integration.Tests/AuthHelper.cs @@ -8,6 +8,7 @@ using System.Threading.Tasks; using Jellyfin.Api.Models.StartupDtos; using Jellyfin.Api.Models.UserDtos; using Jellyfin.Extensions.Json; +using MediaBrowser.Model.Dto; using Xunit; namespace Jellyfin.Server.Integration.Tests @@ -43,6 +44,33 @@ namespace Jellyfin.Server.Integration.Tests return auth!.AccessToken; } + public static async Task GetUserDtoAsync(HttpClient client) + { + using var response = await client.GetAsync("Users/Me").ConfigureAwait(false); + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + var userDto = await JsonSerializer.DeserializeAsync( + await response.Content.ReadAsStreamAsync().ConfigureAwait(false), JsonDefaults.Options).ConfigureAwait(false); + Assert.NotNull(userDto); + return userDto; + } + + public static async Task GetRootFolderDtoAsync(HttpClient client, Guid userId = default) + { + if (userId.Equals(default)) + { + var userDto = await GetUserDtoAsync(client).ConfigureAwait(false); + userId = userDto.Id; + } + + var response = await client.GetAsync($"Users/{userId}/Items/Root").ConfigureAwait(false); + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + var rootDto = await JsonSerializer.DeserializeAsync( + await response.Content.ReadAsStreamAsync().ConfigureAwait(false), + JsonDefaults.Options).ConfigureAwait(false); + Assert.NotNull(rootDto); + return rootDto; + } + public static void AddAuthHeader(this HttpHeaders headers, string accessToken) { headers.Add(AuthHeaderName, DummyAuthHeader + $", Token={accessToken}"); diff --git a/tests/Jellyfin.Server.Integration.Tests/Controllers/MusicGenreControllerTests.cs b/tests/Jellyfin.Server.Integration.Tests/Controllers/MusicGenreControllerTests.cs new file mode 100644 index 0000000000..17f3dc99fd --- /dev/null +++ b/tests/Jellyfin.Server.Integration.Tests/Controllers/MusicGenreControllerTests.cs @@ -0,0 +1,26 @@ +using System.Net; +using System.Threading.Tasks; +using Xunit; + +namespace Jellyfin.Server.Integration.Tests.Controllers; + +public sealed class MusicGenreControllerTests : IClassFixture +{ + private readonly JellyfinApplicationFactory _factory; + private static string? _accessToken; + + public MusicGenreControllerTests(JellyfinApplicationFactory factory) + { + _factory = factory; + } + + [Fact] + public async Task MusicGenres_FakeMusicGenre_NotFound() + { + var client = _factory.CreateClient(); + client.DefaultRequestHeaders.AddAuthHeader(_accessToken ??= await AuthHelper.CompleteStartupAsync(client).ConfigureAwait(false)); + + var response = await client.GetAsync("MusicGenres/Fake-MusicGenre").ConfigureAwait(false); + Assert.Equal(HttpStatusCode.NotFound, response.StatusCode); + } +} diff --git a/tests/Jellyfin.Server.Integration.Tests/Controllers/UserControllerTests.cs b/tests/Jellyfin.Server.Integration.Tests/Controllers/UserControllerTests.cs index 2b825a93a0..e5cde66762 100644 --- a/tests/Jellyfin.Server.Integration.Tests/Controllers/UserControllerTests.cs +++ b/tests/Jellyfin.Server.Integration.Tests/Controllers/UserControllerTests.cs @@ -66,6 +66,16 @@ namespace Jellyfin.Server.Integration.Tests.Controllers Assert.False(users![0].HasConfiguredPassword); } + [Fact] + [Priority(-1)] + public async Task Me_Valid_Success() + { + var client = _factory.CreateClient(); + client.DefaultRequestHeaders.AddAuthHeader(_accessToken ??= await AuthHelper.CompleteStartupAsync(client).ConfigureAwait(false)); + + _ = await AuthHelper.GetUserDtoAsync(client).ConfigureAwait(false); + } + [Fact] [Priority(0)] public async Task New_Valid_Success() @@ -108,7 +118,7 @@ namespace Jellyfin.Server.Integration.Tests.Controllers var createRequest = new CreateUserByName() { - Name = username + Name = username! }; using var response = await CreateUserByName(client, createRequest).ConfigureAwait(false); diff --git a/tests/Jellyfin.Server.Integration.Tests/Controllers/UserLibraryControllerTests.cs b/tests/Jellyfin.Server.Integration.Tests/Controllers/UserLibraryControllerTests.cs new file mode 100644 index 0000000000..69f2ccf339 --- /dev/null +++ b/tests/Jellyfin.Server.Integration.Tests/Controllers/UserLibraryControllerTests.cs @@ -0,0 +1,129 @@ +using System; +using System.Globalization; +using System.Net; +using System.Text.Json; +using System.Threading.Tasks; +using Jellyfin.Extensions.Json; +using MediaBrowser.Model.Dto; +using MediaBrowser.Model.Querying; +using Xunit; + +namespace Jellyfin.Server.Integration.Tests.Controllers; + +public sealed class UserLibraryControllerTests : IClassFixture +{ + private readonly JellyfinApplicationFactory _factory; + private readonly JsonSerializerOptions _jsonOptions = JsonDefaults.Options; + private static string? _accessToken; + + public UserLibraryControllerTests(JellyfinApplicationFactory factory) + { + _factory = factory; + } + + [Fact] + public async Task GetRootFolder_NonExistenUserId_NotFound() + { + var client = _factory.CreateClient(); + client.DefaultRequestHeaders.AddAuthHeader(_accessToken ??= await AuthHelper.CompleteStartupAsync(client).ConfigureAwait(false)); + + var response = await client.GetAsync($"Users/{Guid.NewGuid()}/Items/Root").ConfigureAwait(false); + Assert.Equal(HttpStatusCode.NotFound, response.StatusCode); + } + + [Fact] + public async Task GetRootFolder_UserId_Valid() + { + var client = _factory.CreateClient(); + client.DefaultRequestHeaders.AddAuthHeader(_accessToken ??= await AuthHelper.CompleteStartupAsync(client).ConfigureAwait(false)); + + _ = await AuthHelper.GetRootFolderDtoAsync(client).ConfigureAwait(false); + } + + [Theory] + [InlineData("Users/{0}/Items/{1}")] + [InlineData("Users/{0}/Items/{1}/Intros")] + [InlineData("Users/{0}/Items/{1}/LocalTrailers")] + [InlineData("Users/{0}/Items/{1}/SpecialFeatures")] + [InlineData("Users/{0}/Items/{1}/Lyrics")] + public async Task GetItem_NonExistenUserId_NotFound(string format) + { + var client = _factory.CreateClient(); + client.DefaultRequestHeaders.AddAuthHeader(_accessToken ??= await AuthHelper.CompleteStartupAsync(client).ConfigureAwait(false)); + + var rootFolderDto = await AuthHelper.GetRootFolderDtoAsync(client).ConfigureAwait(false); + + var response = await client.GetAsync(string.Format(CultureInfo.InvariantCulture, format, Guid.NewGuid(), rootFolderDto.Id)).ConfigureAwait(false); + Assert.Equal(HttpStatusCode.NotFound, response.StatusCode); + } + + [Theory] + [InlineData("Users/{0}/Items/{1}")] + [InlineData("Users/{0}/Items/{1}/Intros")] + [InlineData("Users/{0}/Items/{1}/LocalTrailers")] + [InlineData("Users/{0}/Items/{1}/SpecialFeatures")] + [InlineData("Users/{0}/Items/{1}/Lyrics")] + public async Task GetItem_NonExistentItemId_NotFound(string format) + { + var client = _factory.CreateClient(); + client.DefaultRequestHeaders.AddAuthHeader(_accessToken ??= await AuthHelper.CompleteStartupAsync(client).ConfigureAwait(false)); + + var userDto = await AuthHelper.GetUserDtoAsync(client).ConfigureAwait(false); + + var response = await client.GetAsync(string.Format(CultureInfo.InvariantCulture, format, userDto.Id, Guid.NewGuid())).ConfigureAwait(false); + Assert.Equal(HttpStatusCode.NotFound, response.StatusCode); + } + + [Fact] + public async Task GetItem_UserIdAndItemId_Valid() + { + var client = _factory.CreateClient(); + client.DefaultRequestHeaders.AddAuthHeader(_accessToken ??= await AuthHelper.CompleteStartupAsync(client).ConfigureAwait(false)); + + var userDto = await AuthHelper.GetUserDtoAsync(client).ConfigureAwait(false); + var rootFolderDto = await AuthHelper.GetRootFolderDtoAsync(client, userDto.Id).ConfigureAwait(false); + + var response = await client.GetAsync($"Users/{userDto.Id}/Items/{rootFolderDto.Id}").ConfigureAwait(false); + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + var rootDto = await JsonSerializer.DeserializeAsync( + await response.Content.ReadAsStreamAsync().ConfigureAwait(false), + _jsonOptions).ConfigureAwait(false); + Assert.NotNull(rootDto); + } + + [Fact] + public async Task GetIntros_UserIdAndItemId_Valid() + { + var client = _factory.CreateClient(); + client.DefaultRequestHeaders.AddAuthHeader(_accessToken ??= await AuthHelper.CompleteStartupAsync(client).ConfigureAwait(false)); + + var userDto = await AuthHelper.GetUserDtoAsync(client).ConfigureAwait(false); + var rootFolderDto = await AuthHelper.GetRootFolderDtoAsync(client, userDto.Id).ConfigureAwait(false); + + var response = await client.GetAsync($"Users/{userDto.Id}/Items/{rootFolderDto.Id}/Intros").ConfigureAwait(false); + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + var rootDto = await JsonSerializer.DeserializeAsync>( + await response.Content.ReadAsStreamAsync().ConfigureAwait(false), + _jsonOptions).ConfigureAwait(false); + Assert.NotNull(rootDto); + } + + [Theory] + [InlineData("Users/{0}/Items/{1}/LocalTrailers")] + [InlineData("Users/{0}/Items/{1}/SpecialFeatures")] + public async Task LocalTrailersAndSpecialFeatures_UserIdAndItemId_Valid(string format) + { + var client = _factory.CreateClient(); + client.DefaultRequestHeaders.AddAuthHeader(_accessToken ??= await AuthHelper.CompleteStartupAsync(client).ConfigureAwait(false)); + + var userDto = await AuthHelper.GetUserDtoAsync(client).ConfigureAwait(false); + var rootFolderDto = await AuthHelper.GetRootFolderDtoAsync(client, userDto.Id).ConfigureAwait(false); + + var response = await client.GetAsync(string.Format(CultureInfo.InvariantCulture, format, userDto.Id, rootFolderDto.Id)).ConfigureAwait(false); + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + var rootDto = await JsonSerializer.DeserializeAsync( + await response.Content.ReadAsStreamAsync().ConfigureAwait(false), + _jsonOptions).ConfigureAwait(false); + Assert.NotNull(rootDto); + } +} diff --git a/tests/Jellyfin.Server.Integration.Tests/Controllers/VideosControllerTests.cs b/tests/Jellyfin.Server.Integration.Tests/Controllers/VideosControllerTests.cs new file mode 100644 index 0000000000..0f9a2e90aa --- /dev/null +++ b/tests/Jellyfin.Server.Integration.Tests/Controllers/VideosControllerTests.cs @@ -0,0 +1,27 @@ +using System; +using System.Net; +using System.Threading.Tasks; +using Xunit; + +namespace Jellyfin.Server.Integration.Tests.Controllers; + +public sealed class VideosControllerTests : IClassFixture +{ + private readonly JellyfinApplicationFactory _factory; + private static string? _accessToken; + + public VideosControllerTests(JellyfinApplicationFactory factory) + { + _factory = factory; + } + + [Fact] + public async Task DeleteAlternateSources_NonExistentItemId_NotFound() + { + var client = _factory.CreateClient(); + client.DefaultRequestHeaders.AddAuthHeader(_accessToken ??= await AuthHelper.CompleteStartupAsync(client).ConfigureAwait(false)); + + var response = await client.DeleteAsync($"Videos/{Guid.NewGuid()}").ConfigureAwait(false); + Assert.Equal(HttpStatusCode.NotFound, response.StatusCode); + } +} -- cgit v1.2.3 From ef4ae9a2dd9d5aff87262910e87d734ef3183125 Mon Sep 17 00:00:00 2001 From: gnattu Date: Thu, 9 Feb 2023 06:42:17 +0800 Subject: Implement hardware filters for videotoolbox, use Apple AAC encoder when available (#7807) --- .../MediaEncoding/EncodingHelper.cs | 86 ++++++++++++++++++++++ .../Encoder/EncoderValidator.cs | 6 +- 2 files changed, 91 insertions(+), 1 deletion(-) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 9b5edabc06..14547d4406 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -559,6 +559,12 @@ namespace MediaBrowser.Controller.MediaEncoding if (string.Equals(codec, "aac", StringComparison.OrdinalIgnoreCase)) { + // Use Apple's aac encoder if available as it provides best audio quality + if (_mediaEncoder.SupportsEncoder("aac_at")) + { + return "aac_at"; + } + // Use libfdk_aac for better audio quality if using custom build of FFmpeg which has fdk_aac support if (_mediaEncoder.SupportsEncoder("libfdk_aac")) { @@ -2814,6 +2820,13 @@ namespace MediaBrowser.Controller.MediaEncoding { return "deinterlace_qsv=mode=2"; } + else if (hwDeintSuffix.Contains("videotoolbox", StringComparison.OrdinalIgnoreCase)) + { + return string.Format( + CultureInfo.InvariantCulture, + "yadif_videotoolbox={0}:-1:0", + doubleRateDeint ? "1" : "0"); + } return string.Empty; } @@ -4450,6 +4463,75 @@ namespace MediaBrowser.Controller.MediaEncoding return (mainFilters, subFilters, overlayFilters); } + /// + /// Gets the parameter of Apple VideoToolBox filter chain. + /// + /// Encoding state. + /// Encoding options. + /// Video encoder to use. + /// The tuple contains three lists: main, sub and overlay filters. + public (List MainFilters, List SubFilters, List OverlayFilters) GetAppleVidFilterChain( + EncodingJobInfo state, + EncodingOptions options, + string vidEncoder) + { + if (!string.Equals(options.HardwareAccelerationType, "videotoolbox", StringComparison.OrdinalIgnoreCase)) + { + return (null, null, null); + } + + var swFilterChain = GetSwVidFilterChain(state, options, vidEncoder); + + if (!options.EnableHardwareEncoding) + { + return swFilterChain; + } + + if (_mediaEncoder.EncoderVersion.CompareTo(new Version("5.0.0")) < 0) + { + // All features used here requires ffmpeg 5.0 or later, fallback to software filters if using an old ffmpeg + return swFilterChain; + } + + var doDeintH264 = state.DeInterlace("h264", true) || state.DeInterlace("avc", true); + var doDeintHevc = state.DeInterlace("h265", true) || state.DeInterlace("hevc", true); + var doDeintH2645 = doDeintH264 || doDeintHevc; + var inW = state.VideoStream?.Width; + var inH = state.VideoStream?.Height; + var reqW = state.BaseRequest.Width; + var reqH = state.BaseRequest.Height; + var reqMaxW = state.BaseRequest.MaxWidth; + var reqMaxH = state.BaseRequest.MaxHeight; + var threeDFormat = state.MediaSource.Video3DFormat; + var newfilters = new List(); + var noOverlay = swFilterChain.OverlayFilters.Count == 0; + var supportsHwDeint = _mediaEncoder.SupportsFilter("yadif_videotoolbox"); + // fallback to software filters if we are using filters not supported by hardware yet. + var useHardwareFilters = noOverlay && (!doDeintH2645 || supportsHwDeint); + + if (!useHardwareFilters) + { + return swFilterChain; + } + + // ffmpeg cannot use videotoolbox to scale + var swScaleFilter = GetSwScaleFilter(state, options, vidEncoder, inW, inH, threeDFormat, reqW, reqH, reqMaxW, reqMaxH); + newfilters.Add(swScaleFilter); + + // hwupload on videotoolbox encoders can automatically convert AVFrame into its CVPixelBuffer equivalent + // videotoolbox will automatically convert the CVPixelBuffer to a pixel format the encoder supports, so we don't have to set a pixel format explicitly here + // This will reduce CPU usage significantly on UHD videos with 10 bit colors because we bypassed the ffmpeg pixel format conversion + newfilters.Add("hwupload"); + + if (doDeintH2645) + { + var deintFilter = GetHwDeinterlaceFilter(state, options, "videotoolbox"); + newfilters.Add(deintFilter); + } + + return (newfilters, swFilterChain.SubFilters, swFilterChain.OverlayFilters); + } + /// /// Gets the parameter of video processing filters. /// @@ -4492,6 +4574,10 @@ namespace MediaBrowser.Controller.MediaEncoding { (mainFilters, subFilters, overlayFilters) = GetAmdVidFilterChain(state, options, outputVideoCodec); } + else if (string.Equals(options.HardwareAccelerationType, "videotoolbox", StringComparison.OrdinalIgnoreCase)) + { + (mainFilters, subFilters, overlayFilters) = GetAppleVidFilterChain(state, options, outputVideoCodec); + } else { (mainFilters, subFilters, overlayFilters) = GetSwVidFilterChain(state, options, outputVideoCodec); diff --git a/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs b/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs index 8479b7d50d..9e6134b524 100644 --- a/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs +++ b/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs @@ -56,6 +56,7 @@ namespace MediaBrowser.MediaEncoding.Encoder "libvpx", "libvpx-vp9", "aac", + "aac_at", "libfdk_aac", "ac3", "libmp3lame", @@ -106,7 +107,10 @@ namespace MediaBrowser.MediaEncoding.Encoder // vulkan "libplacebo", "scale_vulkan", - "overlay_vulkan" + "overlay_vulkan", + "hwupload_vaapi", + // videotoolbox + "yadif_videotoolbox" }; private static readonly IReadOnlyDictionary _filterOptionsDict = new Dictionary -- cgit v1.2.3 From cb61a57e828f1e35b32cdb020a57bb4df35a5b3a Mon Sep 17 00:00:00 2001 From: Jpuc1143 <80900349+Jpuc1143@users.noreply.github.com> Date: Thu, 9 Feb 2023 20:45:40 -0300 Subject: Reduced number of calls to GetPreference() Co-authored-by: Cody Robibero --- MediaBrowser.Controller/Entities/BaseItem.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index 0cd9720549..3d683052fe 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -1607,7 +1607,8 @@ namespace MediaBrowser.Controller.Entities return false; } - if (user.GetPreference(PreferenceKind.AllowedTags).Any() && !user.GetPreference(PreferenceKind.AllowedTags).Any(i => Tags.Contains(i, StringComparison.OrdinalIgnoreCase))) + var allowedTagsPreference = user.GetPreference(PreferenceKind.AllowedTags); + if (allowedTagsPreference.Any() && !allowedTagsPreference.Any(i => Tags.Contains(i, StringComparison.OrdinalIgnoreCase))) { return false; } -- cgit v1.2.3 From b7418d6e9e08af44edfc30971cd7b1b7871554c7 Mon Sep 17 00:00:00 2001 From: Shadowghost Date: Mon, 13 Feb 2023 15:42:04 +0100 Subject: Add permission for collection management --- Jellyfin.Api/Auth/UserPermissionPolicy/UserPermissionHandler.cs | 3 +-- .../Auth/UserPermissionPolicy/UserPermissionRequirement.cs | 2 +- Jellyfin.Api/Constants/Policies.cs | 5 +++++ Jellyfin.Api/Controllers/CollectionController.cs | 3 ++- Jellyfin.Data/Entities/User.cs | 1 + Jellyfin.Data/Enums/PermissionKind.cs | 7 ++++++- Jellyfin.Server.Implementations/Users/UserManager.cs | 2 ++ Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs | 2 +- Jellyfin.Server/Migrations/Routines/MigrateUserDb.cs | 1 + MediaBrowser.Controller/Entities/Movies/BoxSet.cs | 2 +- MediaBrowser.Model/Users/UserPolicy.cs | 7 +++++++ 11 files changed, 28 insertions(+), 7 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/Jellyfin.Api/Auth/UserPermissionPolicy/UserPermissionHandler.cs b/Jellyfin.Api/Auth/UserPermissionPolicy/UserPermissionHandler.cs index ba2b1b657e..e72bec46fd 100644 --- a/Jellyfin.Api/Auth/UserPermissionPolicy/UserPermissionHandler.cs +++ b/Jellyfin.Api/Auth/UserPermissionPolicy/UserPermissionHandler.cs @@ -1,5 +1,4 @@ using System.Threading.Tasks; -using Jellyfin.Api.Auth.DownloadPolicy; using Jellyfin.Api.Extensions; using MediaBrowser.Common.Extensions; using MediaBrowser.Controller.Library; @@ -8,7 +7,7 @@ using Microsoft.AspNetCore.Authorization; namespace Jellyfin.Api.Auth.UserPermissionPolicy { /// - /// Download authorization handler. + /// User permission authorization handler. /// public class UserPermissionHandler : AuthorizationHandler { diff --git a/Jellyfin.Api/Auth/UserPermissionPolicy/UserPermissionRequirement.cs b/Jellyfin.Api/Auth/UserPermissionPolicy/UserPermissionRequirement.cs index 195a611992..4694556eb7 100644 --- a/Jellyfin.Api/Auth/UserPermissionPolicy/UserPermissionRequirement.cs +++ b/Jellyfin.Api/Auth/UserPermissionPolicy/UserPermissionRequirement.cs @@ -1,7 +1,7 @@ using Jellyfin.Api.Auth.DefaultAuthorizationPolicy; using Jellyfin.Data.Enums; -namespace Jellyfin.Api.Auth.DownloadPolicy +namespace Jellyfin.Api.Auth.UserPermissionPolicy { /// /// The user permission requirement. diff --git a/Jellyfin.Api/Constants/Policies.cs b/Jellyfin.Api/Constants/Policies.cs index adc95e57b2..1ef38ca072 100644 --- a/Jellyfin.Api/Constants/Policies.cs +++ b/Jellyfin.Api/Constants/Policies.cs @@ -69,4 +69,9 @@ public static class Policies /// Policy name for accessing a SyncPlay group. /// public const string SyncPlayIsInGroup = "SyncPlayIsInGroup"; + + /// + /// Policy name for accessing collection management. + /// + public const string CollectionManagement = "CollectionManagement"; } diff --git a/Jellyfin.Api/Controllers/CollectionController.cs b/Jellyfin.Api/Controllers/CollectionController.cs index f9f9be7ce4..2db04afb80 100644 --- a/Jellyfin.Api/Controllers/CollectionController.cs +++ b/Jellyfin.Api/Controllers/CollectionController.cs @@ -1,6 +1,7 @@ using System; using System.ComponentModel.DataAnnotations; using System.Threading.Tasks; +using Jellyfin.Api.Constants; using Jellyfin.Api.Extensions; using Jellyfin.Api.ModelBinders; using MediaBrowser.Controller.Collections; @@ -16,7 +17,7 @@ namespace Jellyfin.Api.Controllers; /// The collection controller. /// [Route("Collections")] -[Authorize] +[Authorize(Policy = Policies.CollectionManagement)] public class CollectionController : BaseJellyfinApiController { private readonly ICollectionManager _collectionManager; diff --git a/Jellyfin.Data/Entities/User.cs b/Jellyfin.Data/Entities/User.cs index 4ce581749f..606e1b5427 100644 --- a/Jellyfin.Data/Entities/User.cs +++ b/Jellyfin.Data/Entities/User.cs @@ -508,6 +508,7 @@ namespace Jellyfin.Data.Entities Permissions.Add(new Permission(PermissionKind.EnableVideoPlaybackTranscoding, true)); Permissions.Add(new Permission(PermissionKind.ForceRemoteSourceTranscoding, false)); Permissions.Add(new Permission(PermissionKind.EnableRemoteControlOfOtherUsers, false)); + Permissions.Add(new Permission(PermissionKind.EnableCollectionManagement, false)); } /// diff --git a/Jellyfin.Data/Enums/PermissionKind.cs b/Jellyfin.Data/Enums/PermissionKind.cs index 7d52008747..40280b95ef 100644 --- a/Jellyfin.Data/Enums/PermissionKind.cs +++ b/Jellyfin.Data/Enums/PermissionKind.cs @@ -108,6 +108,11 @@ namespace Jellyfin.Data.Enums /// /// Whether the server should force transcoding on remote connections for the user. /// - ForceRemoteSourceTranscoding = 20 + ForceRemoteSourceTranscoding = 20, + + /// + /// Whether the user can create, modify and delete collections. + /// + EnableCollectionManagement = 21 } } diff --git a/Jellyfin.Server.Implementations/Users/UserManager.cs b/Jellyfin.Server.Implementations/Users/UserManager.cs index f9679510d7..92384986af 100644 --- a/Jellyfin.Server.Implementations/Users/UserManager.cs +++ b/Jellyfin.Server.Implementations/Users/UserManager.cs @@ -369,6 +369,7 @@ namespace Jellyfin.Server.Implementations.Users EnablePlaybackRemuxing = user.HasPermission(PermissionKind.EnablePlaybackRemuxing), ForceRemoteSourceTranscoding = user.HasPermission(PermissionKind.ForceRemoteSourceTranscoding), EnablePublicSharing = user.HasPermission(PermissionKind.EnablePublicSharing), + EnableCollectionManagement = user.HasPermission(PermissionKind.EnableCollectionManagement), AccessSchedules = user.AccessSchedules.ToArray(), BlockedTags = user.GetPreference(PreferenceKind.BlockedTags), AllowedTags = user.GetPreference(PreferenceKind.AllowedTags), @@ -685,6 +686,7 @@ namespace Jellyfin.Server.Implementations.Users user.SetPermission(PermissionKind.EnableAllFolders, policy.EnableAllFolders); user.SetPermission(PermissionKind.EnableRemoteControlOfOtherUsers, policy.EnableRemoteControlOfOtherUsers); user.SetPermission(PermissionKind.EnablePlaybackRemuxing, policy.EnablePlaybackRemuxing); + user.SetPermission(PermissionKind.EnableCollectionManagement, policy.EnableCollectionManagement); user.SetPermission(PermissionKind.ForceRemoteSourceTranscoding, policy.ForceRemoteSourceTranscoding); user.SetPermission(PermissionKind.EnablePublicSharing, policy.EnablePublicSharing); diff --git a/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs b/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs index 968a8e58ce..dffcfbba87 100644 --- a/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs +++ b/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs @@ -10,7 +10,6 @@ using Emby.Server.Implementations; using Jellyfin.Api.Auth; using Jellyfin.Api.Auth.AnonymousLanAccessPolicy; using Jellyfin.Api.Auth.DefaultAuthorizationPolicy; -using Jellyfin.Api.Auth.DownloadPolicy; using Jellyfin.Api.Auth.FirstTimeSetupPolicy; using Jellyfin.Api.Auth.SyncPlayAccessPolicy; using Jellyfin.Api.Auth.UserPermissionPolicy; @@ -75,6 +74,7 @@ namespace Jellyfin.Server.Extensions options.AddPolicy(Policies.SyncPlayCreateGroup, new SyncPlayAccessRequirement(SyncPlayAccessRequirementType.CreateGroup)); options.AddPolicy(Policies.SyncPlayJoinGroup, new SyncPlayAccessRequirement(SyncPlayAccessRequirementType.JoinGroup)); options.AddPolicy(Policies.SyncPlayIsInGroup, new SyncPlayAccessRequirement(SyncPlayAccessRequirementType.IsInGroup)); + options.AddPolicy(Policies.CollectionManagement, new UserPermissionRequirement(PermissionKind.EnableCollectionManagement)); options.AddPolicy(Policies.AnonymousLanAccessPolicy, new AnonymousLanAccessRequirement()); options.AddPolicy( Policies.RequiresElevation, diff --git a/Jellyfin.Server/Migrations/Routines/MigrateUserDb.cs b/Jellyfin.Server/Migrations/Routines/MigrateUserDb.cs index ea2f033027..9bf1e6b808 100644 --- a/Jellyfin.Server/Migrations/Routines/MigrateUserDb.cs +++ b/Jellyfin.Server/Migrations/Routines/MigrateUserDb.cs @@ -163,6 +163,7 @@ namespace Jellyfin.Server.Migrations.Routines user.SetPermission(PermissionKind.EnablePlaybackRemuxing, policy.EnablePlaybackRemuxing); user.SetPermission(PermissionKind.ForceRemoteSourceTranscoding, policy.ForceRemoteSourceTranscoding); user.SetPermission(PermissionKind.EnablePublicSharing, policy.EnablePublicSharing); + user.SetPermission(PermissionKind.EnableCollectionManagement, policy.EnableCollectionManagement); foreach (var policyAccessSchedule in policy.AccessSchedules) { diff --git a/MediaBrowser.Controller/Entities/Movies/BoxSet.cs b/MediaBrowser.Controller/Entities/Movies/BoxSet.cs index 882abc9272..66210cb6c4 100644 --- a/MediaBrowser.Controller/Entities/Movies/BoxSet.cs +++ b/MediaBrowser.Controller/Entities/Movies/BoxSet.cs @@ -104,7 +104,7 @@ namespace MediaBrowser.Controller.Entities.Movies public override bool IsAuthorizedToDelete(User user, List allCollectionFolders) { - return true; + return user.HasPermission(PermissionKind.IsAdministrator) || user.HasPermission(PermissionKind.EnableCollectionManagement); } public override bool IsSaveLocalMetadataEnabled() diff --git a/MediaBrowser.Model/Users/UserPolicy.cs b/MediaBrowser.Model/Users/UserPolicy.cs index 1619dac5ad..cc7d57eb0a 100644 --- a/MediaBrowser.Model/Users/UserPolicy.cs +++ b/MediaBrowser.Model/Users/UserPolicy.cs @@ -13,6 +13,7 @@ namespace MediaBrowser.Model.Users public UserPolicy() { IsHidden = true; + EnableCollectionManagement = false; EnableContentDeletion = false; EnableContentDeletionFromFolders = Array.Empty(); @@ -73,6 +74,12 @@ namespace MediaBrowser.Model.Users /// true if this instance is hidden; otherwise, false. public bool IsHidden { get; set; } + /// + /// Gets or sets a value indicating whether this instance can manage collections. + /// + /// true if this instance is hidden; otherwise, false. + public bool EnableCollectionManagement { get; set; } + /// /// Gets or sets a value indicating whether this instance is disabled. /// -- cgit v1.2.3