From fb090df0b59b71d7f143d2181d46f18943bbc35e Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Fri, 7 May 2021 00:39:20 +0200 Subject: Enable nullable reference types for MediaBrowser.Controller --- MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs | 2 ++ 1 file changed, 2 insertions(+) (limited to 'MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs') diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 2b5364775..97cb8d63b 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -1,3 +1,5 @@ +#nullable disable + #pragma warning disable CS1591 using System; -- cgit v1.2.3 From 6bcbc2b88ae84b1d7cfc50f0872580bed437a60f Mon Sep 17 00:00:00 2001 From: crobibero Date: Thu, 13 May 2021 07:32:02 -0600 Subject: Reduce warnings in MediaBrowser.Controller --- MediaBrowser.Controller/Channels/Channel.cs | 2 +- .../Channels/IChannelManager.cs | 26 +++- .../Channels/IDisableMediaSourceDisplay.cs | 8 + .../Channels/IHasFolderAttributes.cs | 9 ++ .../Channels/IRequiresMediaInfoCallback.cs | 8 +- .../Channels/ISearchableChannel.cs | 32 ---- .../Channels/ISupportsDelete.cs | 17 +++ .../Channels/ISupportsLatestMedia.cs | 21 +++ .../Channels/ISupportsMediaProbe.cs | 8 + .../Channels/InternalChannelFeatures.cs | 4 +- MediaBrowser.Controller/Devices/IDeviceManager.cs | 4 +- MediaBrowser.Controller/Dto/IDtoService.cs | 6 + .../Entities/AggregateFolder.cs | 8 +- .../Entities/Audio/MusicArtist.cs | 4 +- .../Entities/Audio/MusicGenre.cs | 6 +- MediaBrowser.Controller/Entities/BaseItem.cs | 39 +++-- .../Entities/CollectionFolder.cs | 66 ++++---- MediaBrowser.Controller/Entities/Folder.cs | 170 ++++++++++----------- MediaBrowser.Controller/Entities/Genre.cs | 42 +++-- MediaBrowser.Controller/Entities/IHasSeries.cs | 2 +- MediaBrowser.Controller/Entities/IHasShares.cs | 11 ++ MediaBrowser.Controller/Entities/Movies/Movie.cs | 4 +- MediaBrowser.Controller/Entities/MusicVideo.cs | 4 +- MediaBrowser.Controller/Entities/Person.cs | 9 +- MediaBrowser.Controller/Entities/Share.cs | 5 - MediaBrowser.Controller/Entities/Studio.cs | 6 +- MediaBrowser.Controller/Entities/TV/Episode.cs | 13 +- MediaBrowser.Controller/Entities/TV/Season.cs | 6 +- MediaBrowser.Controller/Entities/TV/Series.cs | 5 +- MediaBrowser.Controller/Entities/Trailer.cs | 4 +- MediaBrowser.Controller/Entities/UserItemData.cs | 2 +- MediaBrowser.Controller/Entities/UserRootFolder.cs | 5 +- MediaBrowser.Controller/Entities/UserView.cs | 20 ++- MediaBrowser.Controller/Entities/Year.cs | 10 +- .../Extensions/StringExtensions.cs | 2 +- MediaBrowser.Controller/Library/ILibraryManager.cs | 6 + MediaBrowser.Controller/LiveTv/LiveTvChannel.cs | 2 +- MediaBrowser.Controller/LiveTv/LiveTvProgram.cs | 2 +- MediaBrowser.Controller/LiveTv/TimerInfo.cs | 15 +- .../MediaEncoding/EncodingHelper.cs | 1 + .../MediaEncoding/EncodingJobInfo.cs | 31 +--- .../MediaEncoding/IMediaEncoder.cs | 2 +- .../MediaEncoding/TranscodingJobType.cs | 23 +++ MediaBrowser.Controller/Playlists/Playlist.cs | 3 +- .../Plugins/IRunBeforeStartup.cs | 9 ++ .../Plugins/IServerEntryPoint.cs | 8 +- .../Providers/MetadataRefreshOptions.cs | 2 +- MediaBrowser.Controller/Sync/IHasDynamicAccess.cs | 22 --- .../Sync/IRemoteSyncProvider.cs | 9 -- .../Sync/IServerSyncProvider.cs | 32 ---- MediaBrowser.Controller/Sync/ISyncProvider.cs | 31 ---- MediaBrowser.Controller/Sync/SyncedFileInfo.cs | 43 ------ MediaBrowser.Controller/TV/ITVSeriesManager.cs | 10 ++ 53 files changed, 412 insertions(+), 427 deletions(-) create mode 100644 MediaBrowser.Controller/Channels/IDisableMediaSourceDisplay.cs create mode 100644 MediaBrowser.Controller/Channels/IHasFolderAttributes.cs create mode 100644 MediaBrowser.Controller/Channels/ISupportsDelete.cs create mode 100644 MediaBrowser.Controller/Channels/ISupportsLatestMedia.cs create mode 100644 MediaBrowser.Controller/Channels/ISupportsMediaProbe.cs create mode 100644 MediaBrowser.Controller/Entities/IHasShares.cs create mode 100644 MediaBrowser.Controller/MediaEncoding/TranscodingJobType.cs create mode 100644 MediaBrowser.Controller/Plugins/IRunBeforeStartup.cs delete mode 100644 MediaBrowser.Controller/Sync/IHasDynamicAccess.cs delete mode 100644 MediaBrowser.Controller/Sync/IRemoteSyncProvider.cs delete mode 100644 MediaBrowser.Controller/Sync/IServerSyncProvider.cs delete mode 100644 MediaBrowser.Controller/Sync/ISyncProvider.cs delete mode 100644 MediaBrowser.Controller/Sync/SyncedFileInfo.cs (limited to 'MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs') diff --git a/MediaBrowser.Controller/Channels/Channel.cs b/MediaBrowser.Controller/Channels/Channel.cs index 26c64e0da..26a936be0 100644 --- a/MediaBrowser.Controller/Channels/Channel.cs +++ b/MediaBrowser.Controller/Channels/Channel.cs @@ -84,7 +84,7 @@ namespace MediaBrowser.Controller.Channels internal static bool IsChannelVisible(BaseItem channelItem, User user) { - var channel = ChannelManager.GetChannel(channelItem.ChannelId.ToString("")); + var channel = ChannelManager.GetChannel(channelItem.ChannelId.ToString(string.Empty)); return channel.IsVisible(user); } diff --git a/MediaBrowser.Controller/Channels/IChannelManager.cs b/MediaBrowser.Controller/Channels/IChannelManager.cs index 4c5626338..95d95465e 100644 --- a/MediaBrowser.Controller/Channels/IChannelManager.cs +++ b/MediaBrowser.Controller/Channels/IChannelManager.cs @@ -51,32 +51,47 @@ namespace MediaBrowser.Controller.Channels /// Gets the channels internal. /// /// The query. + /// The of . QueryResult GetChannelsInternal(ChannelQuery query); /// /// Gets the channels. /// /// The query. + /// The of . QueryResult GetChannels(ChannelQuery query); /// - /// Gets the latest media. + /// Gets the latest channel items. /// + /// The item query. + /// The cancellation token. + /// A containing the of . Task> GetLatestChannelItems(InternalItemsQuery query, CancellationToken cancellationToken); /// - /// Gets the latest media. + /// Gets the latest channel items. /// + /// The item query. + /// The cancellation token. + /// A containing the of . Task> GetLatestChannelItemsInternal(InternalItemsQuery query, CancellationToken cancellationToken); /// /// Gets the channel items. /// + /// The query. + /// The cancellation token. + /// A containing the of . Task> GetChannelItems(InternalItemsQuery query, CancellationToken cancellationToken); /// - /// Gets the channel items internal. + /// Gets the channel items. /// + /// The query. + /// The progress to report to. + /// The cancellation token. + /// A containing the of . Task> GetChannelItemsInternal(InternalItemsQuery query, IProgress progress, CancellationToken cancellationToken); /// @@ -87,6 +102,11 @@ namespace MediaBrowser.Controller.Channels /// Task{IEnumerable{MediaSourceInfo}}. IEnumerable GetStaticMediaSources(BaseItem item, CancellationToken cancellationToken); + /// + /// Whether the item supports media probe. + /// + /// The item. + /// Whether media probe should be enabled. bool EnableMediaProbe(BaseItem item); } } diff --git a/MediaBrowser.Controller/Channels/IDisableMediaSourceDisplay.cs b/MediaBrowser.Controller/Channels/IDisableMediaSourceDisplay.cs new file mode 100644 index 000000000..a2dc5682d --- /dev/null +++ b/MediaBrowser.Controller/Channels/IDisableMediaSourceDisplay.cs @@ -0,0 +1,8 @@ +#pragma warning disable CS1591 + +namespace MediaBrowser.Controller.Channels +{ + public interface IDisableMediaSourceDisplay + { + } +} \ No newline at end of file diff --git a/MediaBrowser.Controller/Channels/IHasFolderAttributes.cs b/MediaBrowser.Controller/Channels/IHasFolderAttributes.cs new file mode 100644 index 000000000..47277a8cc --- /dev/null +++ b/MediaBrowser.Controller/Channels/IHasFolderAttributes.cs @@ -0,0 +1,9 @@ +#pragma warning disable CS1591 + +namespace MediaBrowser.Controller.Channels +{ + public interface IHasFolderAttributes + { + string[] Attributes { get; } + } +} \ No newline at end of file diff --git a/MediaBrowser.Controller/Channels/IRequiresMediaInfoCallback.cs b/MediaBrowser.Controller/Channels/IRequiresMediaInfoCallback.cs index 589295543..eeaa6b622 100644 --- a/MediaBrowser.Controller/Channels/IRequiresMediaInfoCallback.cs +++ b/MediaBrowser.Controller/Channels/IRequiresMediaInfoCallback.cs @@ -1,5 +1,3 @@ -#pragma warning disable CS1591 - using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; @@ -7,11 +5,17 @@ using MediaBrowser.Model.Dto; namespace MediaBrowser.Controller.Channels { + /// + /// The channel requires a media info callback. + /// public interface IRequiresMediaInfoCallback { /// /// Gets the channel item media information. /// + /// The channel item id. + /// The cancellation token. + /// The enumerable of media source info. Task> GetChannelItemMediaInfo(string id, CancellationToken cancellationToken); } } diff --git a/MediaBrowser.Controller/Channels/ISearchableChannel.cs b/MediaBrowser.Controller/Channels/ISearchableChannel.cs index b58446fc4..b87943a6e 100644 --- a/MediaBrowser.Controller/Channels/ISearchableChannel.cs +++ b/MediaBrowser.Controller/Channels/ISearchableChannel.cs @@ -5,7 +5,6 @@ using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Controller.Entities; namespace MediaBrowser.Controller.Channels { @@ -19,35 +18,4 @@ namespace MediaBrowser.Controller.Channels /// Task{IEnumerable{ChannelItemInfo}}. Task> Search(ChannelSearchInfo searchInfo, CancellationToken cancellationToken); } - - public interface ISupportsLatestMedia - { - /// - /// Gets the latest media. - /// - /// The request. - /// The cancellation token. - /// Task{IEnumerable{ChannelItemInfo}}. - Task> GetLatestMedia(ChannelLatestMediaSearch request, CancellationToken cancellationToken); - } - - public interface ISupportsDelete - { - bool CanDelete(BaseItem item); - - Task DeleteItem(string id, CancellationToken cancellationToken); - } - - public interface IDisableMediaSourceDisplay - { - } - - public interface ISupportsMediaProbe - { - } - - public interface IHasFolderAttributes - { - string[] Attributes { get; } - } } diff --git a/MediaBrowser.Controller/Channels/ISupportsDelete.cs b/MediaBrowser.Controller/Channels/ISupportsDelete.cs new file mode 100644 index 000000000..d7234fa38 --- /dev/null +++ b/MediaBrowser.Controller/Channels/ISupportsDelete.cs @@ -0,0 +1,17 @@ +#nullable disable + +#pragma warning disable CS1591 + +using System.Threading; +using System.Threading.Tasks; +using MediaBrowser.Controller.Entities; + +namespace MediaBrowser.Controller.Channels +{ + public interface ISupportsDelete + { + bool CanDelete(BaseItem item); + + Task DeleteItem(string id, CancellationToken cancellationToken); + } +} \ No newline at end of file diff --git a/MediaBrowser.Controller/Channels/ISupportsLatestMedia.cs b/MediaBrowser.Controller/Channels/ISupportsLatestMedia.cs new file mode 100644 index 000000000..6820d9222 --- /dev/null +++ b/MediaBrowser.Controller/Channels/ISupportsLatestMedia.cs @@ -0,0 +1,21 @@ +#nullable disable + +#pragma warning disable CS1591 + +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +namespace MediaBrowser.Controller.Channels +{ + public interface ISupportsLatestMedia + { + /// + /// Gets the latest media. + /// + /// The request. + /// The cancellation token. + /// Task{IEnumerable{ChannelItemInfo}}. + Task> GetLatestMedia(ChannelLatestMediaSearch request, CancellationToken cancellationToken); + } +} \ No newline at end of file diff --git a/MediaBrowser.Controller/Channels/ISupportsMediaProbe.cs b/MediaBrowser.Controller/Channels/ISupportsMediaProbe.cs new file mode 100644 index 000000000..2682de51c --- /dev/null +++ b/MediaBrowser.Controller/Channels/ISupportsMediaProbe.cs @@ -0,0 +1,8 @@ +#pragma warning disable CS1591 + +namespace MediaBrowser.Controller.Channels +{ + public interface ISupportsMediaProbe + { + } +} \ No newline at end of file diff --git a/MediaBrowser.Controller/Channels/InternalChannelFeatures.cs b/MediaBrowser.Controller/Channels/InternalChannelFeatures.cs index 152c653dc..45cd08173 100644 --- a/MediaBrowser.Controller/Channels/InternalChannelFeatures.cs +++ b/MediaBrowser.Controller/Channels/InternalChannelFeatures.cs @@ -30,7 +30,7 @@ namespace MediaBrowser.Controller.Channels public List ContentTypes { get; set; } /// - /// Represents the maximum number of records the channel allows retrieving at a time. + /// Gets or sets the maximum number of records the channel allows retrieving at a time. /// public int? MaxPageSize { get; set; } @@ -41,7 +41,7 @@ namespace MediaBrowser.Controller.Channels public List DefaultSortFields { get; set; } /// - /// Indicates if a sort ascending/descending toggle is supported or not. + /// Gets or sets a value indicating whether a sort ascending/descending toggle is supported or not. /// public bool SupportsSortOrderToggle { get; set; } diff --git a/MediaBrowser.Controller/Devices/IDeviceManager.cs b/MediaBrowser.Controller/Devices/IDeviceManager.cs index ef17c8fb3..8096be1bd 100644 --- a/MediaBrowser.Controller/Devices/IDeviceManager.cs +++ b/MediaBrowser.Controller/Devices/IDeviceManager.cs @@ -20,7 +20,6 @@ namespace MediaBrowser.Controller.Devices /// /// The reported identifier. /// The capabilities. - /// Task. void SaveCapabilities(string reportedId, ClientCapabilities capabilities); /// @@ -47,6 +46,9 @@ namespace MediaBrowser.Controller.Devices /// /// Determines whether this instance [can access device] the specified user identifier. /// + /// The user to test. + /// The device id to test. + /// Whether the user can access the device. bool CanAccessDevice(User user, string deviceId); void UpdateDeviceOptions(string deviceId, DeviceOptions options); diff --git a/MediaBrowser.Controller/Dto/IDtoService.cs b/MediaBrowser.Controller/Dto/IDtoService.cs index 7f4bbead0..e0950b1f6 100644 --- a/MediaBrowser.Controller/Dto/IDtoService.cs +++ b/MediaBrowser.Controller/Dto/IDtoService.cs @@ -36,11 +36,17 @@ namespace MediaBrowser.Controller.Dto /// The options. /// The user. /// The owner. + /// The of . IReadOnlyList GetBaseItemDtos(IReadOnlyList items, DtoOptions options, User user = null, BaseItem owner = null); /// /// Gets the item by name dto. /// + /// The item. + /// The dto options. + /// The list of tagged items. + /// The user. + /// The . BaseItemDto GetItemByNameDto(BaseItem item, DtoOptions options, List taggedItems, User user = null); } } diff --git a/MediaBrowser.Controller/Entities/AggregateFolder.cs b/MediaBrowser.Controller/Entities/AggregateFolder.cs index e365bfda1..533130fc8 100644 --- a/MediaBrowser.Controller/Entities/AggregateFolder.cs +++ b/MediaBrowser.Controller/Entities/AggregateFolder.cs @@ -22,6 +22,8 @@ namespace MediaBrowser.Controller.Entities /// public class AggregateFolder : Folder { + private bool _requiresRefresh; + public AggregateFolder() { PhysicalLocationsList = Array.Empty(); @@ -85,8 +87,6 @@ namespace MediaBrowser.Controller.Entities } } - private bool _requiresRefresh; - public override bool RequiresRefresh() { var changed = base.RequiresRefresh() || _requiresRefresh; @@ -106,11 +106,11 @@ namespace MediaBrowser.Controller.Entities return changed; } - public override bool BeforeMetadataRefresh(bool replaceAllMetdata) + public override bool BeforeMetadataRefresh(bool replaceAllMetadata) { ClearCache(); - var changed = base.BeforeMetadataRefresh(replaceAllMetdata) || _requiresRefresh; + var changed = base.BeforeMetadataRefresh(replaceAllMetadata) || _requiresRefresh; _requiresRefresh = false; return changed; } diff --git a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs index b07c3eed1..0928a8073 100644 --- a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs +++ b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs @@ -208,9 +208,9 @@ namespace MediaBrowser.Controller.Entities.Audio /// /// This is called before any metadata refresh and returns true or false indicating if changes were made. /// - public override bool BeforeMetadataRefresh(bool replaceAllMetdata) + public override bool BeforeMetadataRefresh(bool replaceAllMetadata) { - var hasChanges = base.BeforeMetadataRefresh(replaceAllMetdata); + var hasChanges = base.BeforeMetadataRefresh(replaceAllMetadata); if (IsAccessedByName) { diff --git a/MediaBrowser.Controller/Entities/Audio/MusicGenre.cs b/MediaBrowser.Controller/Entities/Audio/MusicGenre.cs index b07d47ffd..a682a2e58 100644 --- a/MediaBrowser.Controller/Entities/Audio/MusicGenre.cs +++ b/MediaBrowser.Controller/Entities/Audio/MusicGenre.cs @@ -38,7 +38,7 @@ namespace MediaBrowser.Controller.Entities.Audio public override bool IsDisplayedAsFolder => true; /// - /// Returns the folder containing the item. + /// Gets the folder containing the item. /// If the item is a folder, it returns the folder itself. /// /// The containing folder path. @@ -106,9 +106,9 @@ namespace MediaBrowser.Controller.Entities.Audio /// /// This is called before any metadata refresh and returns true or false indicating if changes were made. /// - public override bool BeforeMetadataRefresh(bool replaceAllMetdata) + public override bool BeforeMetadataRefresh(bool replaceAllMetadata) { - var hasChanges = base.BeforeMetadataRefresh(replaceAllMetdata); + var hasChanges = base.BeforeMetadataRefresh(replaceAllMetadata); var newPath = GetRebasedPath(); if (!string.Equals(Path, newPath, StringComparison.Ordinal)) diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index 238c98982..6e46b4cec 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -92,7 +92,8 @@ namespace MediaBrowser.Controller.Entities public const string ShortsFolderName = "shorts"; public const string FeaturettesFolderName = "featurettes"; - public static readonly string[] AllExtrasTypesFolderNames = { + public static readonly string[] AllExtrasTypesFolderNames = + { ExtrasFolderName, BehindTheScenesFolderName, DeletedScenesFolderName, @@ -177,7 +178,7 @@ namespace MediaBrowser.Controller.Entities public virtual bool AlwaysScanInternalMetadataPath => false; /// - /// Gets a value indicating whether this instance is in mixed folder. + /// Gets or sets a value indicating whether this instance is in mixed folder. /// /// true if this instance is in mixed folder; otherwise, false. [JsonIgnore] @@ -244,7 +245,7 @@ namespace MediaBrowser.Controller.Entities public ProgramAudio? Audio { get; set; } /// - /// Return the id that should be used to key display prefs for this item. + /// Gets the id that should be used to key display prefs for this item. /// Default is based on the type for everything except actual generic folders. /// /// The display prefs id. @@ -280,7 +281,7 @@ namespace MediaBrowser.Controller.Entities } /// - /// Returns the folder containing the item. + /// Gets the folder containing the item. /// If the item is a folder, it returns the folder itself. /// [JsonIgnore] @@ -305,8 +306,11 @@ namespace MediaBrowser.Controller.Entities public string ServiceName { get; set; } /// - /// If this content came from an external service, the id of the content on that service. + /// Gets or sets the external id. /// + /// + /// If this content came from an external service, the id of the content on that service. + /// [JsonIgnore] public string ExternalId { get; set; } @@ -330,7 +334,7 @@ namespace MediaBrowser.Controller.Entities } /// - /// Gets or sets the type of the location. + /// Gets the type of the location. /// /// The type of the location. [JsonIgnore] @@ -449,8 +453,11 @@ namespace MediaBrowser.Controller.Entities } /// - /// This is just a helper for convenience. + /// Gets the primary image path. /// + /// + /// This is just a helper for convenience. + /// /// The primary image path. [JsonIgnore] public string PrimaryImagePath => this.GetImagePath(ImageType.Primary); @@ -541,7 +548,7 @@ namespace MediaBrowser.Controller.Entities public DateTime DateLastRefreshed { get; set; } /// - /// The logger. + /// Gets or sets the logger. /// public static ILogger Logger { get; set; } @@ -621,7 +628,7 @@ namespace MediaBrowser.Controller.Entities private Guid[] _themeVideoIds; /// - /// Gets the name of the sort. + /// Gets or sets the name of the sort. /// /// The name of the sort. [JsonIgnore] @@ -848,7 +855,7 @@ namespace MediaBrowser.Controller.Entities } /// - /// When the item first debuted. For movies this could be premiere date, episodes would be first aired + /// Gets or sets the date that the item first debuted. For movies this could be premiere date, episodes would be first aired. /// /// The premiere date. [JsonIgnore] @@ -945,7 +952,7 @@ namespace MediaBrowser.Controller.Entities public int? ProductionYear { get; set; } /// - /// If the item is part of a series, this is it's number in the series. + /// Gets or sets the index number. If the item is part of a series, this is it's number in the series. /// This could be episode number, album track number, etc. /// /// The index number. @@ -953,7 +960,7 @@ namespace MediaBrowser.Controller.Entities public int? IndexNumber { get; set; } /// - /// For an episode this could be the season number, or for a song this could be the disc number. + /// Gets or sets the parent index number. For an episode this could be the season number, or for a song this could be the disc number. /// /// The parent index number. [JsonIgnore] @@ -1017,9 +1024,9 @@ namespace MediaBrowser.Controller.Entities } // if (!user.IsParentalScheduleAllowed()) - //{ + // { // return PlayAccess.None; - //} + // } return PlayAccess.Full; } @@ -2645,7 +2652,9 @@ namespace MediaBrowser.Controller.Entities /// /// This is called before any metadata refresh and returns true if changes were made. /// - public virtual bool BeforeMetadataRefresh(bool replaceAllMetdata) + /// Whether to replace all metadata. + /// true if the item has change, else false. + public virtual bool BeforeMetadataRefresh(bool replaceAllMetadata) { _sortName = null; diff --git a/MediaBrowser.Controller/Entities/CollectionFolder.cs b/MediaBrowser.Controller/Entities/CollectionFolder.cs index a86da29ce..d0fb3997d 100644 --- a/MediaBrowser.Controller/Entities/CollectionFolder.cs +++ b/MediaBrowser.Controller/Entities/CollectionFolder.cs @@ -29,30 +29,45 @@ namespace MediaBrowser.Controller.Entities public class CollectionFolder : Folder, ICollectionFolder { private static readonly JsonSerializerOptions _jsonOptions = JsonDefaults.Options; - public static IXmlSerializer XmlSerializer { get; set; } - - public static IServerApplicationHost ApplicationHost { get; set; } + private static readonly Dictionary _libraryOptions = new Dictionary(); + private bool _requiresRefresh; + /// + /// Initializes a new instance of the class. + /// public CollectionFolder() { PhysicalLocationsList = Array.Empty(); PhysicalFolderIds = Array.Empty(); } + public static IXmlSerializer XmlSerializer { get; set; } + + public static IServerApplicationHost ApplicationHost { get; set; } + [JsonIgnore] public override bool SupportsPlayedStatus => false; [JsonIgnore] public override bool SupportsInheritedParentImages => false; + public string CollectionType { get; set; } + + /// + /// Gets the item's children. + /// + /// + /// Our children are actually just references to the ones in the physical root... + /// + /// The actual children. + [JsonIgnore] + public override IEnumerable Children => GetActualChildren(); + public override bool CanDelete() { return false; } - public string CollectionType { get; set; } - - private static readonly Dictionary LibraryOptions = new Dictionary(); public LibraryOptions GetLibraryOptions() { return GetLibraryOptions(Path); @@ -106,12 +121,12 @@ namespace MediaBrowser.Controller.Entities public static LibraryOptions GetLibraryOptions(string path) { - lock (LibraryOptions) + lock (_libraryOptions) { - if (!LibraryOptions.TryGetValue(path, out var options)) + if (!_libraryOptions.TryGetValue(path, out var options)) { options = LoadLibraryOptions(path); - LibraryOptions[path] = options; + _libraryOptions[path] = options; } return options; @@ -120,9 +135,9 @@ namespace MediaBrowser.Controller.Entities public static void SaveLibraryOptions(string path, LibraryOptions options) { - lock (LibraryOptions) + lock (_libraryOptions) { - LibraryOptions[path] = options; + _libraryOptions[path] = options; var clone = JsonSerializer.Deserialize(JsonSerializer.SerializeToUtf8Bytes(options, _jsonOptions), _jsonOptions); foreach (var mediaPath in clone.PathInfos) @@ -139,15 +154,18 @@ namespace MediaBrowser.Controller.Entities public static void OnCollectionFolderChange() { - lock (LibraryOptions) + lock (_libraryOptions) { - LibraryOptions.Clear(); + _libraryOptions.Clear(); } } /// - /// Allow different display preferences for each collection folder. + /// Gets the display preferences id. /// + /// + /// Allow different display preferences for each collection folder. + /// /// The display prefs id. [JsonIgnore] public override Guid DisplayPreferencesId => Id; @@ -155,21 +173,20 @@ namespace MediaBrowser.Controller.Entities [JsonIgnore] public override string[] PhysicalLocations => PhysicalLocationsList; + public string[] PhysicalLocationsList { get; set; } + + public Guid[] PhysicalFolderIds { get; set; } + public override bool IsSaveLocalMetadataEnabled() { return true; } - public string[] PhysicalLocationsList { get; set; } - - public Guid[] PhysicalFolderIds { get; set; } - protected override FileSystemMetadata[] GetFileSystemChildren(IDirectoryService directoryService) { return CreateResolveArgs(directoryService, true).FileSystemChildren; } - private bool _requiresRefresh; public override bool RequiresRefresh() { var changed = base.RequiresRefresh() || _requiresRefresh; @@ -201,9 +218,9 @@ namespace MediaBrowser.Controller.Entities return changed; } - public override bool BeforeMetadataRefresh(bool replaceAllMetdata) + public override bool BeforeMetadataRefresh(bool replaceAllMetadata) { - var changed = base.BeforeMetadataRefresh(replaceAllMetdata) || _requiresRefresh; + var changed = base.BeforeMetadataRefresh(replaceAllMetadata) || _requiresRefresh; _requiresRefresh = false; return changed; } @@ -312,13 +329,6 @@ namespace MediaBrowser.Controller.Entities return Task.CompletedTask; } - /// - /// Our children are actually just references to the ones in the physical root... - /// - /// The actual children. - [JsonIgnore] - public override IEnumerable Children => GetActualChildren(); - public IEnumerable GetActualChildren() { return GetPhysicalFolders(true).SelectMany(c => c.Children); diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index a59f5c6e4..29d837c14 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -37,6 +37,11 @@ namespace MediaBrowser.Controller.Entities /// public class Folder : BaseItem { + public Folder() + { + LinkedChildren = Array.Empty(); + } + public static IUserViewManager UserViewManager { get; set; } /// @@ -50,11 +55,6 @@ namespace MediaBrowser.Controller.Entities [JsonIgnore] public DateTime? DateLastMediaAdded { get; set; } - public Folder() - { - LinkedChildren = Array.Empty(); - } - [JsonIgnore] public override bool SupportsThemeMedia => true; @@ -86,6 +86,85 @@ namespace MediaBrowser.Controller.Entities [JsonIgnore] public virtual bool SupportsDateLastMediaAdded => false; + [JsonIgnore] + public override string FileNameWithoutExtension + { + get + { + if (IsFileProtocol) + { + return System.IO.Path.GetFileName(Path); + } + + return null; + } + } + + /// + /// Gets the actual children. + /// + /// The actual children. + [JsonIgnore] + public virtual IEnumerable Children => LoadChildren(); + + /// + /// Gets thread-safe access to all recursive children of this folder - without regard to user. + /// + /// The recursive children. + [JsonIgnore] + public IEnumerable RecursiveChildren => GetRecursiveChildren(); + + [JsonIgnore] + protected virtual bool SupportsShortcutChildren => false; + + protected virtual bool FilterLinkedChildrenPerUser => false; + + [JsonIgnore] + protected override bool SupportsOwnedItems => base.SupportsOwnedItems || SupportsShortcutChildren; + + [JsonIgnore] + public virtual bool SupportsUserDataFromChildren + { + get + { + // These are just far too slow. + if (this is ICollectionFolder) + { + return false; + } + + if (this is UserView) + { + return false; + } + + if (this is UserRootFolder) + { + return false; + } + + if (this is Channel) + { + return false; + } + + if (SourceType != SourceType.Library) + { + return false; + } + + if (this is IItemByName) + { + if (this is not IHasDualAccess hasDualAccess || hasDualAccess.IsAccessedByName) + { + return false; + } + } + + return true; + } + } + public override bool CanDelete() { if (IsRoot) @@ -108,20 +187,6 @@ namespace MediaBrowser.Controller.Entities return baseResult; } - [JsonIgnore] - public override string FileNameWithoutExtension - { - get - { - if (IsFileProtocol) - { - return System.IO.Path.GetFileName(Path); - } - - return null; - } - } - protected override bool IsAllowTagFilterEnforced() { if (this is ICollectionFolder) @@ -137,9 +202,6 @@ namespace MediaBrowser.Controller.Entities return true; } - [JsonIgnore] - protected virtual bool SupportsShortcutChildren => false; - /// /// Adds the child. /// @@ -169,20 +231,6 @@ namespace MediaBrowser.Controller.Entities LibraryManager.CreateItem(item, this); } - /// - /// Gets the actual children. - /// - /// The actual children. - [JsonIgnore] - public virtual IEnumerable Children => LoadChildren(); - - /// - /// thread-safe access to all recursive children of this folder - without regard to user. - /// - /// The recursive children. - [JsonIgnore] - public IEnumerable RecursiveChildren => GetRecursiveChildren(); - public override bool IsVisible(User user) { if (this is ICollectionFolder && !(this is BasePluginFolder)) @@ -1428,8 +1476,6 @@ namespace MediaBrowser.Controller.Entities return list; } - protected virtual bool FilterLinkedChildrenPerUser => false; - public bool ContainsLinkedChildByItemId(Guid itemId) { var linkedChildren = LinkedChildren; @@ -1530,9 +1576,6 @@ namespace MediaBrowser.Controller.Entities .Where(i => i.Item2 != null); } - [JsonIgnore] - protected override bool SupportsOwnedItems => base.SupportsOwnedItems || SupportsShortcutChildren; - protected override async Task RefreshedOwnedItems(MetadataRefreshOptions options, List fileSystemChildren, CancellationToken cancellationToken) { var changesFound = false; @@ -1696,51 +1739,6 @@ namespace MediaBrowser.Controller.Entities return !IsPlayed(user); } - [JsonIgnore] - public virtual bool SupportsUserDataFromChildren - { - get - { - // These are just far too slow. - if (this is ICollectionFolder) - { - return false; - } - - if (this is UserView) - { - return false; - } - - if (this is UserRootFolder) - { - return false; - } - - if (this is Channel) - { - return false; - } - - if (SourceType != SourceType.Library) - { - return false; - } - - var iItemByName = this as IItemByName; - if (iItemByName != null) - { - var hasDualAccess = this as IHasDualAccess; - if (hasDualAccess == null || hasDualAccess.IsAccessedByName) - { - return false; - } - } - - return true; - } - } - public override void FillUserDataDtoValues(UserItemDataDto dto, UserItemData userData, BaseItemDto itemDto, User user, DtoOptions fields) { if (!SupportsUserDataFromChildren) diff --git a/MediaBrowser.Controller/Entities/Genre.cs b/MediaBrowser.Controller/Entities/Genre.cs index 310c0c9ec..698643b44 100644 --- a/MediaBrowser.Controller/Entities/Genre.cs +++ b/MediaBrowser.Controller/Entities/Genre.cs @@ -16,6 +16,23 @@ namespace MediaBrowser.Controller.Entities /// public class Genre : BaseItem, IItemByName { + /// + /// Gets the folder containing the item. + /// If the item is a folder, it returns the folder itself. + /// + /// The containing folder path. + [JsonIgnore] + public override string ContainingFolderPath => Path; + + [JsonIgnore] + public override bool IsDisplayedAsFolder => true; + + [JsonIgnore] + public override bool SupportsAncestors => false; + + [JsonIgnore] + public override bool SupportsPeople => false; + public override List GetUserDataKeys() { var list = base.GetUserDataKeys(); @@ -34,20 +51,6 @@ namespace MediaBrowser.Controller.Entities return 1; } - /// - /// Gets the folder containing the item. - /// If the item is a folder, it returns the folder itself. - /// - /// The containing folder path. - [JsonIgnore] - public override string ContainingFolderPath => Path; - - [JsonIgnore] - public override bool IsDisplayedAsFolder => true; - - [JsonIgnore] - public override bool SupportsAncestors => false; - public override bool IsSaveLocalMetadataEnabled() { return true; @@ -72,9 +75,6 @@ namespace MediaBrowser.Controller.Entities return LibraryManager.GetItemList(query); } - [JsonIgnore] - public override bool SupportsPeople => false; - public static string GetPath(string name) { return GetPath(name, true); @@ -107,12 +107,10 @@ namespace MediaBrowser.Controller.Entities return base.RequiresRefresh(); } - /// - /// This is called before any metadata refresh and returns true or false indicating if changes were made. - /// - public override bool BeforeMetadataRefresh(bool replaceAllMetdata) + /// + public override bool BeforeMetadataRefresh(bool replaceAllMetadata) { - var hasChanges = base.BeforeMetadataRefresh(replaceAllMetdata); + var hasChanges = base.BeforeMetadataRefresh(replaceAllMetadata); var newPath = GetRebasedPath(); if (!string.Equals(Path, newPath, StringComparison.Ordinal)) diff --git a/MediaBrowser.Controller/Entities/IHasSeries.cs b/MediaBrowser.Controller/Entities/IHasSeries.cs index 64d769d5b..5f774bbde 100644 --- a/MediaBrowser.Controller/Entities/IHasSeries.cs +++ b/MediaBrowser.Controller/Entities/IHasSeries.cs @@ -9,7 +9,7 @@ namespace MediaBrowser.Controller.Entities public interface IHasSeries { /// - /// Gets the name of the series. + /// Gets or sets the name of the series. /// /// The name of the series. string SeriesName { get; set; } diff --git a/MediaBrowser.Controller/Entities/IHasShares.cs b/MediaBrowser.Controller/Entities/IHasShares.cs new file mode 100644 index 000000000..bdde744a3 --- /dev/null +++ b/MediaBrowser.Controller/Entities/IHasShares.cs @@ -0,0 +1,11 @@ +#nullable disable + +#pragma warning disable CS1591 + +namespace MediaBrowser.Controller.Entities +{ + public interface IHasShares + { + Share[] Shares { get; set; } + } +} \ No newline at end of file diff --git a/MediaBrowser.Controller/Entities/Movies/Movie.cs b/MediaBrowser.Controller/Entities/Movies/Movie.cs index 64d60c2e9..b54bbf5eb 100644 --- a/MediaBrowser.Controller/Entities/Movies/Movie.cs +++ b/MediaBrowser.Controller/Entities/Movies/Movie.cs @@ -144,9 +144,9 @@ namespace MediaBrowser.Controller.Entities.Movies } /// - public override bool BeforeMetadataRefresh(bool replaceAllMetdata) + public override bool BeforeMetadataRefresh(bool replaceAllMetadata) { - var hasChanges = base.BeforeMetadataRefresh(replaceAllMetdata); + var hasChanges = base.BeforeMetadataRefresh(replaceAllMetadata); if (!ProductionYear.HasValue) { diff --git a/MediaBrowser.Controller/Entities/MusicVideo.cs b/MediaBrowser.Controller/Entities/MusicVideo.cs index 4e622ba01..237ad5198 100644 --- a/MediaBrowser.Controller/Entities/MusicVideo.cs +++ b/MediaBrowser.Controller/Entities/MusicVideo.cs @@ -36,9 +36,9 @@ namespace MediaBrowser.Controller.Entities return info; } - public override bool BeforeMetadataRefresh(bool replaceAllMetdata) + public override bool BeforeMetadataRefresh(bool replaceAllMetadata) { - var hasChanges = base.BeforeMetadataRefresh(replaceAllMetdata); + var hasChanges = base.BeforeMetadataRefresh(replaceAllMetadata); if (!ProductionYear.HasValue) { diff --git a/MediaBrowser.Controller/Entities/Person.cs b/MediaBrowser.Controller/Entities/Person.cs index d9ff55362..913f76d3b 100644 --- a/MediaBrowser.Controller/Entities/Person.cs +++ b/MediaBrowser.Controller/Entities/Person.cs @@ -50,7 +50,7 @@ namespace MediaBrowser.Controller.Entities } /// - /// Returns the folder containing the item. + /// Gets the folder containing the item. /// If the item is a folder, it returns the folder itself. /// /// The containing folder path. @@ -67,6 +67,9 @@ namespace MediaBrowser.Controller.Entities return true; } + /// + /// Gets a value indicating whether to enable alpha numeric sorting. + /// [JsonIgnore] public override bool EnableAlphaNumericSorting => false; @@ -126,9 +129,9 @@ namespace MediaBrowser.Controller.Entities /// /// This is called before any metadata refresh and returns true or false indicating if changes were made. /// - public override bool BeforeMetadataRefresh(bool replaceAllMetdata) + public override bool BeforeMetadataRefresh(bool replaceAllMetadata) { - var hasChanges = base.BeforeMetadataRefresh(replaceAllMetdata); + var hasChanges = base.BeforeMetadataRefresh(replaceAllMetadata); var newPath = GetRebasedPath(); if (!string.Equals(Path, newPath, StringComparison.Ordinal)) diff --git a/MediaBrowser.Controller/Entities/Share.cs b/MediaBrowser.Controller/Entities/Share.cs index 7e4ec1830..64f446eef 100644 --- a/MediaBrowser.Controller/Entities/Share.cs +++ b/MediaBrowser.Controller/Entities/Share.cs @@ -4,11 +4,6 @@ namespace MediaBrowser.Controller.Entities { - public interface IHasShares - { - Share[] Shares { get; set; } - } - public class Share { public string UserId { get; set; } diff --git a/MediaBrowser.Controller/Entities/Studio.cs b/MediaBrowser.Controller/Entities/Studio.cs index ae1d10447..6fd0a6c6c 100644 --- a/MediaBrowser.Controller/Entities/Studio.cs +++ b/MediaBrowser.Controller/Entities/Studio.cs @@ -29,7 +29,7 @@ namespace MediaBrowser.Controller.Entities } /// - /// Returns the folder containing the item. + /// Gets the folder containing the item. /// If the item is a folder, it returns the folder itself. /// /// The containing folder path. @@ -105,9 +105,9 @@ namespace MediaBrowser.Controller.Entities /// /// This is called before any metadata refresh and returns true or false indicating if changes were made. /// - public override bool BeforeMetadataRefresh(bool replaceAllMetdata) + public override bool BeforeMetadataRefresh(bool replaceAllMetadata) { - var hasChanges = base.BeforeMetadataRefresh(replaceAllMetdata); + var hasChanges = base.BeforeMetadataRefresh(replaceAllMetadata); var newPath = GetRebasedPath(); if (!string.Equals(Path, newPath, StringComparison.Ordinal)) diff --git a/MediaBrowser.Controller/Entities/TV/Episode.cs b/MediaBrowser.Controller/Entities/TV/Episode.cs index 2724bd9b3..1b4cc7a78 100644 --- a/MediaBrowser.Controller/Entities/TV/Episode.cs +++ b/MediaBrowser.Controller/Entities/TV/Episode.cs @@ -34,7 +34,7 @@ namespace MediaBrowser.Controller.Entities.TV public IReadOnlyList RemoteTrailerIds { get; set; } /// - /// Gets the season in which it aired. + /// Gets or sets the season in which it aired. /// /// The aired season. public int? AirsBeforeSeasonNumber { get; set; } @@ -44,7 +44,7 @@ namespace MediaBrowser.Controller.Entities.TV public int? AirsBeforeEpisodeNumber { get; set; } /// - /// This is the ending episode number for double episodes. + /// Gets or sets the ending episode number for double episodes. /// /// The index number. public int? IndexNumberEnd { get; set; } @@ -116,7 +116,7 @@ namespace MediaBrowser.Controller.Entities.TV } /// - /// This Episode's Series Instance. + /// Gets the Episode's Series Instance. /// /// The series. [JsonIgnore] @@ -261,6 +261,7 @@ namespace MediaBrowser.Controller.Entities.TV [JsonIgnore] public Guid SeasonId { get; set; } + [JsonIgnore] public Guid SeriesId { get; set; } @@ -318,9 +319,9 @@ namespace MediaBrowser.Controller.Entities.TV return id; } - public override bool BeforeMetadataRefresh(bool replaceAllMetdata) + public override bool BeforeMetadataRefresh(bool replaceAllMetadata) { - var hasChanges = base.BeforeMetadataRefresh(replaceAllMetdata); + var hasChanges = base.BeforeMetadataRefresh(replaceAllMetadata); if (!IsLocked) { @@ -328,7 +329,7 @@ namespace MediaBrowser.Controller.Entities.TV { try { - if (LibraryManager.FillMissingEpisodeNumbersFromPath(this, replaceAllMetdata)) + if (LibraryManager.FillMissingEpisodeNumbersFromPath(this, replaceAllMetadata)) { hasChanges = true; } diff --git a/MediaBrowser.Controller/Entities/TV/Season.cs b/MediaBrowser.Controller/Entities/TV/Season.cs index ad3e0fe8d..5e2053dcc 100644 --- a/MediaBrowser.Controller/Entities/TV/Season.cs +++ b/MediaBrowser.Controller/Entities/TV/Season.cs @@ -81,7 +81,7 @@ namespace MediaBrowser.Controller.Entities.TV } /// - /// This Episode's Series Instance. + /// Gets this Episode's Series Instance. /// /// The series. [JsonIgnore] @@ -242,9 +242,9 @@ namespace MediaBrowser.Controller.Entities.TV /// This is called before any metadata refresh and returns true or false indicating if changes were made. /// /// true if XXXX, false otherwise. - public override bool BeforeMetadataRefresh(bool replaceAllMetdata) + public override bool BeforeMetadataRefresh(bool replaceAllMetadata) { - var hasChanges = base.BeforeMetadataRefresh(replaceAllMetdata); + var hasChanges = base.BeforeMetadataRefresh(replaceAllMetadata); if (!IndexNumber.HasValue && !string.IsNullOrEmpty(Path)) { diff --git a/MediaBrowser.Controller/Entities/TV/Series.cs b/MediaBrowser.Controller/Entities/TV/Series.cs index ded825abc..44d07b4a4 100644 --- a/MediaBrowser.Controller/Entities/TV/Series.cs +++ b/MediaBrowser.Controller/Entities/TV/Series.cs @@ -59,8 +59,11 @@ namespace MediaBrowser.Controller.Entities.TV public IReadOnlyList RemoteTrailerIds { get; set; } /// - /// airdate, dvd or absolute. + /// Gets or sets the display order. /// + /// + /// Valid options are airdate, dvd or absolute. + /// public string DisplayOrder { get; set; } /// diff --git a/MediaBrowser.Controller/Entities/Trailer.cs b/MediaBrowser.Controller/Entities/Trailer.cs index b086b5906..732b45521 100644 --- a/MediaBrowser.Controller/Entities/Trailer.cs +++ b/MediaBrowser.Controller/Entities/Trailer.cs @@ -45,9 +45,9 @@ namespace MediaBrowser.Controller.Entities return info; } - public override bool BeforeMetadataRefresh(bool replaceAllMetdata) + public override bool BeforeMetadataRefresh(bool replaceAllMetadata) { - var hasChanges = base.BeforeMetadataRefresh(replaceAllMetdata); + var hasChanges = base.BeforeMetadataRefresh(replaceAllMetadata); if (!ProductionYear.HasValue) { diff --git a/MediaBrowser.Controller/Entities/UserItemData.cs b/MediaBrowser.Controller/Entities/UserItemData.cs index f60359c01..6ab2116d7 100644 --- a/MediaBrowser.Controller/Entities/UserItemData.cs +++ b/MediaBrowser.Controller/Entities/UserItemData.cs @@ -96,7 +96,7 @@ namespace MediaBrowser.Controller.Entities public const double MinLikeValue = 6.5; /// - /// This is an interpreted property to indicate likes or dislikes + /// Gets or sets a value indicating whether the item is liked or not. /// This should never be serialized. /// /// null if [likes] contains no value, true if [likes]; otherwise, false. diff --git a/MediaBrowser.Controller/Entities/UserRootFolder.cs b/MediaBrowser.Controller/Entities/UserRootFolder.cs index e492740ed..2dea2e50b 100644 --- a/MediaBrowser.Controller/Entities/UserRootFolder.cs +++ b/MediaBrowser.Controller/Entities/UserRootFolder.cs @@ -23,6 +23,7 @@ namespace MediaBrowser.Controller.Entities { private List _childrenIds = null; private readonly object _childIdsLock = new object(); + protected override List LoadChildren() { lock (_childIdsLock) @@ -87,10 +88,10 @@ namespace MediaBrowser.Controller.Entities return list; } - public override bool BeforeMetadataRefresh(bool replaceAllMetdata) + public override bool BeforeMetadataRefresh(bool replaceAllMetadata) { ClearCache(); - var hasChanges = base.BeforeMetadataRefresh(replaceAllMetdata); + var hasChanges = base.BeforeMetadataRefresh(replaceAllMetadata); if (string.Equals("default", Name, StringComparison.OrdinalIgnoreCase)) { diff --git a/MediaBrowser.Controller/Entities/UserView.cs b/MediaBrowser.Controller/Entities/UserView.cs index 0dfde2766..1e6c01bf8 100644 --- a/MediaBrowser.Controller/Entities/UserView.cs +++ b/MediaBrowser.Controller/Entities/UserView.cs @@ -15,13 +15,19 @@ namespace MediaBrowser.Controller.Entities { public class UserView : Folder, IHasCollectionType { - /// + /// + /// Gets or sets the view type. + /// public string ViewType { get; set; } - /// + /// + /// Gets or sets the display parent id. + /// public new Guid DisplayParentId { get; set; } - /// + /// + /// Gets or sets the user id. + /// public Guid? UserId { get; set; } public static ITVSeriesManager TVSeriesManager; @@ -110,10 +116,10 @@ namespace MediaBrowser.Controller.Entities return GetChildren(user, false); } - private static string[] UserSpecificViewTypes = new string[] - { - Model.Entities.CollectionType.Playlists - }; + private static readonly string[] UserSpecificViewTypes = new string[] + { + Model.Entities.CollectionType.Playlists + }; public static bool IsUserSpecific(Folder folder) { diff --git a/MediaBrowser.Controller/Entities/Year.cs b/MediaBrowser.Controller/Entities/Year.cs index 4d84a151a..f268bc939 100644 --- a/MediaBrowser.Controller/Entities/Year.cs +++ b/MediaBrowser.Controller/Entities/Year.cs @@ -24,7 +24,7 @@ namespace MediaBrowser.Controller.Entities } /// - /// Returns the folder containing the item. + /// Gets the folder containing the item. /// If the item is a folder, it returns the folder itself. /// /// The containing folder path. @@ -112,11 +112,13 @@ namespace MediaBrowser.Controller.Entities } /// - /// This is called before any metadata refresh and returns true or false indicating if changes were made. + /// This is called before any metadata refresh and returns true if changes were made. /// - public override bool BeforeMetadataRefresh(bool replaceAllMetdata) + /// Whether to replace all metadata. + /// true if the item has change, else false. + public override bool BeforeMetadataRefresh(bool replaceAllMetadata) { - var hasChanges = base.BeforeMetadataRefresh(replaceAllMetdata); + var hasChanges = base.BeforeMetadataRefresh(replaceAllMetadata); var newPath = GetRebasedPath(); if (!string.Equals(Path, newPath, StringComparison.Ordinal)) diff --git a/MediaBrowser.Controller/Extensions/StringExtensions.cs b/MediaBrowser.Controller/Extensions/StringExtensions.cs index 8441a3171..48bd9522a 100644 --- a/MediaBrowser.Controller/Extensions/StringExtensions.cs +++ b/MediaBrowser.Controller/Extensions/StringExtensions.cs @@ -33,7 +33,7 @@ namespace MediaBrowser.Controller.Extensions { // will throw if input contains invalid unicode chars // https://mnaoumov.wordpress.com/2014/06/14/stripping-invalid-characters-from-utf-16-strings/ - text = Regex.Replace(text, "([\ud800-\udbff](?![\udc00-\udfff]))|((? /// Resolves a set of files into a list of BaseItem. /// + /// The list of tiles. + /// Instance of the interface. + /// The parent folder. + /// The library options. + /// The collection type. + /// The list of . IEnumerable ResolvePaths( IEnumerable files, IDirectoryService directoryService, diff --git a/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs b/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs index 51e56f4b5..1a893fc2d 100644 --- a/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs +++ b/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs @@ -148,7 +148,7 @@ namespace MediaBrowser.Controller.LiveTv public bool IsNews { get; set; } /// - /// Gets or sets a value indicating whether this instance is kids. + /// Gets a value indicating whether this instance is kids. /// /// true if this instance is kids; otherwise, false. [JsonIgnore] diff --git a/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs b/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs index a66bec11c..e2adec000 100644 --- a/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs +++ b/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs @@ -71,7 +71,7 @@ namespace MediaBrowser.Controller.LiveTv public override SourceType SourceType => SourceType.LiveTV; /// - /// The start date of the program, in UTC. + /// Gets or sets start date of the program, in UTC. /// [JsonIgnore] public DateTime StartDate { get; set; } diff --git a/MediaBrowser.Controller/LiveTv/TimerInfo.cs b/MediaBrowser.Controller/LiveTv/TimerInfo.cs index e54dc967c..1a2e8acb3 100644 --- a/MediaBrowser.Controller/LiveTv/TimerInfo.cs +++ b/MediaBrowser.Controller/LiveTv/TimerInfo.cs @@ -28,18 +28,17 @@ namespace MediaBrowser.Controller.LiveTv public string[] Tags { get; set; } /// - /// Id of the recording. + /// Gets or sets the id of the recording. /// public string Id { get; set; } /// /// Gets or sets the series timer identifier. /// - /// The series timer identifier. public string SeriesTimerId { get; set; } /// - /// ChannelId of the recording. + /// Gets or sets the channelId of the recording. /// public string ChannelId { get; set; } @@ -52,24 +51,24 @@ namespace MediaBrowser.Controller.LiveTv public string ShowId { get; set; } /// - /// Name of the recording. + /// Gets or sets the name of the recording. /// public string Name { get; set; } /// - /// Description of the recording. + /// Gets or sets the description of the recording. /// public string Overview { get; set; } public string SeriesId { get; set; } /// - /// The start date of the recording, in UTC. + /// Gets or sets the start date of the recording, in UTC. /// public DateTime StartDate { get; set; } /// - /// The end date of the recording, in UTC. + /// Gets or sets the end date of the recording, in UTC. /// public DateTime EndDate { get; set; } @@ -133,7 +132,7 @@ namespace MediaBrowser.Controller.LiveTv public bool IsSeries { get; set; } /// - /// Gets or sets a value indicating whether this instance is live. + /// Gets a value indicating whether this instance is live. /// /// true if this instance is live; otherwise, false. [JsonIgnore] diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 97cb8d63b..9300fd49a 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -2933,6 +2933,7 @@ namespace MediaBrowser.Controller.MediaEncoding return threads; } + #nullable disable public void TryStreamCopy(EncodingJobInfo state) { diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs b/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs index 1e13382b7..bc34785ee 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs @@ -430,7 +430,7 @@ namespace MediaBrowser.Controller.MediaEncoding } /// - /// Predicts the audio sample rate that will be in the output stream. + /// Gets the target video level. /// public double? TargetVideoLevel { @@ -453,7 +453,7 @@ namespace MediaBrowser.Controller.MediaEncoding } /// - /// Predicts the audio sample rate that will be in the output stream. + /// Gets the target video bit depth. /// public int? TargetVideoBitDepth { @@ -488,7 +488,7 @@ namespace MediaBrowser.Controller.MediaEncoding } /// - /// Predicts the audio sample rate that will be in the output stream. + /// Gets the target framerate. /// public float? TargetFramerate { @@ -520,7 +520,7 @@ namespace MediaBrowser.Controller.MediaEncoding } /// - /// Predicts the audio sample rate that will be in the output stream. + /// Gets the target packet length. /// public int? TargetPacketLength { @@ -536,7 +536,7 @@ namespace MediaBrowser.Controller.MediaEncoding } /// - /// Predicts the audio sample rate that will be in the output stream. + /// Gets the target video profile. /// public string TargetVideoProfile { @@ -700,25 +700,4 @@ namespace MediaBrowser.Controller.MediaEncoding Progress.Report(percentComplete.Value); } } - - /// - /// Enum TranscodingJobType. - /// - public enum TranscodingJobType - { - /// - /// The progressive. - /// - Progressive, - - /// - /// The HLS. - /// - Hls, - - /// - /// The dash. - /// - Dash - } } diff --git a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs index d3260280a..76a9fd7c7 100644 --- a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs +++ b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs @@ -20,7 +20,7 @@ namespace MediaBrowser.Controller.MediaEncoding public interface IMediaEncoder : ITranscoderSupport { /// - /// The location of the discovered FFmpeg tool. + /// Gets location of the discovered FFmpeg tool. /// FFmpegLocation EncoderLocation { get; } diff --git a/MediaBrowser.Controller/MediaEncoding/TranscodingJobType.cs b/MediaBrowser.Controller/MediaEncoding/TranscodingJobType.cs new file mode 100644 index 000000000..66b628371 --- /dev/null +++ b/MediaBrowser.Controller/MediaEncoding/TranscodingJobType.cs @@ -0,0 +1,23 @@ +namespace MediaBrowser.Controller.MediaEncoding +{ + /// + /// Enum TranscodingJobType. + /// + public enum TranscodingJobType + { + /// + /// The progressive. + /// + Progressive, + + /// + /// The HLS. + /// + Hls, + + /// + /// The dash. + /// + Dash + } +} \ No newline at end of file diff --git a/MediaBrowser.Controller/Playlists/Playlist.cs b/MediaBrowser.Controller/Playlists/Playlist.cs index a80c11643..f767c2c2b 100644 --- a/MediaBrowser.Controller/Playlists/Playlist.cs +++ b/MediaBrowser.Controller/Playlists/Playlist.cs @@ -22,7 +22,8 @@ namespace MediaBrowser.Controller.Playlists { public class Playlist : Folder, IHasShares { - public static string[] SupportedExtensions = + public static readonly IReadOnlyList SupportedExtensions = + new[] { ".m3u", ".m3u8", diff --git a/MediaBrowser.Controller/Plugins/IRunBeforeStartup.cs b/MediaBrowser.Controller/Plugins/IRunBeforeStartup.cs new file mode 100644 index 000000000..ea966c282 --- /dev/null +++ b/MediaBrowser.Controller/Plugins/IRunBeforeStartup.cs @@ -0,0 +1,9 @@ +namespace MediaBrowser.Controller.Plugins +{ + /// + /// Indicates that a should be invoked as a pre-startup task. + /// + public interface IRunBeforeStartup + { + } +} \ No newline at end of file diff --git a/MediaBrowser.Controller/Plugins/IServerEntryPoint.cs b/MediaBrowser.Controller/Plugins/IServerEntryPoint.cs index b44e2531e..6024661e1 100644 --- a/MediaBrowser.Controller/Plugins/IServerEntryPoint.cs +++ b/MediaBrowser.Controller/Plugins/IServerEntryPoint.cs @@ -14,13 +14,7 @@ namespace MediaBrowser.Controller.Plugins /// /// Run the initialization for this module. This method is invoked at application start. /// + /// A representing the asynchronous operation. Task RunAsync(); } - - /// - /// Indicates that a should be invoked as a pre-startup task. - /// - public interface IRunBeforeStartup - { - } } diff --git a/MediaBrowser.Controller/Providers/MetadataRefreshOptions.cs b/MediaBrowser.Controller/Providers/MetadataRefreshOptions.cs index 115250466..2cf536779 100644 --- a/MediaBrowser.Controller/Providers/MetadataRefreshOptions.cs +++ b/MediaBrowser.Controller/Providers/MetadataRefreshOptions.cs @@ -40,7 +40,7 @@ namespace MediaBrowser.Controller.Providers /// /// Gets or sets a value indicating whether all existing data should be overwritten with new data from providers - /// when paired with MetadataRefreshMode=FullRefresh + /// when paired with MetadataRefreshMode=FullRefresh. /// public bool ReplaceAllMetadata { get; set; } diff --git a/MediaBrowser.Controller/Sync/IHasDynamicAccess.cs b/MediaBrowser.Controller/Sync/IHasDynamicAccess.cs deleted file mode 100644 index 3d3e44da0..000000000 --- a/MediaBrowser.Controller/Sync/IHasDynamicAccess.cs +++ /dev/null @@ -1,22 +0,0 @@ -#nullable disable - -#pragma warning disable CS1591 - -using System.Threading; -using System.Threading.Tasks; -using MediaBrowser.Model.Sync; - -namespace MediaBrowser.Controller.Sync -{ - public interface IHasDynamicAccess - { - /// - /// Gets the synced file information. - /// - /// The identifier. - /// The target. - /// The cancellation token. - /// Task<SyncedFileInfo>. - Task GetSyncedFileInfo(string id, SyncTarget target, CancellationToken cancellationToken); - } -} diff --git a/MediaBrowser.Controller/Sync/IRemoteSyncProvider.cs b/MediaBrowser.Controller/Sync/IRemoteSyncProvider.cs deleted file mode 100644 index b2c53365c..000000000 --- a/MediaBrowser.Controller/Sync/IRemoteSyncProvider.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace MediaBrowser.Controller.Sync -{ - /// - /// A marker interface. - /// - public interface IRemoteSyncProvider - { - } -} diff --git a/MediaBrowser.Controller/Sync/IServerSyncProvider.cs b/MediaBrowser.Controller/Sync/IServerSyncProvider.cs deleted file mode 100644 index 3891ac0a6..000000000 --- a/MediaBrowser.Controller/Sync/IServerSyncProvider.cs +++ /dev/null @@ -1,32 +0,0 @@ -#nullable disable - -#pragma warning disable CS1591 - -using System; -using System.IO; -using System.Threading; -using System.Threading.Tasks; -using MediaBrowser.Model.IO; -using MediaBrowser.Model.Querying; -using MediaBrowser.Model.Sync; - -namespace MediaBrowser.Controller.Sync -{ - public interface IServerSyncProvider : ISyncProvider - { - /// - /// Transfers the file. - /// - Task SendFile(SyncJob syncJob, string originalMediaPath, Stream inputStream, bool isMedia, string[] outputPathParts, SyncTarget target, IProgress progress, CancellationToken cancellationToken); - - Task> GetFiles(string[] directoryPathParts, SyncTarget target, CancellationToken cancellationToken); - } - - public interface ISupportsDirectCopy - { - /// - /// Sends the file. - /// - Task SendFile(SyncJob syncJob, string originalMediaPath, string inputPath, bool isMedia, string[] outputPathParts, SyncTarget target, IProgress progress, CancellationToken cancellationToken); - } -} diff --git a/MediaBrowser.Controller/Sync/ISyncProvider.cs b/MediaBrowser.Controller/Sync/ISyncProvider.cs deleted file mode 100644 index ea20014c7..000000000 --- a/MediaBrowser.Controller/Sync/ISyncProvider.cs +++ /dev/null @@ -1,31 +0,0 @@ -#nullable disable - -#pragma warning disable CS1591 - -using System.Collections.Generic; -using MediaBrowser.Model.Sync; - -namespace MediaBrowser.Controller.Sync -{ - public interface ISyncProvider - { - /// - /// Gets the name. - /// - /// The name. - string Name { get; } - - /// - /// Gets the synchronize targets. - /// - /// The user identifier. - /// IEnumerable<SyncTarget>. - List GetSyncTargets(string userId); - - /// - /// Gets all synchronize targets. - /// - /// IEnumerable<SyncTarget>. - List GetAllSyncTargets(); - } -} diff --git a/MediaBrowser.Controller/Sync/SyncedFileInfo.cs b/MediaBrowser.Controller/Sync/SyncedFileInfo.cs deleted file mode 100644 index 7eac52299..000000000 --- a/MediaBrowser.Controller/Sync/SyncedFileInfo.cs +++ /dev/null @@ -1,43 +0,0 @@ -#nullable disable - -#pragma warning disable CS1591 - -using System.Collections.Generic; -using MediaBrowser.Model.MediaInfo; - -namespace MediaBrowser.Controller.Sync -{ - public class SyncedFileInfo - { - public SyncedFileInfo() - { - RequiredHttpHeaders = new Dictionary(); - } - - /// - /// Gets or sets the path. - /// - /// The path. - public string Path { get; set; } - - public string[] PathParts { get; set; } - - /// - /// Gets or sets the protocol. - /// - /// The protocol. - public MediaProtocol Protocol { get; set; } - - /// - /// Gets or sets the required HTTP headers. - /// - /// The required HTTP headers. - public Dictionary RequiredHttpHeaders { get; set; } - - /// - /// Gets or sets the identifier. - /// - /// The identifier. - public string Id { get; set; } - } -} diff --git a/MediaBrowser.Controller/TV/ITVSeriesManager.cs b/MediaBrowser.Controller/TV/ITVSeriesManager.cs index 291dea04e..328cf18f6 100644 --- a/MediaBrowser.Controller/TV/ITVSeriesManager.cs +++ b/MediaBrowser.Controller/TV/ITVSeriesManager.cs @@ -6,16 +6,26 @@ using MediaBrowser.Model.Querying; namespace MediaBrowser.Controller.TV { + /// + /// The TV Series manager. + /// public interface ITVSeriesManager { /// /// Gets the next up. /// + /// The next up query. + /// The dto options. + /// The query result of . QueryResult GetNextUp(NextUpQuery query, DtoOptions options); /// /// Gets the next up. /// + /// The next up request. + /// The list of parent folders. + /// The dto options. + /// The query result of . QueryResult GetNextUp(NextUpQuery request, BaseItem[] parentsFolders, DtoOptions options); } } -- cgit v1.2.3 From ffc5aba023ee8ba77331447929079f0b0f4068a2 Mon Sep 17 00:00:00 2001 From: nyanmisaka Date: Sun, 16 May 2021 18:40:28 +0800 Subject: Fix the 'No decoder surfaces left' error on Cuda --- MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs') diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 97cb8d63b..61d583d94 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -596,7 +596,8 @@ namespace MediaBrowser.Controller.MediaEncoding && string.Equals(encodingOptions.HardwareAccelerationType, "nvenc", StringComparison.OrdinalIgnoreCase) && isNvdecDecoder) { - arg.Append("-hwaccel_output_format cuda -autorotate 0 "); + // Fix for 'No decoder surfaces left' error. https://trac.ffmpeg.org/ticket/7562 + arg.Append("-hwaccel_output_format cuda -extra_hw_frames 3 -autorotate 0 "); } if (state.IsVideoRequest @@ -1070,7 +1071,6 @@ namespace MediaBrowser.Controller.MediaEncoding else if (string.Equals(videoEncoder, "h264_nvenc", StringComparison.OrdinalIgnoreCase) // h264 (h264_nvenc) || string.Equals(videoEncoder, "hevc_nvenc", StringComparison.OrdinalIgnoreCase)) // hevc (hevc_nvenc) { - // following preset will be deprecated in ffmpeg 4.4, use p1~p7 instead. switch (encodingOptions.EncoderPreset) { case "veryslow": @@ -1251,7 +1251,7 @@ namespace MediaBrowser.Controller.MediaEncoding } if (string.Equals(videoEncoder, "h264_amf", StringComparison.OrdinalIgnoreCase) - && profile.Contains("constrainedbaseline", StringComparison.OrdinalIgnoreCase)) + && profile.Contains("baseline", StringComparison.OrdinalIgnoreCase)) { profile = "constrained_baseline"; } -- cgit v1.2.3 From d461e3912a1dfb59a22234e434497b72834de66b Mon Sep 17 00:00:00 2001 From: Cody Robibero Date: Sun, 6 Jun 2021 09:16:41 -0600 Subject: Remove warninigs from MediaBrowser.Controller (Part 3) (#6078) Co-authored-by: Bond-009 --- .../Library/LibraryManager.cs | 10 +- .../Channels/IDisableMediaSourceDisplay.cs | 8 +- .../Channels/ISupportsMediaProbe.cs | 5 +- .../Entities/AggregateFolder.cs | 6 +- MediaBrowser.Controller/Entities/Audio/Audio.cs | 9 +- .../Entities/Audio/MusicArtist.cs | 4 +- MediaBrowser.Controller/Entities/BaseItem.cs | 42 +++-- .../Entities/CollectionFolder.cs | 6 +- MediaBrowser.Controller/Entities/Folder.cs | 27 ++- MediaBrowser.Controller/Entities/Genre.cs | 6 +- .../Entities/IHasScreenshots.cs | 4 +- .../Entities/ISupportsBoxSetGrouping.cs | 2 + .../Entities/LinkedChildComparer.cs | 3 +- MediaBrowser.Controller/Entities/TV/Episode.cs | 7 +- MediaBrowser.Controller/Entities/TV/Season.cs | 4 +- MediaBrowser.Controller/Entities/UserRootFolder.cs | 4 +- MediaBrowser.Controller/Entities/UserView.cs | 2 +- .../Entities/UserViewBuilder.cs | 18 +- MediaBrowser.Controller/Entities/Video.cs | 3 +- MediaBrowser.Controller/IO/FileData.cs | 2 +- MediaBrowser.Controller/Library/ILibraryManager.cs | 6 +- .../Library/IUserDataManager.cs | 11 +- MediaBrowser.Controller/Library/IUserManager.cs | 12 +- MediaBrowser.Controller/Library/ItemResolveArgs.cs | 6 +- MediaBrowser.Controller/LiveTv/LiveTvProgram.cs | 7 +- .../MediaEncoding/BaseEncodingJobOptions.cs | 204 ++++++++++++++++++++ .../MediaEncoding/EncodingHelper.cs | 27 +-- .../MediaEncoding/EncodingJobInfo.cs | 1 + .../MediaEncoding/EncodingJobOptions.cs | 205 --------------------- MediaBrowser.Controller/MediaEncoding/JobLogger.cs | 1 + .../Net/BasePeriodicWebSocketListener.cs | 9 - .../Net/IWebSocketConnection.cs | 4 +- .../Net/WebSocketListenerState.cs | 17 ++ .../Persistence/IItemRepository.cs | 12 +- .../Persistence/IUserDataRepository.cs | 11 +- MediaBrowser.Controller/Playlists/Playlist.cs | 2 +- .../Plugins/IRunBeforeStartup.cs | 4 +- .../Providers/IForcedProvider.cs | 2 + .../Resolvers/BaseItemResolver.cs | 57 ------ MediaBrowser.Controller/Resolvers/ItemResolver.cs | 57 ++++++ .../Sorting/AlphanumComparator.cs | 2 + MediaBrowser.Providers/Manager/ProviderManager.cs | 6 +- 42 files changed, 441 insertions(+), 394 deletions(-) create mode 100644 MediaBrowser.Controller/MediaEncoding/BaseEncodingJobOptions.cs delete mode 100644 MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs create mode 100644 MediaBrowser.Controller/Net/WebSocketListenerState.cs delete mode 100644 MediaBrowser.Controller/Resolvers/BaseItemResolver.cs create mode 100644 MediaBrowser.Controller/Resolvers/ItemResolver.cs (limited to 'MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs') diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index f8d8197d4..4af1f10f0 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -1065,17 +1065,17 @@ namespace Emby.Server.Implementations.Library // Start by just validating the children of the root, but go no further await RootFolder.ValidateChildren( new SimpleProgress(), - cancellationToken, new MetadataRefreshOptions(new DirectoryService(_fileSystem)), - recursive: false).ConfigureAwait(false); + recursive: false, + cancellationToken).ConfigureAwait(false); await GetUserRootFolder().RefreshMetadata(cancellationToken).ConfigureAwait(false); await GetUserRootFolder().ValidateChildren( new SimpleProgress(), - cancellationToken, new MetadataRefreshOptions(new DirectoryService(_fileSystem)), - recursive: false).ConfigureAwait(false); + recursive: false, + cancellationToken).ConfigureAwait(false); // Quickly scan CollectionFolders for changes foreach (var folder in GetUserRootFolder().Children.OfType()) @@ -1095,7 +1095,7 @@ namespace Emby.Server.Implementations.Library innerProgress.RegisterAction(pct => progress.Report(pct * 0.96)); // Validate the entire media library - await RootFolder.ValidateChildren(innerProgress, cancellationToken, new MetadataRefreshOptions(new DirectoryService(_fileSystem)), recursive: true).ConfigureAwait(false); + await RootFolder.ValidateChildren(innerProgress, new MetadataRefreshOptions(new DirectoryService(_fileSystem)), recursive: true, cancellationToken).ConfigureAwait(false); progress.Report(96); diff --git a/MediaBrowser.Controller/Channels/IDisableMediaSourceDisplay.cs b/MediaBrowser.Controller/Channels/IDisableMediaSourceDisplay.cs index a2dc5682d..8d0d8dc9f 100644 --- a/MediaBrowser.Controller/Channels/IDisableMediaSourceDisplay.cs +++ b/MediaBrowser.Controller/Channels/IDisableMediaSourceDisplay.cs @@ -1,7 +1,13 @@ -#pragma warning disable CS1591 +#pragma warning disable CA1040 // Avoid empty interfaces namespace MediaBrowser.Controller.Channels { + /// + /// Disable media source display. + /// + /// + /// can inherit this interface to disable being displayed. + /// public interface IDisableMediaSourceDisplay { } diff --git a/MediaBrowser.Controller/Channels/ISupportsMediaProbe.cs b/MediaBrowser.Controller/Channels/ISupportsMediaProbe.cs index 2682de51c..e411b081c 100644 --- a/MediaBrowser.Controller/Channels/ISupportsMediaProbe.cs +++ b/MediaBrowser.Controller/Channels/ISupportsMediaProbe.cs @@ -1,7 +1,10 @@ -#pragma warning disable CS1591 +#pragma warning disable CA1040 // Avoid empty interfaces namespace MediaBrowser.Controller.Channels { + /// + /// Channel supports media probe. + /// public interface ISupportsMediaProbe { } diff --git a/MediaBrowser.Controller/Entities/AggregateFolder.cs b/MediaBrowser.Controller/Entities/AggregateFolder.cs index 533130fc8..fe1bc62ab 100644 --- a/MediaBrowser.Controller/Entities/AggregateFolder.cs +++ b/MediaBrowser.Controller/Entities/AggregateFolder.cs @@ -155,11 +155,11 @@ namespace MediaBrowser.Controller.Entities return base.GetNonCachedChildren(directoryService).Concat(_virtualChildren); } - protected override async Task ValidateChildrenInternal(IProgress progress, CancellationToken cancellationToken, bool recursive, bool refreshChildMetadata, MetadataRefreshOptions refreshOptions, IDirectoryService directoryService) + protected override async Task ValidateChildrenInternal(IProgress progress, bool recursive, bool refreshChildMetadata, MetadataRefreshOptions refreshOptions, IDirectoryService directoryService, CancellationToken cancellationToken) { ClearCache(); - await base.ValidateChildrenInternal(progress, cancellationToken, recursive, refreshChildMetadata, refreshOptions, directoryService) + await base.ValidateChildrenInternal(progress, recursive, refreshChildMetadata, refreshOptions, directoryService, cancellationToken) .ConfigureAwait(false); ClearCache(); @@ -185,7 +185,7 @@ namespace MediaBrowser.Controller.Entities /// /// The id. /// BaseItem. - /// id + /// The id is empty. public BaseItem FindVirtualChild(Guid id) { if (id.Equals(Guid.Empty)) diff --git a/MediaBrowser.Controller/Entities/Audio/Audio.cs b/MediaBrowser.Controller/Entities/Audio/Audio.cs index 4c2b7cb7c..576ab67a2 100644 --- a/MediaBrowser.Controller/Entities/Audio/Audio.cs +++ b/MediaBrowser.Controller/Entities/Audio/Audio.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using System.Text.Json.Serialization; using Jellyfin.Data.Enums; @@ -82,19 +83,19 @@ namespace MediaBrowser.Controller.Entities.Audio /// System.String. protected override string CreateSortName() { - return (ParentIndexNumber != null ? ParentIndexNumber.Value.ToString("0000 - ") : "") - + (IndexNumber != null ? IndexNumber.Value.ToString("0000 - ") : "") + Name; + return (ParentIndexNumber != null ? ParentIndexNumber.Value.ToString("0000 - ", CultureInfo.InvariantCulture) : string.Empty) + + (IndexNumber != null ? IndexNumber.Value.ToString("0000 - ", CultureInfo.InvariantCulture) : string.Empty) + Name; } public override List GetUserDataKeys() { var list = base.GetUserDataKeys(); - var songKey = IndexNumber.HasValue ? IndexNumber.Value.ToString("0000") : string.Empty; + var songKey = IndexNumber.HasValue ? IndexNumber.Value.ToString("0000", CultureInfo.InvariantCulture) : string.Empty; if (ParentIndexNumber.HasValue) { - songKey = ParentIndexNumber.Value.ToString("0000") + "-" + songKey; + songKey = ParentIndexNumber.Value.ToString("0000", CultureInfo.InvariantCulture) + "-" + songKey; } songKey += Name; diff --git a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs index 0928a8073..c0cd81110 100644 --- a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs +++ b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs @@ -94,7 +94,7 @@ namespace MediaBrowser.Controller.Entities.Audio return base.IsSaveLocalMetadataEnabled(); } - protected override Task ValidateChildrenInternal(IProgress progress, CancellationToken cancellationToken, bool recursive, bool refreshChildMetadata, MetadataRefreshOptions refreshOptions, IDirectoryService directoryService) + protected override Task ValidateChildrenInternal(IProgress progress, bool recursive, bool refreshChildMetadata, MetadataRefreshOptions refreshOptions, IDirectoryService directoryService, CancellationToken cancellationToken) { if (IsAccessedByName) { @@ -102,7 +102,7 @@ namespace MediaBrowser.Controller.Entities.Audio return Task.CompletedTask; } - return base.ValidateChildrenInternal(progress, cancellationToken, recursive, refreshChildMetadata, refreshOptions, directoryService); + return base.ValidateChildrenInternal(progress, recursive, refreshChildMetadata, refreshOptions, directoryService, cancellationToken); } public override List GetUserDataKeys() diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index 6e46b4cec..fcb120ad7 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -620,7 +620,11 @@ namespace MediaBrowser.Controller.Entities public string ForcedSortName { get => _forcedSortName; - set { _forcedSortName = value; _sortName = null; } + set + { + _forcedSortName = value; + _sortName = null; + } } private string _sortName; @@ -1337,7 +1341,7 @@ namespace MediaBrowser.Controller.Entities } // Use some hackery to get the extra type based on foldername - item.ExtraType = Enum.TryParse(extraFolderName.Replace(" ", string.Empty), true, out ExtraType extraType) + item.ExtraType = Enum.TryParse(extraFolderName.Replace(" ", string.Empty, StringComparison.Ordinal), true, out ExtraType extraType) ? extraType : Model.Entities.ExtraType.Unknown; @@ -1427,10 +1431,10 @@ namespace MediaBrowser.Controller.Entities /// Refreshes owned items such as trailers, theme videos, special features, etc. /// Returns true or false indicating if changes were found. /// - /// - /// - /// - /// + /// The metadata refresh options. + /// The list of filesystem children. + /// The cancellation token. + /// true if any items have changed, else false. protected virtual async Task RefreshedOwnedItems(MetadataRefreshOptions options, List fileSystemChildren, CancellationToken cancellationToken) { var themeSongsChanged = false; @@ -1772,7 +1776,7 @@ namespace MediaBrowser.Controller.Entities /// /// The user. /// true if [is parental allowed] [the specified user]; otherwise, false. - /// user + /// If user is null. public bool IsParentalAllowed(User user) { if (user == null) @@ -1917,7 +1921,7 @@ namespace MediaBrowser.Controller.Entities /// /// The user. /// true if the specified user is visible; otherwise, false. - /// user + /// is null. public virtual bool IsVisible(User user) { if (user == null) @@ -2215,7 +2219,7 @@ namespace MediaBrowser.Controller.Entities /// The type. /// Index of the image. /// true if the specified type has image; otherwise, false. - /// Backdrops should be accessed using Item.Backdrops + /// Backdrops should be accessed using Item.Backdrops. public bool HasImage(ImageType type, int imageIndex) { return GetImageInfo(type, imageIndex) != null; @@ -2344,9 +2348,8 @@ namespace MediaBrowser.Controller.Entities /// Type of the image. /// Index of the image. /// System.String. - /// - /// - /// item + /// + /// Item is null. public string GetImagePath(ImageType imageType, int imageIndex) => GetImageInfo(imageType, imageIndex)?.Path; @@ -2442,7 +2445,7 @@ namespace MediaBrowser.Controller.Entities /// Type of the image. /// The images. /// true if XXXX, false otherwise. - /// Cannot call AddImages with chapter images + /// Cannot call AddImages with chapter images. public bool AddImages(ImageType imageType, List images) { if (imageType == ImageType.Chapter) @@ -2526,10 +2529,11 @@ namespace MediaBrowser.Controller.Entities /// /// Gets the file system path to delete when the item is to be deleted. /// - /// + /// The metadata for the deleted paths. public virtual IEnumerable GetDeletePaths() { - return new[] { + return new[] + { new FileSystemMetadata { FullName = Path, @@ -2889,7 +2893,7 @@ namespace MediaBrowser.Controller.Entities /// /// Updates the official rating based on content and returns true or false indicating if it changed. /// - /// + /// true if the rating was updated; otherwise false. public bool UpdateRatingToItems(IList children) { var currentOfficialRating = OfficialRating; @@ -2905,7 +2909,9 @@ namespace MediaBrowser.Controller.Entities OfficialRating = ratings.FirstOrDefault() ?? currentOfficialRating; - return !string.Equals(currentOfficialRating ?? string.Empty, OfficialRating ?? string.Empty, + return !string.Equals( + currentOfficialRating ?? string.Empty, + OfficialRating ?? string.Empty, StringComparison.OrdinalIgnoreCase); } @@ -3002,7 +3008,7 @@ namespace MediaBrowser.Controller.Entities } /// - public bool Equals(BaseItem item) => Object.Equals(Id, item?.Id); + public bool Equals(BaseItem other) => object.Equals(Id, other?.Id); /// public override int GetHashCode() => HashCode.Combine(Id); diff --git a/MediaBrowser.Controller/Entities/CollectionFolder.cs b/MediaBrowser.Controller/Entities/CollectionFolder.cs index d0fb3997d..4a721ca44 100644 --- a/MediaBrowser.Controller/Entities/CollectionFolder.cs +++ b/MediaBrowser.Controller/Entities/CollectionFolder.cs @@ -315,16 +315,16 @@ namespace MediaBrowser.Controller.Entities /// /// Compare our current children (presumably just read from the repo) with the current state of the file system and adjust for any changes - /// ***Currently does not contain logic to maintain items that are unavailable in the file system*** + /// ***Currently does not contain logic to maintain items that are unavailable in the file system***. /// /// The progress. - /// The cancellation token. /// if set to true [recursive]. /// if set to true [refresh child metadata]. /// The refresh options. /// The directory service. + /// The cancellation token. /// Task. - protected override Task ValidateChildrenInternal(IProgress progress, CancellationToken cancellationToken, bool recursive, bool refreshChildMetadata, MetadataRefreshOptions refreshOptions, IDirectoryService directoryService) + protected override Task ValidateChildrenInternal(IProgress progress, bool recursive, bool refreshChildMetadata, MetadataRefreshOptions refreshOptions, IDirectoryService directoryService, CancellationToken cancellationToken) { return Task.CompletedTask; } diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index 29d837c14..bce284831 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -207,8 +207,7 @@ namespace MediaBrowser.Controller.Entities /// /// The item. /// The cancellation token. - /// Task. - /// Unable to add + item.Name + /// Unable to add + item.Name. public void AddChild(BaseItem item, CancellationToken cancellationToken) { item.SetParent(this); @@ -274,20 +273,20 @@ namespace MediaBrowser.Controller.Entities public Task ValidateChildren(IProgress progress, CancellationToken cancellationToken) { - return ValidateChildren(progress, cancellationToken, new MetadataRefreshOptions(new DirectoryService(FileSystem))); + return ValidateChildren(progress, new MetadataRefreshOptions(new DirectoryService(FileSystem)), cancellationToken: cancellationToken); } /// /// Validates that the children of the folder still exist. /// /// The progress. - /// The cancellation token. /// The metadata refresh options. /// if set to true [recursive]. + /// The cancellation token. /// Task. - public Task ValidateChildren(IProgress progress, CancellationToken cancellationToken, MetadataRefreshOptions metadataRefreshOptions, bool recursive = true) + public Task ValidateChildren(IProgress progress, MetadataRefreshOptions metadataRefreshOptions, bool recursive = true, CancellationToken cancellationToken = default) { - return ValidateChildrenInternal(progress, cancellationToken, recursive, true, metadataRefreshOptions, metadataRefreshOptions.DirectoryService); + return ValidateChildrenInternal(progress, recursive, true, metadataRefreshOptions, metadataRefreshOptions.DirectoryService, cancellationToken); } private Dictionary GetActualChildrenDictionary() @@ -327,13 +326,13 @@ namespace MediaBrowser.Controller.Entities /// Validates the children internal. /// /// The progress. - /// The cancellation token. /// if set to true [recursive]. /// if set to true [refresh child metadata]. /// The refresh options. /// The directory service. + /// The cancellation token. /// Task. - protected virtual async Task ValidateChildrenInternal(IProgress progress, CancellationToken cancellationToken, bool recursive, bool refreshChildMetadata, MetadataRefreshOptions refreshOptions, IDirectoryService directoryService) + protected virtual async Task ValidateChildrenInternal(IProgress progress, bool recursive, bool refreshChildMetadata, MetadataRefreshOptions refreshOptions, IDirectoryService directoryService, CancellationToken cancellationToken) { if (recursive) { @@ -342,7 +341,7 @@ namespace MediaBrowser.Controller.Entities try { - await ValidateChildrenInternal2(progress, cancellationToken, recursive, refreshChildMetadata, refreshOptions, directoryService).ConfigureAwait(false); + await ValidateChildrenInternal2(progress, recursive, refreshChildMetadata, refreshOptions, directoryService, cancellationToken).ConfigureAwait(false); } finally { @@ -353,7 +352,7 @@ namespace MediaBrowser.Controller.Entities } } - private async Task ValidateChildrenInternal2(IProgress progress, CancellationToken cancellationToken, bool recursive, bool refreshChildMetadata, MetadataRefreshOptions refreshOptions, IDirectoryService directoryService) + private async Task ValidateChildrenInternal2(IProgress progress, bool recursive, bool refreshChildMetadata, MetadataRefreshOptions refreshOptions, IDirectoryService directoryService, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); @@ -575,7 +574,7 @@ namespace MediaBrowser.Controller.Entities private Task ValidateSubFolders(IList children, IDirectoryService directoryService, IProgress progress, CancellationToken cancellationToken) { return RunTasks( - (folder, innerProgress) => folder.ValidateChildrenInternal(innerProgress, cancellationToken, true, false, null, directoryService), + (folder, innerProgress) => folder.ValidateChildrenInternal(innerProgress, true, false, null, directoryService, cancellationToken), children, progress, cancellationToken); @@ -1013,7 +1012,7 @@ namespace MediaBrowser.Controller.Entities if (!string.IsNullOrEmpty(query.NameStartsWith)) { - items = items.Where(i => i.SortName.StartsWith(query.NameStartsWith, StringComparison.OrdinalIgnoreCase)); + items = items.Where(i => i.SortName.StartsWith(query.NameStartsWith, StringComparison.CurrentCultureIgnoreCase)); } if (!string.IsNullOrEmpty(query.NameLessThan)) @@ -1324,7 +1323,6 @@ namespace MediaBrowser.Controller.Entities /// /// Adds the children to list. /// - /// true if XXXX, false otherwise private void AddChildren(User user, bool includeLinkedChildren, Dictionary result, bool recursive, InternalItemsQuery query) { foreach (var child in GetEligibleChildrenForRecursiveChildren(user)) @@ -1596,7 +1594,8 @@ namespace MediaBrowser.Controller.Entities /// /// Refreshes the linked children. /// - /// true if XXXX, false otherwise + /// The enumerable of file system metadata. + /// true if the linked children were updated, false otherwise. protected virtual bool RefreshLinkedChildren(IEnumerable fileSystemChildren) { if (SupportsShortcutChildren) diff --git a/MediaBrowser.Controller/Entities/Genre.cs b/MediaBrowser.Controller/Entities/Genre.cs index 698643b44..b80a5be3b 100644 --- a/MediaBrowser.Controller/Entities/Genre.cs +++ b/MediaBrowser.Controller/Entities/Genre.cs @@ -107,7 +107,11 @@ namespace MediaBrowser.Controller.Entities return base.RequiresRefresh(); } - /// + /// + /// This is called before any metadata refresh and returns true if changes were made. + /// + /// Whether to replace all metadata. + /// true if the item has change, else false. public override bool BeforeMetadataRefresh(bool replaceAllMetadata) { var hasChanges = base.BeforeMetadataRefresh(replaceAllMetadata); diff --git a/MediaBrowser.Controller/Entities/IHasScreenshots.cs b/MediaBrowser.Controller/Entities/IHasScreenshots.cs index b027a0cb1..f894b35db 100644 --- a/MediaBrowser.Controller/Entities/IHasScreenshots.cs +++ b/MediaBrowser.Controller/Entities/IHasScreenshots.cs @@ -1,7 +1,9 @@ +#pragma warning disable CA1040 // Avoid empty interfaces + namespace MediaBrowser.Controller.Entities { /// - /// Interface IHasScreenshots. + /// The item has screenshots. /// public interface IHasScreenshots { diff --git a/MediaBrowser.Controller/Entities/ISupportsBoxSetGrouping.cs b/MediaBrowser.Controller/Entities/ISupportsBoxSetGrouping.cs index 7d13bf325..1077f462d 100644 --- a/MediaBrowser.Controller/Entities/ISupportsBoxSetGrouping.cs +++ b/MediaBrowser.Controller/Entities/ISupportsBoxSetGrouping.cs @@ -1,3 +1,5 @@ +#pragma warning disable CA1040 // Avoid empty interfaces + namespace MediaBrowser.Controller.Entities { /// diff --git a/MediaBrowser.Controller/Entities/LinkedChildComparer.cs b/MediaBrowser.Controller/Entities/LinkedChildComparer.cs index 66fc44b8a..4e58e2942 100644 --- a/MediaBrowser.Controller/Entities/LinkedChildComparer.cs +++ b/MediaBrowser.Controller/Entities/LinkedChildComparer.cs @@ -2,6 +2,7 @@ #pragma warning disable CS1591 +using System; using System.Collections.Generic; using MediaBrowser.Model.IO; @@ -28,7 +29,7 @@ namespace MediaBrowser.Controller.Entities public int GetHashCode(LinkedChild obj) { - return ((obj.Path ?? string.Empty) + (obj.LibraryItemId ?? string.Empty) + obj.Type).GetHashCode(); + return ((obj.Path ?? string.Empty) + (obj.LibraryItemId ?? string.Empty) + obj.Type).GetHashCode(StringComparison.Ordinal); } } } \ No newline at end of file diff --git a/MediaBrowser.Controller/Entities/TV/Episode.cs b/MediaBrowser.Controller/Entities/TV/Episode.cs index 1b4cc7a78..31c179bca 100644 --- a/MediaBrowser.Controller/Entities/TV/Episode.cs +++ b/MediaBrowser.Controller/Entities/TV/Episode.cs @@ -218,8 +218,8 @@ namespace MediaBrowser.Controller.Entities.TV /// System.String. protected override string CreateSortName() { - return (ParentIndexNumber != null ? ParentIndexNumber.Value.ToString("000 - ") : "") - + (IndexNumber != null ? IndexNumber.Value.ToString("0000 - ") : "") + Name; + return (ParentIndexNumber != null ? ParentIndexNumber.Value.ToString("000 - ", CultureInfo.InvariantCulture) : string.Empty) + + (IndexNumber != null ? IndexNumber.Value.ToString("0000 - ", CultureInfo.InvariantCulture) : string.Empty) + Name; } /// @@ -287,7 +287,8 @@ namespace MediaBrowser.Controller.Entities.TV public override IEnumerable GetDeletePaths() { - return new[] { + return new[] + { new FileSystemMetadata { FullName = Path, diff --git a/MediaBrowser.Controller/Entities/TV/Season.cs b/MediaBrowser.Controller/Entities/TV/Season.cs index 5e2053dcc..aa62bb35b 100644 --- a/MediaBrowser.Controller/Entities/TV/Season.cs +++ b/MediaBrowser.Controller/Entities/TV/Season.cs @@ -122,7 +122,7 @@ namespace MediaBrowser.Controller.Entities.TV var series = Series; if (series != null) { - return series.PresentationUniqueKey + "-" + (IndexNumber ?? 0).ToString("000"); + return series.PresentationUniqueKey + "-" + (IndexNumber ?? 0).ToString("000", CultureInfo.InvariantCulture); } } @@ -135,7 +135,7 @@ namespace MediaBrowser.Controller.Entities.TV /// System.String. protected override string CreateSortName() { - return IndexNumber != null ? IndexNumber.Value.ToString("0000") : Name; + return IndexNumber != null ? IndexNumber.Value.ToString("0000", CultureInfo.InvariantCulture) : Name; } protected override QueryResult GetItemsInternal(InternalItemsQuery query) diff --git a/MediaBrowser.Controller/Entities/UserRootFolder.cs b/MediaBrowser.Controller/Entities/UserRootFolder.cs index 2dea2e50b..2b15a52f0 100644 --- a/MediaBrowser.Controller/Entities/UserRootFolder.cs +++ b/MediaBrowser.Controller/Entities/UserRootFolder.cs @@ -109,11 +109,11 @@ namespace MediaBrowser.Controller.Entities return base.GetNonCachedChildren(directoryService); } - protected override async Task ValidateChildrenInternal(IProgress progress, CancellationToken cancellationToken, bool recursive, bool refreshChildMetadata, MetadataRefreshOptions refreshOptions, IDirectoryService directoryService) + protected override async Task ValidateChildrenInternal(IProgress progress, bool recursive, bool refreshChildMetadata, MetadataRefreshOptions refreshOptions, IDirectoryService directoryService, CancellationToken cancellationToken) { ClearCache(); - await base.ValidateChildrenInternal(progress, cancellationToken, recursive, refreshChildMetadata, refreshOptions, directoryService) + await base.ValidateChildrenInternal(progress, recursive, refreshChildMetadata, refreshOptions, directoryService, cancellationToken) .ConfigureAwait(false); ClearCache(); diff --git a/MediaBrowser.Controller/Entities/UserView.cs b/MediaBrowser.Controller/Entities/UserView.cs index 1e6c01bf8..57dc9b59b 100644 --- a/MediaBrowser.Controller/Entities/UserView.cs +++ b/MediaBrowser.Controller/Entities/UserView.cs @@ -172,7 +172,7 @@ namespace MediaBrowser.Controller.Entities return OriginalFolderViewTypes.Contains(viewType ?? string.Empty, StringComparer.OrdinalIgnoreCase); } - protected override Task ValidateChildrenInternal(IProgress progress, System.Threading.CancellationToken cancellationToken, bool recursive, bool refreshChildMetadata, Providers.MetadataRefreshOptions refreshOptions, Providers.IDirectoryService directoryService) + protected override Task ValidateChildrenInternal(IProgress progress, bool recursive, bool refreshChildMetadata, Providers.MetadataRefreshOptions refreshOptions, Providers.IDirectoryService directoryService, System.Threading.CancellationToken cancellationToken) { return Task.CompletedTask; } diff --git a/MediaBrowser.Controller/Entities/UserViewBuilder.cs b/MediaBrowser.Controller/Entities/UserViewBuilder.cs index 15a4573c2..add734f62 100644 --- a/MediaBrowser.Controller/Entities/UserViewBuilder.cs +++ b/MediaBrowser.Controller/Entities/UserViewBuilder.cs @@ -55,12 +55,12 @@ namespace MediaBrowser.Controller.Entities // if (query.IncludeItemTypes != null && // query.IncludeItemTypes.Length == 1 && // string.Equals(query.IncludeItemTypes[0], "Playlist", StringComparison.OrdinalIgnoreCase)) - //{ + // { // if (!string.Equals(viewType, CollectionType.Playlists, StringComparison.OrdinalIgnoreCase)) // { // return await FindPlaylists(queryParent, user, query).ConfigureAwait(false); // } - //} + // } switch (viewType) { @@ -344,12 +344,14 @@ namespace MediaBrowser.Controller.Entities var parentFolders = GetMediaFolders(parent, query.User, new[] { CollectionType.TvShows, string.Empty }); var result = _tvSeriesManager.GetNextUp( - new NextUpQuery - { - Limit = query.Limit, - StartIndex = query.StartIndex, - UserId = query.User.Id - }, parentFolders, query.DtoOptions); + new NextUpQuery + { + Limit = query.Limit, + StartIndex = query.StartIndex, + UserId = query.User.Id + }, + parentFolders, + query.DtoOptions); return result; } diff --git a/MediaBrowser.Controller/Entities/Video.cs b/MediaBrowser.Controller/Entities/Video.cs index 723027a88..d05b5df2f 100644 --- a/MediaBrowser.Controller/Entities/Video.cs +++ b/MediaBrowser.Controller/Entities/Video.cs @@ -482,7 +482,8 @@ namespace MediaBrowser.Controller.Entities { if (!IsInMixedFolder) { - return new[] { + return new[] + { new FileSystemMetadata { FullName = ContainingFolderPath, diff --git a/MediaBrowser.Controller/IO/FileData.cs b/MediaBrowser.Controller/IO/FileData.cs index 3db60ae0b..b8a0bf331 100644 --- a/MediaBrowser.Controller/IO/FileData.cs +++ b/MediaBrowser.Controller/IO/FileData.cs @@ -24,7 +24,7 @@ namespace MediaBrowser.Controller.IO /// The flatten folder depth. /// if set to true [resolve shortcuts]. /// Dictionary{System.StringFileSystemInfo}. - /// path + /// is null or empty. public static FileSystemMetadata[] GetFilteredFileSystemEntries( IDirectoryService directoryService, string path, diff --git a/MediaBrowser.Controller/Library/ILibraryManager.cs b/MediaBrowser.Controller/Library/ILibraryManager.cs index 3fd4ff899..0593e65f5 100644 --- a/MediaBrowser.Controller/Library/ILibraryManager.cs +++ b/MediaBrowser.Controller/Library/ILibraryManager.cs @@ -352,6 +352,7 @@ namespace MediaBrowser.Controller.Library /// Type of the view. /// Name of the sort. /// The unique identifier. + /// The named view. UserView GetNamedView( string name, Guid parentId, @@ -365,10 +366,11 @@ namespace MediaBrowser.Controller.Library /// The parent. /// Type of the view. /// Name of the sort. + /// The shadow view. UserView GetShadowView( BaseItem parent, - string viewType, - string sortName); + string viewType, + string sortName); /// /// Determines whether [is video file] [the specified path]. diff --git a/MediaBrowser.Controller/Library/IUserDataManager.cs b/MediaBrowser.Controller/Library/IUserDataManager.cs index 58499e853..e5dcfcff0 100644 --- a/MediaBrowser.Controller/Library/IUserDataManager.cs +++ b/MediaBrowser.Controller/Library/IUserDataManager.cs @@ -49,17 +49,16 @@ namespace MediaBrowser.Controller.Library /// /// Get all user data for the given user. /// - /// - /// + /// The user id. + /// The user item data. List GetAllUserData(Guid userId); /// /// Save the all provided user data for the given user. /// - /// - /// - /// - /// + /// The user id. + /// The array of user data. + /// The cancellation token. void SaveAllUserData(Guid userId, UserItemData[] userData, CancellationToken cancellationToken); /// diff --git a/MediaBrowser.Controller/Library/IUserManager.cs b/MediaBrowser.Controller/Library/IUserManager.cs index c95b0ea32..1801b1c41 100644 --- a/MediaBrowser.Controller/Library/IUserManager.cs +++ b/MediaBrowser.Controller/Library/IUserManager.cs @@ -61,16 +61,16 @@ namespace MediaBrowser.Controller.Library /// The user. /// The new name. /// Task. - /// user - /// + /// If user is null. + /// If the provided user doesn't exist. Task RenameUser(User user, string newName); /// /// Updates the user. /// /// The user. - /// user - /// + /// If user is null. + /// If the provided user doesn't exist. void UpdateUser(User user); /// @@ -87,8 +87,8 @@ namespace MediaBrowser.Controller.Library /// /// The name of the new user. /// The created user. - /// name - /// + /// is null or empty. + /// already exists. Task CreateUserAsync(string name); /// diff --git a/MediaBrowser.Controller/Library/ItemResolveArgs.cs b/MediaBrowser.Controller/Library/ItemResolveArgs.cs index 0e2d8fb02..521e37274 100644 --- a/MediaBrowser.Controller/Library/ItemResolveArgs.cs +++ b/MediaBrowser.Controller/Library/ItemResolveArgs.cs @@ -39,7 +39,7 @@ namespace MediaBrowser.Controller.Library public IDirectoryService DirectoryService { get; } /// - /// Gets the file system children. + /// Gets or sets the file system children. /// /// The file system children. public FileSystemMetadata[] FileSystemChildren { get; set; } @@ -242,14 +242,14 @@ namespace MediaBrowser.Controller.Library /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. public override int GetHashCode() { - return Path.GetHashCode(); + return Path.GetHashCode(StringComparison.Ordinal); } /// /// Equals the specified args. /// /// The args. - /// true if XXXX, false otherwise + /// true if the arguments are the same, false otherwise. protected bool Equals(ItemResolveArgs args) { if (args != null) diff --git a/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs b/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs index e2adec000..9d638a0bf 100644 --- a/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs +++ b/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs @@ -53,6 +53,7 @@ namespace MediaBrowser.Controller.LiveTv } private static string EmbyServiceName = "Emby"; + public override double GetDefaultPrimaryImageAspectRatio() { var serviceName = ServiceName; @@ -150,14 +151,14 @@ namespace MediaBrowser.Controller.LiveTv [JsonIgnore] public override string ContainingFolderPath => Path; - //[JsonIgnore] + // [JsonIgnore] // public override string MediaType - //{ + // { // get // { // return ChannelType == ChannelType.TV ? Model.Entities.MediaType.Video : Model.Entities.MediaType.Audio; // } - //} + // } [JsonIgnore] public bool IsAiring diff --git a/MediaBrowser.Controller/MediaEncoding/BaseEncodingJobOptions.cs b/MediaBrowser.Controller/MediaEncoding/BaseEncodingJobOptions.cs new file mode 100644 index 000000000..745ee6bdb --- /dev/null +++ b/MediaBrowser.Controller/MediaEncoding/BaseEncodingJobOptions.cs @@ -0,0 +1,204 @@ +#nullable disable + +#pragma warning disable CS1591 + +using System; +using System.Collections.Generic; +using MediaBrowser.Model.Dlna; + +namespace MediaBrowser.Controller.MediaEncoding +{ + public class BaseEncodingJobOptions + { + /// + /// Gets or sets the id. + /// + /// The id. + public Guid Id { get; set; } + + public string MediaSourceId { get; set; } + + public string DeviceId { get; set; } + + public string Container { get; set; } + + /// + /// Gets or sets the audio codec. + /// + /// The audio codec. + public string AudioCodec { get; set; } + + public bool EnableAutoStreamCopy { get; set; } + + public bool AllowVideoStreamCopy { get; set; } + + public bool AllowAudioStreamCopy { get; set; } + + public bool BreakOnNonKeyFrames { get; set; } + + /// + /// Gets or sets the audio sample rate. + /// + /// The audio sample rate. + public int? AudioSampleRate { get; set; } + + public int? MaxAudioBitDepth { get; set; } + + /// + /// Gets or sets the audio bit rate. + /// + /// The audio bit rate. + public int? AudioBitRate { get; set; } + + /// + /// Gets or sets the audio channels. + /// + /// The audio channels. + public int? AudioChannels { get; set; } + + public int? MaxAudioChannels { get; set; } + + public bool Static { get; set; } + + /// + /// Gets or sets the profile. + /// + /// The profile. + public string Profile { get; set; } + + /// + /// Gets or sets the level. + /// + /// The level. + public string Level { get; set; } + + /// + /// Gets or sets the framerate. + /// + /// The framerate. + public float? Framerate { get; set; } + + public float? MaxFramerate { get; set; } + + public bool CopyTimestamps { get; set; } + + /// + /// Gets or sets the start time ticks. + /// + /// The start time ticks. + public long? StartTimeTicks { 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 video bit rate. + /// + /// The video bit rate. + public int? VideoBitRate { get; set; } + + /// + /// Gets or sets the index of the subtitle stream. + /// + /// The index of the subtitle stream. + public int? SubtitleStreamIndex { get; set; } + + public SubtitleDeliveryMethod SubtitleMethod { get; set; } + + public int? MaxRefFrames { get; set; } + + public int? MaxVideoBitDepth { get; set; } + + public bool RequireAvc { get; set; } + + public bool DeInterlace { get; set; } + + public bool RequireNonAnamorphic { get; set; } + + public int? TranscodingMaxAudioChannels { get; set; } + + public int? CpuCoreLimit { get; set; } + + public string LiveStreamId { get; set; } + + public bool EnableMpegtsM2TsMode { get; set; } + + /// + /// Gets or sets the video codec. + /// + /// The video codec. + public string VideoCodec { get; set; } + + public string SubtitleCodec { get; set; } + + public string TranscodeReasons { get; set; } + + /// + /// Gets or sets the index of the audio stream. + /// + /// The index of the audio stream. + public int? AudioStreamIndex { get; set; } + + /// + /// Gets or sets the index of the video stream. + /// + /// The index of the video stream. + public int? VideoStreamIndex { get; set; } + + public EncodingContext Context { get; set; } + + public Dictionary StreamOptions { get; set; } + + public string GetOption(string qualifier, string name) + { + var value = GetOption(qualifier + "-" + name); + + if (string.IsNullOrEmpty(value)) + { + value = GetOption(name); + } + + return value; + } + + public string GetOption(string name) + { + if (StreamOptions.TryGetValue(name, out var value)) + { + return value; + } + + return null; + } + + public BaseEncodingJobOptions() + { + EnableAutoStreamCopy = true; + AllowVideoStreamCopy = true; + AllowAudioStreamCopy = true; + Context = EncodingContext.Streaming; + StreamOptions = new Dictionary(StringComparer.OrdinalIgnoreCase); + } + } +} \ No newline at end of file diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index feb5883e5..26b0bc3de 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -1166,7 +1166,9 @@ namespace MediaBrowser.Controller.MediaEncoding profileScore = Math.Min(profileScore, 2); // http://www.webmproject.org/docs/encoder-parameters/ - param += string.Format(CultureInfo.InvariantCulture, " -speed 16 -quality good -profile:v {0} -slices 8 -crf {1} -qmin {2} -qmax {3}", + param += string.Format( + CultureInfo.InvariantCulture, + " -speed 16 -quality good -profile:v {0} -slices 8 -crf {1} -qmin {2} -qmax {3}", profileScore.ToString(_usCulture), crf, qmin, @@ -1296,7 +1298,7 @@ namespace MediaBrowser.Controller.MediaEncoding // hevc_qsv use -level 51 instead of -level 153. if (double.TryParse(level, NumberStyles.Any, _usCulture, out double hevcLevel)) { - param += " -level " + hevcLevel / 3; + param += " -level " + (hevcLevel / 3); } } else if (string.Equals(videoEncoder, "h264_amf", StringComparison.OrdinalIgnoreCase) @@ -1392,7 +1394,7 @@ namespace MediaBrowser.Controller.MediaEncoding var requestedProfile = requestedProfiles[0]; // strip spaces because they may be stripped out on the query string as well if (!string.IsNullOrEmpty(videoStream.Profile) - && !requestedProfiles.Contains(videoStream.Profile.Replace(" ", "", StringComparison.Ordinal), StringComparer.OrdinalIgnoreCase)) + && !requestedProfiles.Contains(videoStream.Profile.Replace(" ", string.Empty, StringComparison.Ordinal), StringComparer.OrdinalIgnoreCase)) { var currentScore = GetVideoProfileScore(videoStream.Profile); var requestedScore = GetVideoProfileScore(requestedProfile); @@ -1801,7 +1803,7 @@ namespace MediaBrowser.Controller.MediaEncoding if (isTranscodingAudio && state.TranscodingType != TranscodingJobType.Progressive && resultChannels.HasValue - && (resultChannels.Value > 2 && resultChannels.Value < 6 || resultChannels.Value == 7)) + && ((resultChannels.Value > 2 && resultChannels.Value < 6) || resultChannels.Value == 7)) { resultChannels = 2; } @@ -2129,8 +2131,8 @@ namespace MediaBrowser.Controller.MediaEncoding return (null, null); } - decimal inputWidth = Convert.ToDecimal(videoWidth ?? requestedWidth); - decimal inputHeight = Convert.ToDecimal(videoHeight ?? requestedHeight); + decimal inputWidth = Convert.ToDecimal(videoWidth ?? requestedWidth, CultureInfo.InvariantCulture); + decimal inputHeight = Convert.ToDecimal(videoHeight ?? requestedHeight, CultureInfo.InvariantCulture); decimal outputWidth = requestedWidth.HasValue ? Convert.ToDecimal(requestedWidth.Value) : inputWidth; decimal outputHeight = requestedHeight.HasValue ? Convert.ToDecimal(requestedHeight.Value) : inputHeight; decimal maximumWidth = requestedMaxWidth.HasValue ? Convert.ToDecimal(requestedMaxWidth.Value) : outputWidth; @@ -2197,12 +2199,11 @@ namespace MediaBrowser.Controller.MediaEncoding var isQsvHevcEncoder = videoEncoder.Contains("hevc_qsv", StringComparison.OrdinalIgnoreCase); var isTonemappingSupported = IsTonemappingSupported(state, options); var isVppTonemappingSupported = IsVppTonemappingSupported(state, options); - var isTonemappingSupportedOnVaapi = string.Equals(options.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase)&& isVaapiDecoder && (isVaapiH264Encoder || isVaapiHevcEncoder); + var isTonemappingSupportedOnVaapi = string.Equals(options.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase) && isVaapiDecoder && (isVaapiH264Encoder || isVaapiHevcEncoder); var isTonemappingSupportedOnQsv = string.Equals(options.HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase) && isVaapiDecoder && (isQsvH264Encoder || isQsvHevcEncoder); var isP010PixFmtRequired = (isTonemappingSupportedOnVaapi && (isTonemappingSupported || isVppTonemappingSupported)) || (isTonemappingSupportedOnQsv && isVppTonemappingSupported); - var outputPixFmt = "format=nv12"; if (isP010PixFmtRequired) { @@ -3175,8 +3176,8 @@ namespace MediaBrowser.Controller.MediaEncoding state.ReadInputAtNativeFramerate = mediaSource.ReadAtNativeFramerate; if (state.ReadInputAtNativeFramerate - || mediaSource.Protocol == MediaProtocol.File - && string.Equals(mediaSource.Container, "wtv", StringComparison.OrdinalIgnoreCase)) + || (mediaSource.Protocol == MediaProtocol.File + && string.Equals(mediaSource.Container, "wtv", StringComparison.OrdinalIgnoreCase))) { state.InputVideoSync = "-1"; state.InputAudioSync = "1"; @@ -3549,7 +3550,7 @@ namespace MediaBrowser.Controller.MediaEncoding } /// - /// Gets a hw decoder name + /// Gets a hw decoder name. /// public string GetHwDecoderName(EncodingOptions options, string decoder, string videoCodec, bool isColorDepth10) { @@ -3567,7 +3568,7 @@ namespace MediaBrowser.Controller.MediaEncoding } /// - /// Gets a hwaccel type to use as a hardware decoder(dxva/vaapi) depending on the system + /// Gets a hwaccel type to use as a hardware decoder(dxva/vaapi) depending on the system. /// public string GetHwaccelType(EncodingJobInfo state, EncodingOptions options, string videoCodec, bool isColorDepth10) { @@ -3693,7 +3694,7 @@ namespace MediaBrowser.Controller.MediaEncoding if (flags.Count > 0) { - return " -fflags " + string.Join("", flags); + return " -fflags " + string.Join(string.Empty, flags); } return string.Empty; diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs b/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs index 30e2ac42f..bc0318ad7 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs @@ -69,6 +69,7 @@ namespace MediaBrowser.Controller.MediaEncoding } private TranscodeReason[] _transcodeReasons = null; + public TranscodeReason[] TranscodeReasons { get diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs b/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs deleted file mode 100644 index 61f3bc771..000000000 --- a/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs +++ /dev/null @@ -1,205 +0,0 @@ -#nullable disable - -#pragma warning disable CS1591 - -using System; -using System.Collections.Generic; -using MediaBrowser.Model.Dlna; - -namespace MediaBrowser.Controller.MediaEncoding -{ - // For now until api and media encoding layers are unified - public class BaseEncodingJobOptions - { - /// - /// Gets or sets the id. - /// - /// The id. - public Guid Id { get; set; } - - public string MediaSourceId { get; set; } - - public string DeviceId { get; set; } - - public string Container { get; set; } - - /// - /// Gets or sets the audio codec. - /// - /// The audio codec. - public string AudioCodec { get; set; } - - public bool EnableAutoStreamCopy { get; set; } - - public bool AllowVideoStreamCopy { get; set; } - - public bool AllowAudioStreamCopy { get; set; } - - public bool BreakOnNonKeyFrames { get; set; } - - /// - /// Gets or sets the audio sample rate. - /// - /// The audio sample rate. - public int? AudioSampleRate { get; set; } - - public int? MaxAudioBitDepth { get; set; } - - /// - /// Gets or sets the audio bit rate. - /// - /// The audio bit rate. - public int? AudioBitRate { get; set; } - - /// - /// Gets or sets the audio channels. - /// - /// The audio channels. - public int? AudioChannels { get; set; } - - public int? MaxAudioChannels { get; set; } - - public bool Static { get; set; } - - /// - /// Gets or sets the profile. - /// - /// The profile. - public string Profile { get; set; } - - /// - /// Gets or sets the level. - /// - /// The level. - public string Level { get; set; } - - /// - /// Gets or sets the framerate. - /// - /// The framerate. - public float? Framerate { get; set; } - - public float? MaxFramerate { get; set; } - - public bool CopyTimestamps { get; set; } - - /// - /// Gets or sets the start time ticks. - /// - /// The start time ticks. - public long? StartTimeTicks { 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 video bit rate. - /// - /// The video bit rate. - public int? VideoBitRate { get; set; } - - /// - /// Gets or sets the index of the subtitle stream. - /// - /// The index of the subtitle stream. - public int? SubtitleStreamIndex { get; set; } - - public SubtitleDeliveryMethod SubtitleMethod { get; set; } - - public int? MaxRefFrames { get; set; } - - public int? MaxVideoBitDepth { get; set; } - - public bool RequireAvc { get; set; } - - public bool DeInterlace { get; set; } - - public bool RequireNonAnamorphic { get; set; } - - public int? TranscodingMaxAudioChannels { get; set; } - - public int? CpuCoreLimit { get; set; } - - public string LiveStreamId { get; set; } - - public bool EnableMpegtsM2TsMode { get; set; } - - /// - /// Gets or sets the video codec. - /// - /// The video codec. - public string VideoCodec { get; set; } - - public string SubtitleCodec { get; set; } - - public string TranscodeReasons { get; set; } - - /// - /// Gets or sets the index of the audio stream. - /// - /// The index of the audio stream. - public int? AudioStreamIndex { get; set; } - - /// - /// Gets or sets the index of the video stream. - /// - /// The index of the video stream. - public int? VideoStreamIndex { get; set; } - - public EncodingContext Context { get; set; } - - public Dictionary StreamOptions { get; set; } - - public string GetOption(string qualifier, string name) - { - var value = GetOption(qualifier + "-" + name); - - if (string.IsNullOrEmpty(value)) - { - value = GetOption(name); - } - - return value; - } - - public string GetOption(string name) - { - if (StreamOptions.TryGetValue(name, out var value)) - { - return value; - } - - return null; - } - - public BaseEncodingJobOptions() - { - EnableAutoStreamCopy = true; - AllowVideoStreamCopy = true; - AllowAudioStreamCopy = true; - Context = EncodingContext.Streaming; - StreamOptions = new Dictionary(StringComparer.OrdinalIgnoreCase); - } - } -} diff --git a/MediaBrowser.Controller/MediaEncoding/JobLogger.cs b/MediaBrowser.Controller/MediaEncoding/JobLogger.cs index aa5e2c403..b23c95112 100644 --- a/MediaBrowser.Controller/MediaEncoding/JobLogger.cs +++ b/MediaBrowser.Controller/MediaEncoding/JobLogger.cs @@ -6,6 +6,7 @@ using System; using System.Globalization; using System.IO; using System.Text; +using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Logging; diff --git a/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs b/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs index 855467e8e..d8995ce74 100644 --- a/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs +++ b/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs @@ -270,13 +270,4 @@ namespace MediaBrowser.Controller.Net GC.SuppressFinalize(this); } } - - public class WebSocketListenerState - { - public DateTime DateLastSendUtc { get; set; } - - public long InitialDelayMs { get; set; } - - public long IntervalMs { get; set; } - } } diff --git a/MediaBrowser.Controller/Net/IWebSocketConnection.cs b/MediaBrowser.Controller/Net/IWebSocketConnection.cs index e50cd9781..f1ba1ec72 100644 --- a/MediaBrowser.Controller/Net/IWebSocketConnection.cs +++ b/MediaBrowser.Controller/Net/IWebSocketConnection.cs @@ -60,11 +60,11 @@ namespace MediaBrowser.Controller.Net /// /// Sends a message asynchronously. /// - /// + /// The type of websocket message data. /// The message. /// The cancellation token. /// Task. - /// message + /// The message is null. Task SendAsync(WebSocketMessage message, CancellationToken cancellationToken); Task ProcessAsync(CancellationToken cancellationToken = default); diff --git a/MediaBrowser.Controller/Net/WebSocketListenerState.cs b/MediaBrowser.Controller/Net/WebSocketListenerState.cs new file mode 100644 index 000000000..70604d60a --- /dev/null +++ b/MediaBrowser.Controller/Net/WebSocketListenerState.cs @@ -0,0 +1,17 @@ +#nullable disable + +#pragma warning disable CS1591 + +using System; + +namespace MediaBrowser.Controller.Net +{ + public class WebSocketListenerState + { + public DateTime DateLastSendUtc { get; set; } + + public long InitialDelayMs { get; set; } + + public long IntervalMs { get; set; } + } +} \ No newline at end of file diff --git a/MediaBrowser.Controller/Persistence/IItemRepository.cs b/MediaBrowser.Controller/Persistence/IItemRepository.cs index 56fb36af2..0a9073e7f 100644 --- a/MediaBrowser.Controller/Persistence/IItemRepository.cs +++ b/MediaBrowser.Controller/Persistence/IItemRepository.cs @@ -49,21 +49,23 @@ namespace MediaBrowser.Controller.Persistence /// /// Gets chapters for an item. /// - /// - /// + /// The item. + /// The list of chapter info. List GetChapters(BaseItem id); /// /// Gets a single chapter for an item. /// - /// - /// - /// + /// The item. + /// The chapter index. + /// The chapter info at the specified index. ChapterInfo GetChapter(BaseItem id, int index); /// /// Saves the chapters. /// + /// The item id. + /// The list of chapters to save. void SaveChapters(Guid id, IReadOnlyList chapters); /// diff --git a/MediaBrowser.Controller/Persistence/IUserDataRepository.cs b/MediaBrowser.Controller/Persistence/IUserDataRepository.cs index 6f5f02123..5fa5834c8 100644 --- a/MediaBrowser.Controller/Persistence/IUserDataRepository.cs +++ b/MediaBrowser.Controller/Persistence/IUserDataRepository.cs @@ -40,17 +40,16 @@ namespace MediaBrowser.Controller.Persistence /// /// Return all user data associated with the given user. /// - /// - /// + /// The user id. + /// The list of user item data. List GetAllUserData(long userId); /// /// Save all user data associated with the given user. /// - /// - /// - /// - /// + /// The user id. + /// The user item data. + /// The cancellation token. void SaveAllUserData(long userId, UserItemData[] userData, CancellationToken cancellationToken); } } diff --git a/MediaBrowser.Controller/Playlists/Playlist.cs b/MediaBrowser.Controller/Playlists/Playlist.cs index bb9e5da1e..3eaf23515 100644 --- a/MediaBrowser.Controller/Playlists/Playlist.cs +++ b/MediaBrowser.Controller/Playlists/Playlist.cs @@ -101,7 +101,7 @@ namespace MediaBrowser.Controller.Playlists return new List(); } - protected override Task ValidateChildrenInternal(IProgress progress, CancellationToken cancellationToken, bool recursive, bool refreshChildMetadata, MetadataRefreshOptions refreshOptions, IDirectoryService directoryService) + protected override Task ValidateChildrenInternal(IProgress progress, bool recursive, bool refreshChildMetadata, MetadataRefreshOptions refreshOptions, IDirectoryService directoryService, CancellationToken cancellationToken) { return Task.CompletedTask; } diff --git a/MediaBrowser.Controller/Plugins/IRunBeforeStartup.cs b/MediaBrowser.Controller/Plugins/IRunBeforeStartup.cs index ea966c282..11985f475 100644 --- a/MediaBrowser.Controller/Plugins/IRunBeforeStartup.cs +++ b/MediaBrowser.Controller/Plugins/IRunBeforeStartup.cs @@ -1,4 +1,6 @@ -namespace MediaBrowser.Controller.Plugins +#pragma warning disable CA1040 // Avoid empty interfaces + +namespace MediaBrowser.Controller.Plugins { /// /// Indicates that a should be invoked as a pre-startup task. diff --git a/MediaBrowser.Controller/Providers/IForcedProvider.cs b/MediaBrowser.Controller/Providers/IForcedProvider.cs index 5ae4a56ef..c14c66291 100644 --- a/MediaBrowser.Controller/Providers/IForcedProvider.cs +++ b/MediaBrowser.Controller/Providers/IForcedProvider.cs @@ -1,3 +1,5 @@ +#pragma warning disable CA1040 // Avoid empty interfaces + namespace MediaBrowser.Controller.Providers { /// diff --git a/MediaBrowser.Controller/Resolvers/BaseItemResolver.cs b/MediaBrowser.Controller/Resolvers/BaseItemResolver.cs deleted file mode 100644 index e77593a03..000000000 --- a/MediaBrowser.Controller/Resolvers/BaseItemResolver.cs +++ /dev/null @@ -1,57 +0,0 @@ -#nullable disable - -using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Library; - -namespace MediaBrowser.Controller.Resolvers -{ - /// - /// Class ItemResolver. - /// - /// - public abstract class ItemResolver : IItemResolver - where T : BaseItem, new() - { - /// - /// Gets the priority. - /// - /// The priority. - public virtual ResolverPriority Priority => ResolverPriority.First; - - /// - /// Resolves the specified args. - /// - /// The args. - /// `0. - public virtual T Resolve(ItemResolveArgs args) - { - return null; - } - - /// - /// Sets initial values on the newly resolved item. - /// - /// The item. - /// The args. - protected virtual void SetInitialItemValues(T item, ItemResolveArgs args) - { - } - - /// - /// Resolves the path. - /// - /// The args. - /// BaseItem. - BaseItem IItemResolver.ResolvePath(ItemResolveArgs args) - { - var item = Resolve(args); - - if (item != null) - { - SetInitialItemValues(item, args); - } - - return item; - } - } -} diff --git a/MediaBrowser.Controller/Resolvers/ItemResolver.cs b/MediaBrowser.Controller/Resolvers/ItemResolver.cs new file mode 100644 index 000000000..7fd54fcc6 --- /dev/null +++ b/MediaBrowser.Controller/Resolvers/ItemResolver.cs @@ -0,0 +1,57 @@ +#nullable disable + +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Library; + +namespace MediaBrowser.Controller.Resolvers +{ + /// + /// Class ItemResolver. + /// + /// The type of BaseItem. + public abstract class ItemResolver : IItemResolver + where T : BaseItem, new() + { + /// + /// Gets the priority. + /// + /// The priority. + public virtual ResolverPriority Priority => ResolverPriority.First; + + /// + /// Resolves the specified args. + /// + /// The args. + /// `0. + public virtual T Resolve(ItemResolveArgs args) + { + return null; + } + + /// + /// Sets initial values on the newly resolved item. + /// + /// The item. + /// The args. + protected virtual void SetInitialItemValues(T item, ItemResolveArgs args) + { + } + + /// + /// Resolves the path. + /// + /// The args. + /// BaseItem. + BaseItem IItemResolver.ResolvePath(ItemResolveArgs args) + { + var item = Resolve(args); + + if (item != null) + { + SetInitialItemValues(item, args); + } + + return item; + } + } +} diff --git a/MediaBrowser.Controller/Sorting/AlphanumComparator.cs b/MediaBrowser.Controller/Sorting/AlphanumComparator.cs index 4d9b98889..e00cadca2 100644 --- a/MediaBrowser.Controller/Sorting/AlphanumComparator.cs +++ b/MediaBrowser.Controller/Sorting/AlphanumComparator.cs @@ -121,7 +121,9 @@ namespace MediaBrowser.Controller.Sorting return result; } } +#pragma warning disable SA1500 // TODO remove with StyleCop.Analyzers v1.2.0 https://github.com/DotNetAnalyzers/StyleCopAnalyzers/pull/3196 } while (pos1 < len1 && pos2 < len2); +#pragma warning restore SA1500 return len1 - len2; } diff --git a/MediaBrowser.Providers/Manager/ProviderManager.cs b/MediaBrowser.Providers/Manager/ProviderManager.cs index dd497845d..2dfaa372c 100644 --- a/MediaBrowser.Providers/Manager/ProviderManager.cs +++ b/MediaBrowser.Providers/Manager/ProviderManager.cs @@ -1111,7 +1111,7 @@ namespace MediaBrowser.Providers.Manager await RefreshCollectionFolderChildren(options, collectionFolder, cancellationToken).ConfigureAwait(false); break; case Folder folder: - await folder.ValidateChildren(new SimpleProgress(), cancellationToken, options).ConfigureAwait(false); + await folder.ValidateChildren(new SimpleProgress(), options, cancellationToken: cancellationToken).ConfigureAwait(false); break; } } @@ -1122,7 +1122,7 @@ namespace MediaBrowser.Providers.Manager { await child.RefreshMetadata(options, cancellationToken).ConfigureAwait(false); - await child.ValidateChildren(new SimpleProgress(), cancellationToken, options).ConfigureAwait(false); + await child.ValidateChildren(new SimpleProgress(), options, cancellationToken: cancellationToken).ConfigureAwait(false); } } @@ -1144,7 +1144,7 @@ namespace MediaBrowser.Providers.Manager .Select(i => i.MusicArtist) .Where(i => i != null); - var musicArtistRefreshTasks = musicArtists.Select(i => i.ValidateChildren(new SimpleProgress(), cancellationToken, options, true)); + var musicArtistRefreshTasks = musicArtists.Select(i => i.ValidateChildren(new SimpleProgress(), options, true, cancellationToken)); await Task.WhenAll(musicArtistRefreshTasks).ConfigureAwait(false); -- cgit v1.2.3 From 65f8d8c0cd6cf64cebcbc0cc9279d9857ebf343c Mon Sep 17 00:00:00 2001 From: Cody Robibero Date: Sat, 10 Jul 2021 10:09:02 -0600 Subject: [CA1801] Parameter is never used. Remove the parameter or use it in the method body. --- .../Collections/CollectionManager.cs | 2 +- .../Playlists/PlaylistManager.cs | 2 +- Jellyfin.Api/Controllers/DynamicHlsController.cs | 2 +- Jellyfin.Api/Controllers/VideoHlsController.cs | 2 +- MediaBrowser.Controller/Entities/Folder.cs | 15 +---------- .../Entities/UserViewBuilder.cs | 29 ++++++++++------------ MediaBrowser.Controller/LiveTv/LiveTvChannel.cs | 2 +- .../MediaEncoding/EncodingHelper.cs | 4 +-- MediaBrowser.Providers/TV/SeriesMetadataService.cs | 2 +- 9 files changed, 22 insertions(+), 38 deletions(-) (limited to 'MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs') diff --git a/Emby.Server.Implementations/Collections/CollectionManager.cs b/Emby.Server.Implementations/Collections/CollectionManager.cs index 82d80fc83..4fc33e2ea 100644 --- a/Emby.Server.Implementations/Collections/CollectionManager.cs +++ b/Emby.Server.Implementations/Collections/CollectionManager.cs @@ -164,7 +164,7 @@ namespace Emby.Server.Implementations.Collections DateCreated = DateTime.UtcNow }; - parentFolder.AddChild(collection, CancellationToken.None); + parentFolder.AddChild(collection); if (options.ItemIdList.Count > 0) { diff --git a/Emby.Server.Implementations/Playlists/PlaylistManager.cs b/Emby.Server.Implementations/Playlists/PlaylistManager.cs index 9a1ca9946..8cafde38e 100644 --- a/Emby.Server.Implementations/Playlists/PlaylistManager.cs +++ b/Emby.Server.Implementations/Playlists/PlaylistManager.cs @@ -147,7 +147,7 @@ namespace Emby.Server.Implementations.Playlists playlist.SetMediaType(options.MediaType); - parentFolder.AddChild(playlist, CancellationToken.None); + parentFolder.AddChild(playlist); await playlist.RefreshMetadata(new MetadataRefreshOptions(new DirectoryService(_fileSystem)) { ForceSave = true }, CancellationToken.None) .ConfigureAwait(false); diff --git a/Jellyfin.Api/Controllers/DynamicHlsController.cs b/Jellyfin.Api/Controllers/DynamicHlsController.cs index 62283d038..fc1e4dced 100644 --- a/Jellyfin.Api/Controllers/DynamicHlsController.cs +++ b/Jellyfin.Api/Controllers/DynamicHlsController.cs @@ -1496,7 +1496,7 @@ namespace Jellyfin.Api.Controllers args += " -ar " + state.OutputAudioSampleRate.Value.ToString(CultureInfo.InvariantCulture); } - args += _encodingHelper.GetAudioFilterParam(state, _encodingOptions, true); + args += _encodingHelper.GetAudioFilterParam(state, _encodingOptions); return args; } diff --git a/Jellyfin.Api/Controllers/VideoHlsController.cs b/Jellyfin.Api/Controllers/VideoHlsController.cs index 6a720b1a4..4e7bb695a 100644 --- a/Jellyfin.Api/Controllers/VideoHlsController.cs +++ b/Jellyfin.Api/Controllers/VideoHlsController.cs @@ -485,7 +485,7 @@ namespace Jellyfin.Api.Controllers args += " -ar " + state.OutputAudioSampleRate.Value.ToString(CultureInfo.InvariantCulture); } - args += _encodingHelper.GetAudioFilterParam(state, _encodingOptions, true); + args += _encodingHelper.GetAudioFilterParam(state, _encodingOptions); return args; } diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index 541747422..6587eefab 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -206,9 +206,8 @@ namespace MediaBrowser.Controller.Entities /// Adds the child. /// /// The item. - /// The cancellation token. /// Unable to add + item.Name. - public void AddChild(BaseItem item, CancellationToken cancellationToken) + public void AddChild(BaseItem item) { item.SetParent(this); @@ -1385,18 +1384,6 @@ namespace MediaBrowser.Controller.Entities } } - /// - /// Gets allowed recursive children of an item. - /// - /// The user. - /// if set to true [include linked children]. - /// IEnumerable{BaseItem}. - /// - public IEnumerable GetRecursiveChildren(User user, bool includeLinkedChildren = true) - { - return GetRecursiveChildren(user, null); - } - public virtual IEnumerable GetRecursiveChildren(User user, InternalItemsQuery query) { if (user == null) diff --git a/MediaBrowser.Controller/Entities/UserViewBuilder.cs b/MediaBrowser.Controller/Entities/UserViewBuilder.cs index add734f62..266fda767 100644 --- a/MediaBrowser.Controller/Entities/UserViewBuilder.cs +++ b/MediaBrowser.Controller/Entities/UserViewBuilder.cs @@ -65,7 +65,7 @@ namespace MediaBrowser.Controller.Entities switch (viewType) { case CollectionType.Folders: - return GetResult(_libraryManager.GetUserRootFolder().GetChildren(user, true), queryParent, query); + return GetResult(_libraryManager.GetUserRootFolder().GetChildren(user, true), query); case CollectionType.TvShows: return GetTvView(queryParent, user, query); @@ -110,7 +110,7 @@ namespace MediaBrowser.Controller.Entities return GetMovieMovies(queryParent, user, query); case SpecialFolder.MovieCollections: - return GetMovieCollections(queryParent, user, query); + return GetMovieCollections(user, query); case SpecialFolder.TvFavoriteEpisodes: return GetFavoriteEpisodes(queryParent, user, query); @@ -122,7 +122,7 @@ namespace MediaBrowser.Controller.Entities { if (queryParent is UserView) { - return GetResult(GetMediaFolders(user).OfType().SelectMany(i => i.GetChildren(user, true)), queryParent, query); + return GetResult(GetMediaFolders(user).OfType().SelectMany(i => i.GetChildren(user, true)), query); } return queryParent.GetItems(query); @@ -160,7 +160,7 @@ namespace MediaBrowser.Controller.Entities GetUserView(SpecialFolder.MovieGenres, "Genres", "5", parent) }; - return GetResult(list, parent, query); + return GetResult(list, query); } private QueryResult GetFavoriteMovies(Folder parent, User user, InternalItemsQuery query) @@ -207,7 +207,7 @@ namespace MediaBrowser.Controller.Entities return _libraryManager.GetItemsResult(query); } - private QueryResult GetMovieCollections(Folder parent, User user, InternalItemsQuery query) + private QueryResult GetMovieCollections(User user, InternalItemsQuery query) { query.Parent = null; query.IncludeItemTypes = new[] { nameof(BoxSet) }; @@ -275,9 +275,9 @@ namespace MediaBrowser.Controller.Entities } }) .Where(i => i != null) - .Select(i => GetUserViewWithName(i.Name, SpecialFolder.MovieGenre, i.SortName, parent)); + .Select(i => GetUserViewWithName(SpecialFolder.MovieGenre, i.SortName, parent)); - return GetResult(genres, parent, query); + return GetResult(genres, query); } private QueryResult GetMovieGenreItems(Folder queryParent, Folder displayParent, User user, InternalItemsQuery query) @@ -323,7 +323,7 @@ namespace MediaBrowser.Controller.Entities GetUserView(SpecialFolder.TvGenres, "Genres", "6", parent) }; - return GetResult(list, parent, query); + return GetResult(list, query); } private QueryResult GetTvLatest(Folder parent, User user, InternalItemsQuery query) @@ -403,9 +403,9 @@ namespace MediaBrowser.Controller.Entities } }) .Where(i => i != null) - .Select(i => GetUserViewWithName(i.Name, SpecialFolder.TvGenre, i.SortName, parent)); + .Select(i => GetUserViewWithName(SpecialFolder.TvGenre, i.SortName, parent)); - return GetResult(genres, parent, query); + return GetResult(genres, query); } private QueryResult GetTvGenreItems(Folder queryParent, Folder displayParent, User user, InternalItemsQuery query) @@ -432,13 +432,12 @@ namespace MediaBrowser.Controller.Entities private QueryResult GetResult( IEnumerable items, - BaseItem queryParent, InternalItemsQuery query) where T : BaseItem { items = items.Where(i => Filter(i, query.User, query, _userDataManager, _libraryManager)); - return PostFilterAndSort(items, queryParent, null, query, _libraryManager, _config); + return PostFilterAndSort(items, null, query, _libraryManager); } public static bool FilterItem(BaseItem item, InternalItemsQuery query) @@ -448,11 +447,9 @@ namespace MediaBrowser.Controller.Entities public static QueryResult PostFilterAndSort( IEnumerable items, - BaseItem queryParent, int? totalRecordLimit, InternalItemsQuery query, - ILibraryManager libraryManager, - IServerConfigurationManager configurationManager) + ILibraryManager libraryManager) { var user = query.User; @@ -1001,7 +998,7 @@ namespace MediaBrowser.Controller.Entities return new BaseItem[] { parent }; } - private UserView GetUserViewWithName(string name, string type, string sortName, BaseItem parent) + private UserView GetUserViewWithName(string type, string sortName, BaseItem parent) { return _userViewManager.GetUserSubView(parent.Id, parent.Id.ToString("N", CultureInfo.InvariantCulture), type, sortName); } diff --git a/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs b/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs index 1a893fc2d..ecd3d10d9 100644 --- a/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs +++ b/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs @@ -82,7 +82,7 @@ namespace MediaBrowser.Controller.LiveTv return "TvChannel"; } - public IEnumerable GetTaggedItems(IEnumerable inputItems) + public IEnumerable GetTaggedItems() { return new List(); } diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 26b0bc3de..cb15fae5c 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -1692,7 +1692,7 @@ namespace MediaBrowser.Controller.MediaEncoding return 128000; } - public string GetAudioFilterParam(EncodingJobInfo state, EncodingOptions encodingOptions, bool isHls) + public string GetAudioFilterParam(EncodingJobInfo state, EncodingOptions encodingOptions) { var channels = state.OutputAudioChannels; @@ -3836,7 +3836,7 @@ namespace MediaBrowser.Controller.MediaEncoding args += " -ar " + state.OutputAudioSampleRate.Value.ToString(_usCulture); } - args += GetAudioFilterParam(state, encodingOptions, false); + args += GetAudioFilterParam(state, encodingOptions); return args; } diff --git a/MediaBrowser.Providers/TV/SeriesMetadataService.cs b/MediaBrowser.Providers/TV/SeriesMetadataService.cs index 967908197..dcb693408 100644 --- a/MediaBrowser.Providers/TV/SeriesMetadataService.cs +++ b/MediaBrowser.Providers/TV/SeriesMetadataService.cs @@ -187,7 +187,7 @@ namespace MediaBrowser.Providers.TV SeriesName = series.Name }; - series.AddChild(season, cancellationToken); + series.AddChild(season); await season.RefreshMetadata(new MetadataRefreshOptions(new DirectoryService(FileSystem)), cancellationToken).ConfigureAwait(false); -- cgit v1.2.3 From 8528e9bddb4c2dd9e1e3294649e39c7ec609bdf5 Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Mon, 12 Jul 2021 20:20:50 +0200 Subject: Improve platform checks --- Emby.Dlna/Main/DlnaEntryPoint.cs | 13 ++++++++----- Emby.Server.Implementations/ApplicationHost.cs | 17 +++++------------ Emby.Server.Implementations/IO/ManagedFileSystem.cs | 7 +++---- Jellyfin.Api/Controllers/DynamicHlsController.cs | 2 +- Jellyfin.Api/Controllers/VideoHlsController.cs | 3 +-- Jellyfin.Api/Helpers/HlsHelpers.cs | 3 +-- Jellyfin.Server/Program.cs | 8 ++++---- MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs | 17 ++++++++--------- .../IO/ManagedFileSystemTests.cs | 6 +++--- .../Location/MovieNfoLocationTests.cs | 8 ++++---- .../Parsers/MovieNfoParserTests.cs | 2 +- 11 files changed, 39 insertions(+), 47 deletions(-) (limited to 'MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs') diff --git a/Emby.Dlna/Main/DlnaEntryPoint.cs b/Emby.Dlna/Main/DlnaEntryPoint.cs index 0309926ab..5d252d8dc 100644 --- a/Emby.Dlna/Main/DlnaEntryPoint.cs +++ b/Emby.Dlna/Main/DlnaEntryPoint.cs @@ -27,11 +27,9 @@ using MediaBrowser.Controller.TV; using MediaBrowser.Model.Dlna; using MediaBrowser.Model.Globalization; using MediaBrowser.Model.Net; -using MediaBrowser.Model.System; using Microsoft.Extensions.Logging; using Rssdp; using Rssdp.Infrastructure; -using OperatingSystem = MediaBrowser.Common.System.OperatingSystem; namespace Emby.Dlna.Main { @@ -204,8 +202,8 @@ namespace Emby.Dlna.Main { if (_communicationsServer == null) { - var enableMultiSocketBinding = OperatingSystem.Id == OperatingSystemId.Windows || - OperatingSystem.Id == OperatingSystemId.Linux; + var enableMultiSocketBinding = OperatingSystem.IsWindows() || + OperatingSystem.IsLinux(); _communicationsServer = new SsdpCommunicationsServer(_socketFactory, _networkManager, _logger, enableMultiSocketBinding) { @@ -268,7 +266,12 @@ namespace Emby.Dlna.Main try { - _publisher = new SsdpDevicePublisher(_communicationsServer, _networkManager, OperatingSystem.Name, Environment.OSVersion.VersionString, _config.GetDlnaConfiguration().SendOnlyMatchedHost) + _publisher = new SsdpDevicePublisher( + _communicationsServer, + _networkManager, + MediaBrowser.Common.System.OperatingSystem.Name, + Environment.OSVersion.VersionString, + _config.GetDlnaConfiguration().SendOnlyMatchedHost) { LogFunction = LogMessage, SupportPnpRootDevice = false diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index 7ad7a2732..0523a3c52 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -103,7 +103,6 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Prometheus.DotNetRuntime; -using OperatingSystem = MediaBrowser.Common.System.OperatingSystem; using WebSocketManager = Emby.Server.Implementations.HttpServer.WebSocketManager; namespace Emby.Server.Implementations @@ -150,13 +149,7 @@ namespace Emby.Server.Implementations return false; } - if (OperatingSystem.Id == OperatingSystemId.Windows - || OperatingSystem.Id == OperatingSystemId.Darwin) - { - return true; - } - - return false; + return OperatingSystem.IsWindows() || OperatingSystem.IsMacOS(); } } @@ -721,7 +714,7 @@ namespace Emby.Server.Implementations logger.LogInformation("Environment Variables: {EnvVars}", relevantEnvVars); logger.LogInformation("Arguments: {Args}", commandLineArgs); - logger.LogInformation("Operating system: {OS}", OperatingSystem.Name); + logger.LogInformation("Operating system: {OS}", MediaBrowser.Common.System.OperatingSystem.Name); logger.LogInformation("Architecture: {Architecture}", RuntimeInformation.OSArchitecture); logger.LogInformation("64-Bit Process: {Is64Bit}", Environment.Is64BitProcess); logger.LogInformation("User Interactive: {IsUserInteractive}", Environment.UserInteractive); @@ -1098,8 +1091,8 @@ namespace Emby.Server.Implementations ItemsByNamePath = ApplicationPaths.InternalMetadataPath, InternalMetadataPath = ApplicationPaths.InternalMetadataPath, CachePath = ApplicationPaths.CachePath, - OperatingSystem = OperatingSystem.Id.ToString(), - OperatingSystemDisplayName = OperatingSystem.Name, + OperatingSystem = MediaBrowser.Common.System.OperatingSystem.Id.ToString(), + OperatingSystemDisplayName = MediaBrowser.Common.System.OperatingSystem.Name, CanSelfRestart = CanSelfRestart, CanLaunchWebBrowser = CanLaunchWebBrowser, TranscodingTempPath = ConfigurationManager.GetTranscodePath(), @@ -1124,7 +1117,7 @@ namespace Emby.Server.Implementations Version = ApplicationVersionString, ProductName = ApplicationProductName, Id = SystemId, - OperatingSystem = OperatingSystem.Id.ToString(), + OperatingSystem = MediaBrowser.Common.System.OperatingSystem.Id.ToString(), ServerName = FriendlyName, LocalAddress = GetSmartApiUrl(source), StartupWizardCompleted = ConfigurationManager.CommonConfiguration.IsStartupWizardCompleted diff --git a/Emby.Server.Implementations/IO/ManagedFileSystem.cs b/Emby.Server.Implementations/IO/ManagedFileSystem.cs index ca028a3ca..7c3c7da23 100644 --- a/Emby.Server.Implementations/IO/ManagedFileSystem.cs +++ b/Emby.Server.Implementations/IO/ManagedFileSystem.cs @@ -11,7 +11,6 @@ using MediaBrowser.Common.Configuration; using MediaBrowser.Model.IO; using MediaBrowser.Model.System; using Microsoft.Extensions.Logging; -using OperatingSystem = MediaBrowser.Common.System.OperatingSystem; namespace Emby.Server.Implementations.IO { @@ -24,7 +23,7 @@ namespace Emby.Server.Implementations.IO private readonly List _shortcutHandlers = new List(); private readonly string _tempPath; - private static readonly bool _isEnvironmentCaseInsensitive = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); + private static readonly bool _isEnvironmentCaseInsensitive = OperatingSystem.IsWindows(); public ManagedFileSystem( ILogger logger, @@ -402,7 +401,7 @@ namespace Emby.Server.Implementations.IO public virtual void SetHidden(string path, bool isHidden) { - if (OperatingSystem.Id != OperatingSystemId.Windows) + if (!OperatingSystem.IsWindows()) { return; } @@ -426,7 +425,7 @@ namespace Emby.Server.Implementations.IO public virtual void SetAttributes(string path, bool isHidden, bool isReadOnly) { - if (OperatingSystem.Id != OperatingSystemId.Windows) + if (!OperatingSystem.IsWindows()) { return; } diff --git a/Jellyfin.Api/Controllers/DynamicHlsController.cs b/Jellyfin.Api/Controllers/DynamicHlsController.cs index 62283d038..dcf262e32 100644 --- a/Jellyfin.Api/Controllers/DynamicHlsController.cs +++ b/Jellyfin.Api/Controllers/DynamicHlsController.cs @@ -1380,7 +1380,7 @@ namespace Jellyfin.Api.Controllers } else if (string.Equals(segmentFormat, "mp4", StringComparison.OrdinalIgnoreCase)) { - var outputFmp4HeaderArg = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) switch + var outputFmp4HeaderArg = OperatingSystem.IsWindows() switch { // on Windows, the path of fmp4 header file needs to be configured true => " -hls_fmp4_init_filename \"" + outputPrefix + "-1" + outputExtension + "\"", diff --git a/Jellyfin.Api/Controllers/VideoHlsController.cs b/Jellyfin.Api/Controllers/VideoHlsController.cs index 6a720b1a4..1e0329821 100644 --- a/Jellyfin.Api/Controllers/VideoHlsController.cs +++ b/Jellyfin.Api/Controllers/VideoHlsController.cs @@ -366,8 +366,7 @@ namespace Jellyfin.Api.Controllers else if (string.Equals(segmentFormat, "mp4", StringComparison.OrdinalIgnoreCase)) { var outputFmp4HeaderArg = string.Empty; - var isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); - if (isWindows) + if (OperatingSystem.IsWindows()) { // on Windows, the path of fmp4 header file needs to be configured outputFmp4HeaderArg = " -hls_fmp4_init_filename \"" + outputPrefix + "-1" + outputExtension + "\""; diff --git a/Jellyfin.Api/Helpers/HlsHelpers.cs b/Jellyfin.Api/Helpers/HlsHelpers.cs index d0666034e..d1cdaf867 100644 --- a/Jellyfin.Api/Helpers/HlsHelpers.cs +++ b/Jellyfin.Api/Helpers/HlsHelpers.cs @@ -99,8 +99,7 @@ namespace Jellyfin.Api.Helpers return fmp4InitFileName; } - var isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); - if (isWindows) + if (OperatingSystem.IsWindows()) { // on Windows // #EXT-X-MAP:URI="X:\transcodes\prefix-1.mp4" diff --git a/Jellyfin.Server/Program.cs b/Jellyfin.Server/Program.cs index 3a3d7415b..934372a94 100644 --- a/Jellyfin.Server/Program.cs +++ b/Jellyfin.Server/Program.cs @@ -318,8 +318,8 @@ namespace Jellyfin.Server } } - // Bind to unix socket (only on macOS and Linux) - if (startupConfig.UseUnixSocket() && !RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + // Bind to unix socket (only on unix systems) + if (startupConfig.UseUnixSocket() && Environment.OSVersion.Platform == PlatformID.Unix) { var socketPath = startupConfig.GetUnixSocketPath(); if (string.IsNullOrEmpty(socketPath)) @@ -404,7 +404,7 @@ namespace Jellyfin.Server { if (options.DataDir != null || Directory.Exists(Path.Combine(dataDir, "config")) - || RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + || OperatingSystem.IsWindows()) { // Hang config folder off already set dataDir configDir = Path.Combine(dataDir, "config"); @@ -442,7 +442,7 @@ namespace Jellyfin.Server if (string.IsNullOrEmpty(cacheDir)) { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + if (OperatingSystem.IsWindows()) { // Hang cache folder off already set dataDir cacheDir = Path.Combine(dataDir, "cache"); diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 26b0bc3de..160d9d691 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -143,8 +143,7 @@ namespace MediaBrowser.Controller.MediaEncoding } // Hybrid VPP tonemapping for QSV with VAAPI - var isLinux = RuntimeInformation.IsOSPlatform(OSPlatform.Linux); - if (isLinux && string.Equals(options.HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase)) + if (OperatingSystem.IsLinux() && string.Equals(options.HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase)) { // Limited to HEVC for now since the filter doesn't accept master data from VP9. return IsColorDepth10(state) @@ -503,9 +502,9 @@ namespace MediaBrowser.Controller.MediaEncoding var isQsvEncoder = outputVideoCodec.IndexOf("qsv", StringComparison.OrdinalIgnoreCase) != -1; var isNvdecDecoder = videoDecoder.Contains("cuda", StringComparison.OrdinalIgnoreCase); var isCuvidHevcDecoder = videoDecoder.Contains("hevc_cuvid", StringComparison.OrdinalIgnoreCase); - var isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); - var isLinux = RuntimeInformation.IsOSPlatform(OSPlatform.Linux); - var isMacOS = RuntimeInformation.IsOSPlatform(OSPlatform.OSX); + var isWindows = OperatingSystem.IsWindows(); + var isLinux = OperatingSystem.IsLinux(); + var isMacOS = OperatingSystem.IsMacOS(); var isTonemappingSupported = IsTonemappingSupported(state, encodingOptions); var isVppTonemappingSupported = IsVppTonemappingSupported(state, encodingOptions); @@ -1983,7 +1982,7 @@ namespace MediaBrowser.Controller.MediaEncoding var videoSizeParam = string.Empty; var videoDecoder = GetHardwareAcceleratedVideoDecoder(state, options) ?? string.Empty; - var isLinux = RuntimeInformation.IsOSPlatform(OSPlatform.Linux); + var isLinux = OperatingSystem.IsLinux(); var isVaapiDecoder = videoDecoder.IndexOf("vaapi", StringComparison.OrdinalIgnoreCase) != -1; var isVaapiH264Encoder = outputVideoCodec.IndexOf("h264_vaapi", StringComparison.OrdinalIgnoreCase) != -1; @@ -2528,7 +2527,7 @@ namespace MediaBrowser.Controller.MediaEncoding var isCuvidHevcDecoder = videoDecoder.Contains("hevc_cuvid", StringComparison.OrdinalIgnoreCase); var isLibX264Encoder = outputVideoCodec.IndexOf("libx264", StringComparison.OrdinalIgnoreCase) != -1; var isLibX265Encoder = outputVideoCodec.IndexOf("libx265", StringComparison.OrdinalIgnoreCase) != -1; - var isLinux = RuntimeInformation.IsOSPlatform(OSPlatform.Linux); + var isLinux = OperatingSystem.IsLinux(); var isColorDepth10 = IsColorDepth10(state); var isTonemappingSupported = IsTonemappingSupported(state, options); var isVppTonemappingSupported = IsVppTonemappingSupported(state, options); @@ -3572,8 +3571,8 @@ namespace MediaBrowser.Controller.MediaEncoding /// public string GetHwaccelType(EncodingJobInfo state, EncodingOptions options, string videoCodec, bool isColorDepth10) { - var isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); - var isLinux = RuntimeInformation.IsOSPlatform(OSPlatform.Linux); + var isWindows = OperatingSystem.IsWindows(); + var isLinux = OperatingSystem.IsLinux(); var isWindows8orLater = Environment.OSVersion.Version.Major > 6 || (Environment.OSVersion.Version.Major == 6 && Environment.OSVersion.Version.Minor > 1); var isDxvaSupported = _mediaEncoder.SupportsHwaccel("dxva2") || _mediaEncoder.SupportsHwaccel("d3d11va"); var isCodecAvailable = options.HardwareDecodingCodecs.Contains(videoCodec, StringComparer.OrdinalIgnoreCase); diff --git a/tests/Jellyfin.Server.Implementations.Tests/IO/ManagedFileSystemTests.cs b/tests/Jellyfin.Server.Implementations.Tests/IO/ManagedFileSystemTests.cs index 30e6542f9..d991f5574 100644 --- a/tests/Jellyfin.Server.Implementations.Tests/IO/ManagedFileSystemTests.cs +++ b/tests/Jellyfin.Server.Implementations.Tests/IO/ManagedFileSystemTests.cs @@ -1,10 +1,10 @@ +using System; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Runtime.InteropServices; using AutoFixture; using AutoFixture.AutoMoq; using Emby.Server.Implementations.IO; -using MediaBrowser.Model.System; using Xunit; namespace Jellyfin.Server.Implementations.Tests.IO @@ -31,7 +31,7 @@ namespace Jellyfin.Server.Implementations.Tests.IO { var generatedPath = _sut.MakeAbsolutePath(folderPath, filePath); - if (MediaBrowser.Common.System.OperatingSystem.Id == OperatingSystemId.Windows) + if (OperatingSystem.IsWindows()) { var expectedWindowsPath = expectedAbsolutePath.Replace('/', '\\'); Assert.Equal(expectedWindowsPath, generatedPath.Split(':')[1]); @@ -55,7 +55,7 @@ namespace Jellyfin.Server.Implementations.Tests.IO [SkippableFact] public void GetFileInfo_DanglingSymlink_ExistsFalse() { - Skip.If(RuntimeInformation.IsOSPlatform(OSPlatform.Windows)); + Skip.If(OperatingSystem.IsWindows()); string testFileDir = Path.Combine(Path.GetTempPath(), "jellyfin-test-data"); string testFileName = Path.Combine(testFileDir, Path.GetRandomFileName() + "-danglingsym.link"); diff --git a/tests/Jellyfin.XbmcMetadata.Tests/Location/MovieNfoLocationTests.cs b/tests/Jellyfin.XbmcMetadata.Tests/Location/MovieNfoLocationTests.cs index 357d61c0b..8019e0ab3 100644 --- a/tests/Jellyfin.XbmcMetadata.Tests/Location/MovieNfoLocationTests.cs +++ b/tests/Jellyfin.XbmcMetadata.Tests/Location/MovieNfoLocationTests.cs @@ -1,8 +1,8 @@ -using System.Linq; +using System; +using System.Linq; using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; -using MediaBrowser.Model.System; using MediaBrowser.XbmcMetadata.Savers; using Xunit; @@ -28,7 +28,7 @@ namespace Jellyfin.XbmcMetadata.Tests.Location var path2 = "/media/movies/Avengers Endgame/movie.nfo"; // uses ContainingFolderPath which uses Operating system specific paths - if (MediaBrowser.Common.System.OperatingSystem.Id == OperatingSystemId.Windows) + if (OperatingSystem.IsWindows()) { movie.Path = movie.Path.Replace('/', '\\'); path1 = path1.Replace('/', '\\'); @@ -49,7 +49,7 @@ namespace Jellyfin.XbmcMetadata.Tests.Location var path2 = "/media/movies/Avengers Endgame/VIDEO_TS/VIDEO_TS.nfo"; // uses ContainingFolderPath which uses Operating system specific paths - if (MediaBrowser.Common.System.OperatingSystem.Id == OperatingSystemId.Windows) + if (OperatingSystem.IsWindows()) { movie.Path = movie.Path.Replace('/', '\\'); path1 = path1.Replace('/', '\\'); diff --git a/tests/Jellyfin.XbmcMetadata.Tests/Parsers/MovieNfoParserTests.cs b/tests/Jellyfin.XbmcMetadata.Tests/Parsers/MovieNfoParserTests.cs index 30a48857a..cbcce73eb 100644 --- a/tests/Jellyfin.XbmcMetadata.Tests/Parsers/MovieNfoParserTests.cs +++ b/tests/Jellyfin.XbmcMetadata.Tests/Parsers/MovieNfoParserTests.cs @@ -59,7 +59,7 @@ namespace Jellyfin.XbmcMetadata.Tests.Parsers _localImageFileMetadata = new FileSystemMetadata() { Exists = true, - FullName = MediaBrowser.Common.System.OperatingSystem.Id == OperatingSystemId.Windows ? + FullName = OperatingSystem.IsWindows() ? "C:\\media\\movies\\Justice League (2017).jpg" : "/media/movies/Justice League (2017).jpg" }; -- cgit v1.2.3 From 3beda02d925c74c7a7083eaee733537f3396ec92 Mon Sep 17 00:00:00 2001 From: nyanmisaka Date: Sun, 25 Jul 2021 00:52:16 +0800 Subject: add support for cuda tonemap and overlay --- .../MediaEncoding/EncodingHelper.cs | 385 ++++++++++++++++----- .../MediaEncoding/FilterOptionType.cs | 23 ++ .../MediaEncoding/IMediaEncoder.cs | 14 +- .../Encoder/EncoderValidator.cs | 102 +++++- MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 39 ++- .../Probing/ProbeResultNormalizer.cs | 17 + 6 files changed, 477 insertions(+), 103 deletions(-) create mode 100644 MediaBrowser.Controller/MediaEncoding/FilterOptionType.cs (limited to 'MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs') diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 257cd5df6..b12cacb6f 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -40,6 +40,8 @@ namespace MediaBrowser.Controller.MediaEncoding "ConstrainedHigh" }; + private static readonly Version minVersionForCudaOverlay = new Version(4, 4); + public EncodingHelper( IMediaEncoder mediaEncoder, ISubtitleEncoder subtitleEncoder) @@ -109,17 +111,41 @@ namespace MediaBrowser.Controller.MediaEncoding private bool IsCudaSupported() { return _mediaEncoder.SupportsHwaccel("cuda") - && _mediaEncoder.SupportsFilter("scale_cuda", null) - && _mediaEncoder.SupportsFilter("yadif_cuda", null); + && _mediaEncoder.SupportsFilter("scale_cuda") + && _mediaEncoder.SupportsFilter("yadif_cuda") + && _mediaEncoder.SupportsFilter("hwupload_cuda"); } - private bool IsTonemappingSupported(EncodingJobInfo state, EncodingOptions options) + private bool IsOpenclTonemappingSupported(EncodingJobInfo state, EncodingOptions options) { var videoStream = state.VideoStream; - return IsColorDepth10(state) + if (videoStream == null) + { + return false; + } + + return (string.Equals(videoStream.ColorTransfer, "smpte2084", StringComparison.OrdinalIgnoreCase) + || string.Equals(videoStream.ColorTransfer, "arib-std-b67", StringComparison.OrdinalIgnoreCase)) + && IsColorDepth10(state) && _mediaEncoder.SupportsHwaccel("opencl") - && options.EnableTonemapping - && string.Equals(videoStream.VideoRange, "HDR", StringComparison.OrdinalIgnoreCase); + && _mediaEncoder.SupportsFilter("tonemap_opencl") + && options.EnableTonemapping; + } + + private bool IsCudaTonemappingSupported(EncodingJobInfo state, EncodingOptions options) + { + var videoStream = state.VideoStream; + if (videoStream == null) + { + return false; + } + + return (string.Equals(videoStream.ColorTransfer, "smpte2084", StringComparison.OrdinalIgnoreCase) + || string.Equals(videoStream.ColorTransfer, "arib-std-b67", StringComparison.OrdinalIgnoreCase)) + && IsColorDepth10(state) + && _mediaEncoder.SupportsHwaccel("cuda") + && _mediaEncoder.SupportsFilterWithOption(FilterOptionType.TonemapCudaName) + && options.EnableTonemapping; } private bool IsVppTonemappingSupported(EncodingJobInfo state, EncodingOptions options) @@ -135,23 +161,25 @@ namespace MediaBrowser.Controller.MediaEncoding if (string.Equals(options.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase)) { // Limited to HEVC for now since the filter doesn't accept master data from VP9. - return IsColorDepth10(state) + return string.Equals(videoStream.ColorTransfer, "smpte2084", StringComparison.OrdinalIgnoreCase) + && IsColorDepth10(state) && string.Equals(codec, "hevc", StringComparison.OrdinalIgnoreCase) && _mediaEncoder.SupportsHwaccel("vaapi") - && options.EnableVppTonemapping - && string.Equals(videoStream.ColorTransfer, "smpte2084", StringComparison.OrdinalIgnoreCase); + && _mediaEncoder.SupportsFilter("tonemap_vaapi") + && options.EnableVppTonemapping; } // Hybrid VPP tonemapping for QSV with VAAPI if (OperatingSystem.IsLinux() && string.Equals(options.HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase)) { // Limited to HEVC for now since the filter doesn't accept master data from VP9. - return IsColorDepth10(state) + return string.Equals(videoStream.ColorTransfer, "smpte2084", StringComparison.OrdinalIgnoreCase) + && IsColorDepth10(state) && string.Equals(codec, "hevc", StringComparison.OrdinalIgnoreCase) && _mediaEncoder.SupportsHwaccel("vaapi") + && _mediaEncoder.SupportsFilter("tonemap_vaapi") && _mediaEncoder.SupportsHwaccel("qsv") - && options.EnableVppTonemapping - && string.Equals(videoStream.ColorTransfer, "smpte2084", StringComparison.OrdinalIgnoreCase); + && options.EnableVppTonemapping; } // Native VPP tonemapping may come to QSV in the future. @@ -489,11 +517,14 @@ namespace MediaBrowser.Controller.MediaEncoding /// /// Gets the input argument. /// - public string GetInputArgument(EncodingJobInfo state, EncodingOptions encodingOptions) + public string GetInputArgument(EncodingJobInfo state, EncodingOptions options) { var arg = new StringBuilder(); - var videoDecoder = GetHardwareAcceleratedVideoDecoder(state, encodingOptions) ?? string.Empty; - var outputVideoCodec = GetVideoEncoder(state, encodingOptions) ?? string.Empty; + var videoDecoder = GetHardwareAcceleratedVideoDecoder(state, options) ?? string.Empty; + var outputVideoCodec = GetVideoEncoder(state, options) ?? string.Empty; + var isWindows = OperatingSystem.IsWindows(); + var isLinux = OperatingSystem.IsLinux(); + var isMacOS = OperatingSystem.IsMacOS(); var isSwDecoder = string.IsNullOrEmpty(videoDecoder); var isD3d11vaDecoder = videoDecoder.IndexOf("d3d11va", StringComparison.OrdinalIgnoreCase) != -1; var isVaapiDecoder = videoDecoder.IndexOf("vaapi", StringComparison.OrdinalIgnoreCase) != -1; @@ -502,26 +533,24 @@ namespace MediaBrowser.Controller.MediaEncoding var isQsvEncoder = outputVideoCodec.IndexOf("qsv", StringComparison.OrdinalIgnoreCase) != -1; var isNvdecDecoder = videoDecoder.Contains("cuda", StringComparison.OrdinalIgnoreCase); var isCuvidHevcDecoder = videoDecoder.Contains("hevc_cuvid", StringComparison.OrdinalIgnoreCase); - var isWindows = OperatingSystem.IsWindows(); - var isLinux = OperatingSystem.IsLinux(); - var isMacOS = OperatingSystem.IsMacOS(); - var isTonemappingSupported = IsTonemappingSupported(state, encodingOptions); - var isVppTonemappingSupported = IsVppTonemappingSupported(state, encodingOptions); + var isCuvidVp9Decoder = videoDecoder.Contains("vp9_cuvid", StringComparison.OrdinalIgnoreCase); + var isOpenclTonemappingSupported = IsOpenclTonemappingSupported(state, options); + var isVppTonemappingSupported = IsVppTonemappingSupported(state, options); + var isCudaTonemappingSupported = IsCudaTonemappingSupported(state, options); if (!IsCopyCodec(outputVideoCodec)) { if (state.IsVideoRequest && _mediaEncoder.SupportsHwaccel("vaapi") - && string.Equals(encodingOptions.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase)) + && string.Equals(options.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase)) { if (isVaapiDecoder) { - if (isTonemappingSupported && !isVppTonemappingSupported) + if (isOpenclTonemappingSupported && !isVppTonemappingSupported) { arg.Append("-init_hw_device vaapi=va:") - .Append(encodingOptions.VaapiDevice) - .Append(' ') - .Append("-init_hw_device opencl=ocl@va ") + .Append(options.VaapiDevice) + .Append(" -init_hw_device opencl=ocl@va ") .Append("-hwaccel_device va ") .Append("-hwaccel_output_format vaapi ") .Append("-filter_hw_device ocl "); @@ -530,14 +559,14 @@ namespace MediaBrowser.Controller.MediaEncoding { arg.Append("-hwaccel_output_format vaapi ") .Append("-vaapi_device ") - .Append(encodingOptions.VaapiDevice) + .Append(options.VaapiDevice) .Append(' '); } } else if (!isVaapiDecoder && isVaapiEncoder) { arg.Append("-vaapi_device ") - .Append(encodingOptions.VaapiDevice) + .Append(options.VaapiDevice) .Append(' '); } @@ -545,7 +574,7 @@ namespace MediaBrowser.Controller.MediaEncoding } if (state.IsVideoRequest - && string.Equals(encodingOptions.HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase)) + && string.Equals(options.HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase)) { var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode; @@ -581,9 +610,8 @@ namespace MediaBrowser.Controller.MediaEncoding else if (isVaapiDecoder && isVppTonemappingSupported) { arg.Append("-init_hw_device vaapi=va:") - .Append(encodingOptions.VaapiDevice) - .Append(' ') - .Append("-init_hw_device qsv@va ") + .Append(options.VaapiDevice) + .Append(" -init_hw_device qsv@va ") .Append("-hwaccel_output_format vaapi "); } @@ -592,7 +620,7 @@ namespace MediaBrowser.Controller.MediaEncoding } if (state.IsVideoRequest - && string.Equals(encodingOptions.HardwareAccelerationType, "nvenc", StringComparison.OrdinalIgnoreCase) + && string.Equals(options.HardwareAccelerationType, "nvenc", StringComparison.OrdinalIgnoreCase) && isNvdecDecoder) { // Fix for 'No decoder surfaces left' error. https://trac.ffmpeg.org/ticket/7562 @@ -600,22 +628,31 @@ namespace MediaBrowser.Controller.MediaEncoding } if (state.IsVideoRequest - && ((string.Equals(encodingOptions.HardwareAccelerationType, "nvenc", StringComparison.OrdinalIgnoreCase) - && (isNvdecDecoder || isCuvidHevcDecoder || isSwDecoder)) - || (string.Equals(encodingOptions.HardwareAccelerationType, "amf", StringComparison.OrdinalIgnoreCase) - && (isD3d11vaDecoder || isSwDecoder)))) + && ((string.Equals(options.HardwareAccelerationType, "nvenc", StringComparison.OrdinalIgnoreCase) + && (isNvdecDecoder || isCuvidHevcDecoder || isCuvidVp9Decoder || isSwDecoder)))) + { + if (!isCudaTonemappingSupported && isOpenclTonemappingSupported) + { + arg.Append("-init_hw_device opencl=ocl:") + .Append(options.OpenclDevice) + .Append(" -filter_hw_device ocl "); + } + } + + if (state.IsVideoRequest + && string.Equals(options.HardwareAccelerationType, "amf", StringComparison.OrdinalIgnoreCase) + && (isD3d11vaDecoder || isSwDecoder)) { - if (isTonemappingSupported) + if (isOpenclTonemappingSupported) { arg.Append("-init_hw_device opencl=ocl:") - .Append(encodingOptions.OpenclDevice) - .Append(' ') - .Append("-filter_hw_device ocl "); + .Append(options.OpenclDevice) + .Append(" -filter_hw_device ocl "); } } if (state.IsVideoRequest - && string.Equals(encodingOptions.HardwareAccelerationType, "videotoolbox", StringComparison.OrdinalIgnoreCase)) + && string.Equals(options.HardwareAccelerationType, "videotoolbox", StringComparison.OrdinalIgnoreCase)) { arg.Append("-hwaccel videotoolbox "); } @@ -1991,14 +2028,18 @@ namespace MediaBrowser.Controller.MediaEncoding var isQsvHevcEncoder = outputVideoCodec.Contains("hevc_qsv", StringComparison.OrdinalIgnoreCase); var isNvdecDecoder = videoDecoder.Contains("cuda", StringComparison.OrdinalIgnoreCase); var isNvencEncoder = outputVideoCodec.Contains("nvenc", StringComparison.OrdinalIgnoreCase); - var isTonemappingSupported = IsTonemappingSupported(state, options); - var isVppTonemappingSupported = IsVppTonemappingSupported(state, options); var isTonemappingSupportedOnVaapi = string.Equals(options.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase) && isVaapiDecoder && (isVaapiH264Encoder || isVaapiHevcEncoder); var isTonemappingSupportedOnQsv = string.Equals(options.HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase) && isVaapiDecoder && (isQsvH264Encoder || isQsvHevcEncoder); + var isOpenclTonemappingSupported = IsOpenclTonemappingSupported(state, options); + var isVppTonemappingSupported = IsVppTonemappingSupported(state, options); + + var mediaEncoderVersion = _mediaEncoder.GetMediaEncoderVersion(); + var isCudaOverlaySupported = _mediaEncoder.SupportsFilter("overlay_cuda") && mediaEncoderVersion != null && mediaEncoderVersion >= minVersionForCudaOverlay; + var isCudaFormatConversionSupported = _mediaEncoder.SupportsFilterWithOption(FilterOptionType.ScaleCudaFormat); // Tonemapping and burn-in graphical subtitles requires overlay_vaapi. // But it's still in ffmpeg mailing list. Disable it for now. - if (isTonemappingSupportedOnVaapi && isTonemappingSupported && !isVppTonemappingSupported) + if (isTonemappingSupportedOnVaapi && isOpenclTonemappingSupported && !isVppTonemappingSupported) { return GetOutputSizeParam(state, options, outputVideoCodec); } @@ -2024,13 +2065,22 @@ namespace MediaBrowser.Controller.MediaEncoding if (!string.IsNullOrEmpty(videoSizeParam) && !(isTonemappingSupportedOnQsv && isVppTonemappingSupported)) { - // For QSV, feed it into hardware encoder now + // upload graphical subtitle to QSV if (isLinux && (string.Equals(outputVideoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase) || string.Equals(outputVideoCodec, "hevc_qsv", StringComparison.OrdinalIgnoreCase))) { videoSizeParam += ",hwupload=extra_hw_frames=64"; } } + + if (!string.IsNullOrEmpty(videoSizeParam)) + { + // upload graphical subtitle to cuda + if (isNvdecDecoder && isNvencEncoder && isCudaOverlaySupported && isCudaFormatConversionSupported) + { + videoSizeParam += ",hwupload_cuda"; + } + } } var mapPrefix = state.SubtitleStream.IsExternal ? @@ -2043,9 +2093,9 @@ namespace MediaBrowser.Controller.MediaEncoding // Setup default filtergraph utilizing FFMpeg overlay() and FFMpeg scale() (see the return of this function for index reference) // Always put the scaler before the overlay for better performance - var retStr = !outputSizeParam.IsEmpty - ? " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}]{3}[base];[base][sub]overlay\"" - : " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}][sub]overlay\""; + var retStr = outputSizeParam.IsEmpty + ? " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}][sub]overlay\"" + : " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}]{3}[base];[base][sub]overlay\""; // When the input may or may not be hardware VAAPI decodable if (string.Equals(outputVideoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase) @@ -2056,9 +2106,9 @@ namespace MediaBrowser.Controller.MediaEncoding [sub]: SW scaling subtitle to FixedOutputSize [base][sub]: SW overlay */ - retStr = !outputSizeParam.IsEmpty - ? " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}]{3},hwdownload[base];[base][sub]overlay,format=nv12,hwupload\"" - : " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}]hwdownload[base];[base][sub]overlay,format=nv12,hwupload\""; + retStr = outputSizeParam.IsEmpty + ? " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}]hwdownload[base];[base][sub]overlay,format=nv12,hwupload\"" + : " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}]{3},hwdownload[base];[base][sub]overlay,format=nv12,hwupload\""; } // If we're hardware VAAPI decoding and software encoding, download frames from the decoder first @@ -2071,9 +2121,9 @@ namespace MediaBrowser.Controller.MediaEncoding [sub]: SW scaling subtitle to FixedOutputSize [base][sub]: SW overlay */ - retStr = !outputSizeParam.IsEmpty - ? " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}]{3}[base];[base][sub]overlay\"" - : " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}][sub]overlay\""; + retStr = outputSizeParam.IsEmpty + ? " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}][sub]overlay\"" + : " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}]{3}[base];[base][sub]overlay\""; } else if (string.Equals(outputVideoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase) || string.Equals(outputVideoCodec, "hevc_qsv", StringComparison.OrdinalIgnoreCase)) @@ -2090,16 +2140,25 @@ namespace MediaBrowser.Controller.MediaEncoding } else if (isLinux) { - retStr = !outputSizeParam.IsEmpty - ? " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}]{3}[base];[base][sub]overlay_qsv\"" - : " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}][sub]overlay_qsv\""; + retStr = outputSizeParam.IsEmpty + ? " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}][sub]overlay_qsv\"" + : " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}]{3}[base];[base][sub]overlay_qsv\""; } } else if (isNvdecDecoder && isNvencEncoder) { - retStr = !outputSizeParam.IsEmpty - ? " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}]{3}[base];[base][sub]overlay,format=nv12|yuv420p,hwupload_cuda\"" - : " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}][sub]overlay,format=nv12|yuv420p,hwupload_cuda\""; + if (isCudaOverlaySupported && isCudaFormatConversionSupported) + { + retStr = outputSizeParam.IsEmpty + ? " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}]scale_cuda=format=yuv420p[base];[base][sub]overlay_cuda\"" + : " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}]{3}[base];[base][sub]overlay_cuda\""; + } + else + { + retStr = !outputSizeParam.IsEmpty + ? " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}][sub]overlay,format=nv12|yuv420p,hwupload_cuda\"" + : " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}]{3}[base];[base][sub]overlay,format=nv12|yuv420p,hwupload_cuda\""; + } } return string.Format( @@ -2196,11 +2255,11 @@ namespace MediaBrowser.Controller.MediaEncoding var isVaapiHevcEncoder = videoEncoder.Contains("hevc_vaapi", StringComparison.OrdinalIgnoreCase); var isQsvH264Encoder = videoEncoder.Contains("h264_qsv", StringComparison.OrdinalIgnoreCase); var isQsvHevcEncoder = videoEncoder.Contains("hevc_qsv", StringComparison.OrdinalIgnoreCase); - var isTonemappingSupported = IsTonemappingSupported(state, options); + var isOpenclTonemappingSupported = IsOpenclTonemappingSupported(state, options); var isVppTonemappingSupported = IsVppTonemappingSupported(state, options); var isTonemappingSupportedOnVaapi = string.Equals(options.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase) && isVaapiDecoder && (isVaapiH264Encoder || isVaapiHevcEncoder); var isTonemappingSupportedOnQsv = string.Equals(options.HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase) && isVaapiDecoder && (isQsvH264Encoder || isQsvHevcEncoder); - var isP010PixFmtRequired = (isTonemappingSupportedOnVaapi && (isTonemappingSupported || isVppTonemappingSupported)) + var isP010PixFmtRequired = (isTonemappingSupportedOnVaapi && (isOpenclTonemappingSupported || isVppTonemappingSupported)) || (isTonemappingSupportedOnQsv && isVppTonemappingSupported); var outputPixFmt = "format=nv12"; @@ -2251,15 +2310,23 @@ namespace MediaBrowser.Controller.MediaEncoding var outputWidth = width.Value; var outputHeight = height.Value; - var isTonemappingSupported = IsTonemappingSupported(state, options); + var isNvencEncoder = videoEncoder.Contains("nvenc", StringComparison.OrdinalIgnoreCase); + var isOpenclTonemappingSupported = IsOpenclTonemappingSupported(state, options); + var isCudaTonemappingSupported = IsCudaTonemappingSupported(state, options); var isTonemappingSupportedOnNvenc = string.Equals(options.HardwareAccelerationType, "nvenc", StringComparison.OrdinalIgnoreCase); - var isCudaFormatConversionSupported = _mediaEncoder.SupportsFilter("scale_cuda", "Output format (default \"same\")"); + var mediaEncoderVersion = _mediaEncoder.GetMediaEncoderVersion(); + var isCudaOverlaySupported = _mediaEncoder.SupportsFilter("overlay_cuda") && mediaEncoderVersion != null && mediaEncoderVersion >= minVersionForCudaOverlay; + var isCudaFormatConversionSupported = _mediaEncoder.SupportsFilterWithOption(FilterOptionType.ScaleCudaFormat); + var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode; var outputPixFmt = string.Empty; if (isCudaFormatConversionSupported) { - outputPixFmt = "format=nv12"; - if (isTonemappingSupported && isTonemappingSupportedOnNvenc) + outputPixFmt = (hasGraphicalSubs && isCudaOverlaySupported && isNvencEncoder) + ? "format=yuv420p" + : "format=nv12"; + if ((isOpenclTonemappingSupported || isCudaTonemappingSupported) + && isTonemappingSupportedOnNvenc) { outputPixFmt = "format=p010"; } @@ -2525,16 +2592,21 @@ namespace MediaBrowser.Controller.MediaEncoding var isNvencEncoder = outputVideoCodec.Contains("nvenc", StringComparison.OrdinalIgnoreCase); var isCuvidH264Decoder = videoDecoder.Contains("h264_cuvid", StringComparison.OrdinalIgnoreCase); var isCuvidHevcDecoder = videoDecoder.Contains("hevc_cuvid", StringComparison.OrdinalIgnoreCase); + var isCuvidVp9Decoder = videoDecoder.Contains("vp9_cuvid", StringComparison.OrdinalIgnoreCase); var isLibX264Encoder = outputVideoCodec.IndexOf("libx264", StringComparison.OrdinalIgnoreCase) != -1; var isLibX265Encoder = outputVideoCodec.IndexOf("libx265", StringComparison.OrdinalIgnoreCase) != -1; var isLinux = OperatingSystem.IsLinux(); var isColorDepth10 = IsColorDepth10(state); - var isTonemappingSupported = IsTonemappingSupported(state, options); - var isVppTonemappingSupported = IsVppTonemappingSupported(state, options); - var isTonemappingSupportedOnNvenc = string.Equals(options.HardwareAccelerationType, "nvenc", StringComparison.OrdinalIgnoreCase) && (isNvdecDecoder || isCuvidHevcDecoder || isSwDecoder); + + var isTonemappingSupportedOnNvenc = string.Equals(options.HardwareAccelerationType, "nvenc", StringComparison.OrdinalIgnoreCase) && (isNvdecDecoder || isCuvidHevcDecoder || isCuvidVp9Decoder || isSwDecoder); var isTonemappingSupportedOnAmf = string.Equals(options.HardwareAccelerationType, "amf", StringComparison.OrdinalIgnoreCase) && (isD3d11vaDecoder || isSwDecoder); var isTonemappingSupportedOnVaapi = string.Equals(options.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase) && isVaapiDecoder && (isVaapiH264Encoder || isVaapiHevcEncoder); var isTonemappingSupportedOnQsv = string.Equals(options.HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase) && isVaapiDecoder && (isQsvH264Encoder || isQsvHevcEncoder); + var isOpenclTonemappingSupported = IsOpenclTonemappingSupported(state, options); + var isVppTonemappingSupported = IsVppTonemappingSupported(state, options); + var isCudaTonemappingSupported = IsCudaTonemappingSupported(state, options); + var mediaEncoderVersion = _mediaEncoder.GetMediaEncoderVersion(); + var isCudaOverlaySupported = _mediaEncoder.SupportsFilter("overlay_cuda") && mediaEncoderVersion != null && mediaEncoderVersion >= minVersionForCudaOverlay; var hasSubs = state.SubtitleStream != null && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode; var hasTextSubs = state.SubtitleStream != null && state.SubtitleStream.IsTextSubtitleStream && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode; @@ -2546,19 +2618,25 @@ namespace MediaBrowser.Controller.MediaEncoding var isScalingInAdvance = false; var isCudaDeintInAdvance = false; var isHwuploadCudaRequired = false; + var isNoTonemapFilterApplied = true; var isDeinterlaceH264 = state.DeInterlace("h264", true) || state.DeInterlace("avc", true); var isDeinterlaceHevc = state.DeInterlace("h265", true) || state.DeInterlace("hevc", true); // Add OpenCL tonemapping filter for NVENC/AMF/VAAPI. - if (isTonemappingSupportedOnNvenc || isTonemappingSupportedOnAmf || (isTonemappingSupportedOnVaapi && !isVppTonemappingSupported)) + if ((isTonemappingSupportedOnNvenc && !isCudaTonemappingSupported) || isTonemappingSupportedOnAmf || (isTonemappingSupportedOnVaapi && !isVppTonemappingSupported)) { - // Currently only with the use of NVENC decoder can we get a decent performance. - // Currently only the HEVC/H265 format is supported with NVDEC decoder. // NVIDIA Pascal and Turing or higher are recommended. // AMD Polaris and Vega or higher are recommended. // Intel Kaby Lake or newer is required. - if (isTonemappingSupported) + if (isOpenclTonemappingSupported) { + isNoTonemapFilterApplied = false; + var inputHdrParams = GetInputHdrParams(videoStream.ColorTransfer); + if (!string.IsNullOrEmpty(inputHdrParams)) + { + filters.Add(inputHdrParams); + } + var parameters = "tonemap_opencl=format=nv12:primaries=bt709:transfer=bt709:matrix=bt709:tonemap={0}:desat={1}:threshold={2}:peak={3}"; if (options.TonemappingParam != 0) @@ -2630,7 +2708,11 @@ namespace MediaBrowser.Controller.MediaEncoding filters.Add("hwdownload,format=p010"); } - if (isNvdecDecoder || isCuvidHevcDecoder || isSwDecoder || isD3d11vaDecoder) + if (isNvdecDecoder + || isCuvidHevcDecoder + || isCuvidVp9Decoder + || isSwDecoder + || isD3d11vaDecoder) { // Upload the HDR10 or HLG data to the OpenCL device, // use tonemap_opencl filter for tone mapping, @@ -2638,6 +2720,14 @@ namespace MediaBrowser.Controller.MediaEncoding filters.Add("hwupload"); } + // Fallback to hable if bt2390 is chosen but not supported in tonemap_opencl. + var isBt2390SupportedInOpenclTonemap = _mediaEncoder.SupportsFilterWithOption(FilterOptionType.TonemapOpenclBt2390); + if (string.Equals(options.TonemappingAlgorithm, "bt2390", StringComparison.OrdinalIgnoreCase) + && !isBt2390SupportedInOpenclTonemap) + { + options.TonemappingAlgorithm = "hable"; + } + filters.Add( string.Format( CultureInfo.InvariantCulture, @@ -2649,7 +2739,11 @@ namespace MediaBrowser.Controller.MediaEncoding options.TonemappingParam, options.TonemappingRange)); - if (isNvdecDecoder || isCuvidHevcDecoder || isSwDecoder || isD3d11vaDecoder) + if (isNvdecDecoder + || isCuvidHevcDecoder + || isCuvidVp9Decoder + || isSwDecoder + || isD3d11vaDecoder) { filters.Add("hwdownload"); filters.Add("format=nv12"); @@ -2665,12 +2759,18 @@ namespace MediaBrowser.Controller.MediaEncoding // Reverse the data route from opencl to vaapi. filters.Add("hwmap=derive_device=vaapi:reverse=1"); } + + var outputSdrParams = GetOutputSdrParams(options.TonemappingRange); + if (!string.IsNullOrEmpty(outputSdrParams)) + { + filters.Add(outputSdrParams); + } } } // When the input may or may not be hardware VAAPI decodable. if ((isVaapiH264Encoder || isVaapiHevcEncoder) - && !(isTonemappingSupportedOnVaapi && (isTonemappingSupported || isVppTonemappingSupported))) + && !(isTonemappingSupportedOnVaapi && (isOpenclTonemappingSupported || isVppTonemappingSupported))) { filters.Add("format=nv12|vaapi"); filters.Add("hwupload"); @@ -2778,6 +2878,61 @@ namespace MediaBrowser.Controller.MediaEncoding request.MaxHeight)); } + // Add Cuda tonemapping filter. + if (isNvdecDecoder && isCudaTonemappingSupported) + { + isNoTonemapFilterApplied = false; + var inputHdrParams = GetInputHdrParams(videoStream.ColorTransfer); + if (!string.IsNullOrEmpty(inputHdrParams)) + { + filters.Add(inputHdrParams); + } + + var parameters = (hasGraphicalSubs && isCudaOverlaySupported && isNvencEncoder) + ? "tonemap_cuda=format=yuv420p:primaries=bt709:transfer=bt709:matrix=bt709:tonemap={0}:peak={1}:desat={2}" + : "tonemap_cuda=format=nv12:primaries=bt709:transfer=bt709:matrix=bt709:tonemap={0}:peak={1}:desat={2}"; + + if (options.TonemappingParam != 0) + { + parameters += ":param={3}"; + } + + if (!string.Equals(options.TonemappingRange, "auto", StringComparison.OrdinalIgnoreCase)) + { + parameters += ":range={4}"; + } + + filters.Add( + string.Format( + CultureInfo.InvariantCulture, + parameters, + options.TonemappingAlgorithm, + options.TonemappingPeak, + options.TonemappingDesat, + options.TonemappingParam, + options.TonemappingRange)); + + if (isLibX264Encoder + || isLibX265Encoder + || hasTextSubs + || (hasGraphicalSubs && !isCudaOverlaySupported && isNvencEncoder)) + { + if (isNvencEncoder) + { + isHwuploadCudaRequired = true; + } + + filters.Add("hwdownload"); + filters.Add("format=nv12"); + } + + var outputSdrParams = GetOutputSdrParams(options.TonemappingRange); + if (!string.IsNullOrEmpty(outputSdrParams)) + { + filters.Add(outputSdrParams); + } + } + // Add VPP tonemapping filter for VAAPI. // Full hardware based video post processing, faster than OpenCL but lacks fine tuning options. if ((isTonemappingSupportedOnVaapi || isTonemappingSupportedOnQsv) @@ -2787,10 +2942,10 @@ namespace MediaBrowser.Controller.MediaEncoding } // Another case is when using Nvenc decoder. - if (isNvdecDecoder && !isTonemappingSupported) + if (isNvdecDecoder && !isOpenclTonemappingSupported && !isCudaTonemappingSupported) { var codec = videoStream.Codec; - var isCudaFormatConversionSupported = _mediaEncoder.SupportsFilter("scale_cuda", "Output format (default \"same\")"); + var isCudaFormatConversionSupported = _mediaEncoder.SupportsFilterWithOption(FilterOptionType.ScaleCudaFormat); // Assert 10-bit hardware decodable if (isColorDepth10 && (string.Equals(codec, "hevc", StringComparison.OrdinalIgnoreCase) @@ -2799,7 +2954,10 @@ namespace MediaBrowser.Controller.MediaEncoding { if (isCudaFormatConversionSupported) { - if (isLibX264Encoder || isLibX265Encoder || hasSubs) + if (isLibX264Encoder + || isLibX265Encoder + || hasTextSubs + || (hasGraphicalSubs && !isCudaOverlaySupported && isNvencEncoder)) { if (isNvencEncoder) { @@ -2826,7 +2984,11 @@ namespace MediaBrowser.Controller.MediaEncoding } // Assert 8-bit hardware decodable - else if (!isColorDepth10 && (isLibX264Encoder || isLibX265Encoder || hasSubs)) + else if (!isColorDepth10 + && (isLibX264Encoder + || isLibX265Encoder + || hasTextSubs + || (hasGraphicalSubs && !isCudaOverlaySupported && isNvencEncoder))) { if (isNvencEncoder) { @@ -2847,7 +3009,7 @@ namespace MediaBrowser.Controller.MediaEncoding { // Convert hw context from ocl to va. // For tonemapping and text subs burn-in. - if (isTonemappingSupportedOnVaapi && isTonemappingSupported && !isVppTonemappingSupported) + if (isTonemappingSupportedOnVaapi && isOpenclTonemappingSupported && !isVppTonemappingSupported) { filters.Add("scale_vaapi"); } @@ -2893,6 +3055,17 @@ namespace MediaBrowser.Controller.MediaEncoding filters.Add("hwupload_cuda"); } + // If no tonemap filter is applied, + // tag the video range as SDR to prevent the encoder from encoding HDR video. + if (isNoTonemapFilterApplied) + { + var outputSdrParams = GetOutputSdrParams(null); + if (!string.IsNullOrEmpty(outputSdrParams)) + { + filters.Add(outputSdrParams); + } + } + var output = string.Empty; if (filters.Count > 0) { @@ -2905,6 +3078,36 @@ namespace MediaBrowser.Controller.MediaEncoding return output; } + public static string GetInputHdrParams(string colorTransfer) + { + if (string.Equals(colorTransfer, "arib-std-b67", StringComparison.OrdinalIgnoreCase)) + { + // HLG + return "setparams=color_primaries=bt2020:color_trc=arib-std-b67:colorspace=bt2020nc"; + } + else + { + // HDR10 + return "setparams=color_primaries=bt2020:color_trc=smpte2084:colorspace=bt2020nc"; + } + } + + public static string GetOutputSdrParams(string tonemappingRange) + { + // SDR + if (string.Equals(tonemappingRange, "tv", StringComparison.OrdinalIgnoreCase)) + { + return "setparams=color_primaries=bt709:color_trc=bt709:colorspace=bt709:range=tv"; + } + + if (string.Equals(tonemappingRange, "pc", StringComparison.OrdinalIgnoreCase)) + { + return "setparams=color_primaries=bt709:color_trc=bt709:colorspace=bt709:range=pc"; + } + + return "setparams=color_primaries=bt709:color_trc=bt709:colorspace=bt709"; + } + /// /// Gets the number of threads. /// @@ -3371,8 +3574,13 @@ namespace MediaBrowser.Controller.MediaEncoding if (string.Equals(encodingOptions.HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase) && IsVppTonemappingSupported(state, encodingOptions)) { - // Since tonemap_vaapi only support HEVC for now, no need to check the codec again. - return GetHwaccelType(state, encodingOptions, "hevc", isColorDepth10); + var outputVideoCodec = GetVideoEncoder(state, encodingOptions) ?? string.Empty; + var isQsvEncoder = outputVideoCodec.IndexOf("qsv", StringComparison.OrdinalIgnoreCase) != -1; + if (isQsvEncoder) + { + // Since tonemap_vaapi only support HEVC for now, no need to check the codec again. + return GetHwaccelType(state, encodingOptions, "hevc", isColorDepth10); + } } if (string.Equals(encodingOptions.HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase)) @@ -3895,6 +4103,11 @@ namespace MediaBrowser.Controller.MediaEncoding if (videoStream != null) { + if (videoStream.BitDepth.HasValue) + { + return videoStream.BitDepth.Value == 10; + } + if (!string.IsNullOrEmpty(videoStream.PixelFormat)) { result = videoStream.PixelFormat.Contains("p10", StringComparison.OrdinalIgnoreCase); @@ -3914,12 +4127,6 @@ namespace MediaBrowser.Controller.MediaEncoding return true; } } - - result = (videoStream.BitDepth ?? 8) == 10; - if (result) - { - return true; - } } return result; diff --git a/MediaBrowser.Controller/MediaEncoding/FilterOptionType.cs b/MediaBrowser.Controller/MediaEncoding/FilterOptionType.cs new file mode 100644 index 000000000..7ce707b19 --- /dev/null +++ b/MediaBrowser.Controller/MediaEncoding/FilterOptionType.cs @@ -0,0 +1,23 @@ +namespace MediaBrowser.Controller.MediaEncoding +{ + /// + /// Enum FilterOptionType. + /// + public enum FilterOptionType + { + /// + /// The scale_cuda_format. + /// + ScaleCudaFormat = 0, + + /// + /// The tonemap_cuda_name. + /// + TonemapCudaName = 1, + + /// + /// The tonemap_opencl_bt2390. + /// + TonemapOpenclBt2390 = 2 + } +} diff --git a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs index 76a9fd7c7..31913acef 100644 --- a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs +++ b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs @@ -55,9 +55,21 @@ namespace MediaBrowser.Controller.MediaEncoding /// Whether given filter is supported. /// /// The filter. + /// true if the filter is supported, false otherwise. + bool SupportsFilter(string filter); + + /// + /// Whether filter is supported with the given option. + /// /// The option. /// true if the filter is supported, false otherwise. - bool SupportsFilter(string filter, string option); + bool SupportsFilterWithOption(FilterOptionType option); + + /// + /// Get the version of media encoder. + /// + /// The version of media encoder. + Version GetMediaEncoderVersion(); /// /// Extracts the audio image. diff --git a/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs b/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs index f782e65bd..1ec159c9a 100644 --- a/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs +++ b/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs @@ -89,6 +89,24 @@ namespace MediaBrowser.MediaEncoding.Encoder "hevc_videotoolbox" }; + private static readonly string[] _requiredFilters = new[] + { + "scale_cuda", + "yadif_cuda", + "hwupload_cuda", + "overlay_cuda", + "tonemap_cuda", + "tonemap_opencl", + "tonemap_vaapi", + }; + + private static readonly IReadOnlyDictionary _filterOptionsDict = new Dictionary + { + { 0, new string[] { "scale_cuda", "Output format (default \"same\")" } }, + { 1, new string[] { "tonemap_cuda", "GPU accelerated HDR to SDR tonemapping" } }, + { 2, new string[] { "tonemap_opencl", "bt2390" } } + }; + // These are the library versions that corresponds to our minimum ffmpeg version 4.x according to the version table below private static readonly IReadOnlyDictionary _ffmpegMinimumLibraryVersions = new Dictionary { @@ -156,7 +174,7 @@ namespace MediaBrowser.MediaEncoding.Encoder } // Work out what the version under test is - var version = GetFFmpegVersion(versionOutput); + var version = GetFFmpegVersionInternal(versionOutput); _logger.LogInformation("Found ffmpeg version {Version}", version != null ? version.ToString() : "unknown"); @@ -200,6 +218,34 @@ namespace MediaBrowser.MediaEncoding.Encoder public IEnumerable GetHwaccels() => GetHwaccelTypes(); + public IEnumerable GetFilters() => GetFFmpegFilters(); + + public IDictionary GetFiltersWithOption() => GetFFmpegFiltersWithOption(); + + public Version? GetFFmpegVersion() + { + string output; + try + { + output = GetProcessOutput(_encoderPath, "-version"); + } + catch (Exception ex) + { + _logger.LogError(ex, "Error validating encoder"); + return null; + } + + if (string.IsNullOrWhiteSpace(output)) + { + _logger.LogError("FFmpeg validation: The process returned no result"); + return null; + } + + _logger.LogDebug("ffmpeg output: {Output}", output); + + return GetFFmpegVersionInternal(output); + } + /// /// Using the output from "ffmpeg -version" work out the FFmpeg version. /// For pre-built binaries the first line should contain a string like "ffmpeg version x.y", which is easy @@ -208,7 +254,7 @@ namespace MediaBrowser.MediaEncoding.Encoder /// /// The output from "ffmpeg -version". /// The FFmpeg version. - internal Version? GetFFmpegVersion(string output) + internal Version? GetFFmpegVersionInternal(string output) { // For pre-built binaries the FFmpeg version should be mentioned at the very start of the output var match = Regex.Match(output, @"^ffmpeg version n?((?:[0-9]+\.?)+)"); @@ -297,9 +343,9 @@ namespace MediaBrowser.MediaEncoding.Encoder return found; } - public bool CheckFilter(string filter, string option) + public bool CheckFilterWithOption(string filter, string option) { - if (string.IsNullOrEmpty(filter)) + if (string.IsNullOrEmpty(filter) || string.IsNullOrEmpty(option)) { return false; } @@ -317,11 +363,6 @@ namespace MediaBrowser.MediaEncoding.Encoder if (output.Contains("Filter " + filter, StringComparison.Ordinal)) { - if (string.IsNullOrEmpty(option)) - { - return true; - } - return output.Contains(option, StringComparison.Ordinal); } @@ -362,6 +403,49 @@ namespace MediaBrowser.MediaEncoding.Encoder return found; } + private IEnumerable GetFFmpegFilters() + { + string output; + try + { + output = GetProcessOutput(_encoderPath, "-filters"); + } + catch (Exception ex) + { + _logger.LogError(ex, "Error detecting available filters"); + return Enumerable.Empty(); + } + + if (string.IsNullOrWhiteSpace(output)) + { + return Enumerable.Empty(); + } + + var found = Regex + .Matches(output, @"^\s\S{3}\s(?[\w|-]+)\s+.+$", RegexOptions.Multiline) + .Cast() + .Select(x => x.Groups["filter"].Value) + .Where(x => _requiredFilters.Contains(x)); + + _logger.LogInformation("Available filters: {Filters}", found); + + return found; + } + + private IDictionary GetFFmpegFiltersWithOption() + { + IDictionary dict = new Dictionary(); + for (int i = 0; i < _filterOptionsDict.Count; i++) + { + if (_filterOptionsDict.TryGetValue(i, out var val) && val.Length == 2) + { + dict.Add(i, CheckFilterWithOption(val[0], val[1])); + } + } + + return dict; + } + private string GetProcessOutput(string path, string arguments) { using (var process = new Process() diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index 412a95321..238627e96 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -66,7 +66,10 @@ namespace MediaBrowser.MediaEncoding.Encoder private List _encoders = new List(); private List _decoders = new List(); private List _hwaccels = new List(); + private List _filters = new List(); + private IDictionary _filtersWithOption = new Dictionary(); + private Version _ffmpegVersion = null; private string _ffmpegPath = string.Empty; private string _ffprobePath; private int threads; @@ -130,7 +133,11 @@ namespace MediaBrowser.MediaEncoding.Encoder SetAvailableDecoders(validator.GetDecoders()); SetAvailableEncoders(validator.GetEncoders()); + SetAvailableFilters(validator.GetFilters()); + SetAvailableFiltersWithOption(validator.GetFiltersWithOption()); SetAvailableHwaccels(validator.GetHwaccels()); + SetMediaEncoderVersion(validator); + threads = EncodingHelper.GetNumberOfThreads(null, _configurationManager.GetEncodingOptions(), null); } @@ -278,6 +285,21 @@ namespace MediaBrowser.MediaEncoding.Encoder _hwaccels = list.ToList(); } + public void SetAvailableFilters(IEnumerable list) + { + _filters = list.ToList(); + } + + public void SetAvailableFiltersWithOption(IDictionary dict) + { + _filtersWithOption = dict; + } + + public void SetMediaEncoderVersion(EncoderValidator validator) + { + _ffmpegVersion = validator.GetFFmpegVersion(); + } + public bool SupportsEncoder(string encoder) { return _encoders.Contains(encoder, StringComparer.OrdinalIgnoreCase); @@ -293,17 +315,26 @@ namespace MediaBrowser.MediaEncoding.Encoder return _hwaccels.Contains(hwaccel, StringComparer.OrdinalIgnoreCase); } - public bool SupportsFilter(string filter, string option) + public bool SupportsFilter(string filter) { - if (_ffmpegPath != null) + return _filters.Contains(filter, StringComparer.OrdinalIgnoreCase); + } + + public bool SupportsFilterWithOption(FilterOptionType option) + { + if (_filtersWithOption.TryGetValue((int)option, out var val)) { - var validator = new EncoderValidator(_logger, _ffmpegPath); - return validator.CheckFilter(filter, option); + return val; } return false; } + public Version GetMediaEncoderVersion() + { + return _ffmpegVersion; + } + public bool CanEncodeToAudioCodec(string codec) { if (string.Equals(codec, "opus", StringComparison.OrdinalIgnoreCase)) diff --git a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs index c9ad3c41e..d6799a170 100644 --- a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs +++ b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs @@ -739,6 +739,23 @@ namespace MediaBrowser.MediaEncoding.Probing stream.BitDepth = streamInfo.BitsPerRawSample; } + if (!stream.BitDepth.HasValue) + { + if (!string.IsNullOrEmpty(streamInfo.PixelFormat) + && streamInfo.PixelFormat.Contains("p10", StringComparison.OrdinalIgnoreCase)) + { + stream.BitDepth = 10; + } + + if (!string.IsNullOrEmpty(streamInfo.Profile) + && (streamInfo.Profile.Contains("Main 10", StringComparison.OrdinalIgnoreCase) + || streamInfo.Profile.Contains("High 10", StringComparison.OrdinalIgnoreCase) + || streamInfo.Profile.Contains("Profile 2", StringComparison.OrdinalIgnoreCase))) + { + stream.BitDepth = 10; + } + } + // stream.IsAnamorphic = string.Equals(streamInfo.sample_aspect_ratio, "0:1", StringComparison.OrdinalIgnoreCase) || // string.Equals(stream.AspectRatio, "2.35:1", StringComparison.OrdinalIgnoreCase) || // string.Equals(stream.AspectRatio, "2.40:1", StringComparison.OrdinalIgnoreCase); -- cgit v1.2.3 From 19e3c38fa8766e1dccb21d80224ae87cecf42df4 Mon Sep 17 00:00:00 2001 From: nyanmisaka Date: Mon, 26 Jul 2021 03:09:44 +0800 Subject: Apply suggestions from code review Co-authored-by: Claus Vium --- .../MediaEncoding/EncodingHelper.cs | 26 +++++++++++----------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs') diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index b12cacb6f..249c6f46e 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -124,12 +124,12 @@ namespace MediaBrowser.Controller.MediaEncoding return false; } - return (string.Equals(videoStream.ColorTransfer, "smpte2084", StringComparison.OrdinalIgnoreCase) + return options.EnableTonemapping + && (string.Equals(videoStream.ColorTransfer, "smpte2084", StringComparison.OrdinalIgnoreCase) || string.Equals(videoStream.ColorTransfer, "arib-std-b67", StringComparison.OrdinalIgnoreCase)) && IsColorDepth10(state) && _mediaEncoder.SupportsHwaccel("opencl") - && _mediaEncoder.SupportsFilter("tonemap_opencl") - && options.EnableTonemapping; + && _mediaEncoder.SupportsFilter("tonemap_opencl"); } private bool IsCudaTonemappingSupported(EncodingJobInfo state, EncodingOptions options) @@ -140,12 +140,12 @@ namespace MediaBrowser.Controller.MediaEncoding return false; } - return (string.Equals(videoStream.ColorTransfer, "smpte2084", StringComparison.OrdinalIgnoreCase) + return options.EnableTonemapping + && (string.Equals(videoStream.ColorTransfer, "smpte2084", StringComparison.OrdinalIgnoreCase) || string.Equals(videoStream.ColorTransfer, "arib-std-b67", StringComparison.OrdinalIgnoreCase)) && IsColorDepth10(state) && _mediaEncoder.SupportsHwaccel("cuda") - && _mediaEncoder.SupportsFilterWithOption(FilterOptionType.TonemapCudaName) - && options.EnableTonemapping; + && _mediaEncoder.SupportsFilterWithOption(FilterOptionType.TonemapCudaName); } private bool IsVppTonemappingSupported(EncodingJobInfo state, EncodingOptions options) @@ -161,25 +161,25 @@ namespace MediaBrowser.Controller.MediaEncoding if (string.Equals(options.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase)) { // Limited to HEVC for now since the filter doesn't accept master data from VP9. - return string.Equals(videoStream.ColorTransfer, "smpte2084", StringComparison.OrdinalIgnoreCase) + return options.EnableVppTonemapping + && string.Equals(videoStream.ColorTransfer, "smpte2084", StringComparison.OrdinalIgnoreCase) && IsColorDepth10(state) && string.Equals(codec, "hevc", StringComparison.OrdinalIgnoreCase) && _mediaEncoder.SupportsHwaccel("vaapi") - && _mediaEncoder.SupportsFilter("tonemap_vaapi") - && options.EnableVppTonemapping; + && _mediaEncoder.SupportsFilter("tonemap_vaapi"); } // Hybrid VPP tonemapping for QSV with VAAPI if (OperatingSystem.IsLinux() && string.Equals(options.HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase)) { // Limited to HEVC for now since the filter doesn't accept master data from VP9. - return string.Equals(videoStream.ColorTransfer, "smpte2084", StringComparison.OrdinalIgnoreCase) + return options.EnableVppTonemapping + && string.Equals(videoStream.ColorTransfer, "smpte2084", StringComparison.OrdinalIgnoreCase) && IsColorDepth10(state) && string.Equals(codec, "hevc", StringComparison.OrdinalIgnoreCase) && _mediaEncoder.SupportsHwaccel("vaapi") && _mediaEncoder.SupportsFilter("tonemap_vaapi") - && _mediaEncoder.SupportsHwaccel("qsv") - && options.EnableVppTonemapping; + && _mediaEncoder.SupportsHwaccel("qsv"); } // Native VPP tonemapping may come to QSV in the future. @@ -2155,7 +2155,7 @@ namespace MediaBrowser.Controller.MediaEncoding } else { - retStr = !outputSizeParam.IsEmpty + retStr = outputSizeParam.IsEmpty ? " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}][sub]overlay,format=nv12|yuv420p,hwupload_cuda\"" : " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}]{3}[base];[base][sub]overlay,format=nv12|yuv420p,hwupload_cuda\""; } -- cgit v1.2.3 From d4f09c6c9b142081064c4008bc1e84fb17c81ad8 Mon Sep 17 00:00:00 2001 From: Nyanmisaka Date: Wed, 4 Aug 2021 16:25:17 +0800 Subject: Apply suggestions from code review Co-authored-by: Claus Vium --- MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs') diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 249c6f46e..3f90de318 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -3575,7 +3575,7 @@ namespace MediaBrowser.Controller.MediaEncoding && IsVppTonemappingSupported(state, encodingOptions)) { var outputVideoCodec = GetVideoEncoder(state, encodingOptions) ?? string.Empty; - var isQsvEncoder = outputVideoCodec.IndexOf("qsv", StringComparison.OrdinalIgnoreCase) != -1; + var isQsvEncoder = outputVideoCodec.Contains("qsv", StringComparison.OrdinalIgnoreCase); if (isQsvEncoder) { // Since tonemap_vaapi only support HEVC for now, no need to check the codec again. -- cgit v1.2.3 From 32d27d71a833f35c313f1ae284e8a74aa06b1b6c Mon Sep 17 00:00:00 2001 From: Rich Lander Date: Tue, 10 Aug 2021 14:29:48 -0700 Subject: Fix warnings in MediaBrowser.Controller/MediaEncoding directory --- .../MediaEncoding/BaseEncodingJobOptions.cs | 18 +- .../MediaEncoding/EncodingHelper.cs | 50 ++- .../MediaEncoding/EncodingJobInfo.cs | 436 ++++++++++----------- .../MediaEncoding/IEncodingManager.cs | 7 + .../MediaEncoding/IMediaEncoder.cs | 43 ++ .../MediaEncoding/ISubtitleEncoder.cs | 8 + 6 files changed, 334 insertions(+), 228 deletions(-) (limited to 'MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs') diff --git a/MediaBrowser.Controller/MediaEncoding/BaseEncodingJobOptions.cs b/MediaBrowser.Controller/MediaEncoding/BaseEncodingJobOptions.cs index 745ee6bdb..dd6f468da 100644 --- a/MediaBrowser.Controller/MediaEncoding/BaseEncodingJobOptions.cs +++ b/MediaBrowser.Controller/MediaEncoding/BaseEncodingJobOptions.cs @@ -10,6 +10,15 @@ namespace MediaBrowser.Controller.MediaEncoding { public class BaseEncodingJobOptions { + public BaseEncodingJobOptions() + { + EnableAutoStreamCopy = true; + AllowVideoStreamCopy = true; + AllowAudioStreamCopy = true; + Context = EncodingContext.Streaming; + StreamOptions = new Dictionary(StringComparer.OrdinalIgnoreCase); + } + /// /// Gets or sets the id. /// @@ -191,14 +200,5 @@ namespace MediaBrowser.Controller.MediaEncoding return null; } - - public BaseEncodingJobOptions() - { - EnableAutoStreamCopy = true; - AllowVideoStreamCopy = true; - AllowAudioStreamCopy = true; - Context = EncodingContext.Streaming; - StreamOptions = new Dictionary(StringComparer.OrdinalIgnoreCase); - } } } \ No newline at end of file diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 257cd5df6..9bae95a27 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -161,6 +161,9 @@ namespace MediaBrowser.Controller.MediaEncoding /// /// Gets the name of the output video codec. /// + /// Encording state. + /// Encoding options. + /// Encoder string. public string GetVideoEncoder(EncodingJobInfo state, EncodingOptions encodingOptions) { var codec = state.OutputVideoCodec; @@ -315,6 +318,11 @@ namespace MediaBrowser.Controller.MediaEncoding return container; } + /// + /// Gets decoder from a codec. + /// + /// Codec to use. + /// Decoder string. public string GetDecoderFromCodec(string codec) { // For these need to find out the ffmpeg names @@ -344,6 +352,8 @@ namespace MediaBrowser.Controller.MediaEncoding /// /// Infers the audio codec based on the url. /// + /// Container to use. + /// Codec string. public string InferAudioCodec(string container) { var ext = "." + (container ?? string.Empty); @@ -489,6 +499,9 @@ namespace MediaBrowser.Controller.MediaEncoding /// /// Gets the input argument. /// + /// Encoding state. + /// Encoding options. + /// Input arguments. public string GetInputArgument(EncodingJobInfo state, EncodingOptions encodingOptions) { var arg = new StringBuilder(); @@ -965,6 +978,11 @@ namespace MediaBrowser.Controller.MediaEncoding /// /// Gets the video bitrate to specify on the command line. /// + /// Encoding state. + /// Video encoder to use. + /// Encoding options. + /// Default present to use for encoding. + /// Video bitrate. public string GetVideoQualityParam(EncodingJobInfo state, string videoEncoder, EncodingOptions encodingOptions, string defaultPreset) { var param = string.Empty; @@ -1966,8 +1984,12 @@ namespace MediaBrowser.Controller.MediaEncoding } /// - /// Gets the graphical subtitle param. + /// Gets the graphical subtitle parameter. /// + /// Encoding state. + /// Encoding options. + /// Video codec to use. + /// Graphical subtitle parameter. public string GetGraphicalSubtitleParam( EncodingJobInfo state, EncodingOptions options, @@ -2485,6 +2507,13 @@ namespace MediaBrowser.Controller.MediaEncoding return string.Format(CultureInfo.InvariantCulture, filter, widthParam, heightParam); } + /// + /// Gets the output size parameter. + /// + /// Encoding state. + /// Encoding options. + /// Video codec to use. + /// The output size parameter. public string GetOutputSizeParam( EncodingJobInfo state, EncodingOptions options, @@ -2495,8 +2524,13 @@ namespace MediaBrowser.Controller.MediaEncoding } /// + /// Gets the output size parameter. /// If we're going to put a fixed size on the command line, this will calculate it. /// + /// Encoding state. + /// Encoding options. + /// Video codec to use. + /// The output size parameter. public string GetOutputSizeParamInternal( EncodingJobInfo state, EncodingOptions options, @@ -2908,6 +2942,10 @@ namespace MediaBrowser.Controller.MediaEncoding /// /// Gets the number of threads. /// + /// Encoding state. + /// Encoding options. + /// Video codec to use. + /// Number of threads. #nullable enable public static int GetNumberOfThreads(EncodingJobInfo? state, EncodingOptions encodingOptions, string? outputVideoCodec) { @@ -3551,6 +3589,11 @@ namespace MediaBrowser.Controller.MediaEncoding /// /// Gets a hw decoder name. /// + /// Encoding options. + /// Decoder to use. + /// Video codec to use. + /// Specifies if color depth 10. + /// Hardware decoder name. public string GetHwDecoderName(EncodingOptions options, string decoder, string videoCodec, bool isColorDepth10) { var isCodecAvailable = _mediaEncoder.SupportsDecoder(decoder) && options.HardwareDecodingCodecs.Contains(videoCodec, StringComparer.OrdinalIgnoreCase); @@ -3569,6 +3612,11 @@ namespace MediaBrowser.Controller.MediaEncoding /// /// Gets a hwaccel type to use as a hardware decoder(dxva/vaapi) depending on the system. /// + /// Encoding state. + /// Encoding options. + /// Video codec to use. + /// Specifies if color depth 10. + /// Hardware accelerator type. public string GetHwaccelType(EncodingJobInfo state, EncodingOptions options, string videoCodec, bool isColorDepth10) { var isWindows = OperatingSystem.IsWindows(); diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs b/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs index bc0318ad7..fa9f40d60 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs @@ -1,6 +1,6 @@ #nullable disable -#pragma warning disable CS1591 +#pragma warning disable CS1591, SA1401 using System; using System.Collections.Generic; @@ -20,6 +20,44 @@ namespace MediaBrowser.Controller.MediaEncoding // For now, a common base class until the API and MediaEncoding classes are unified public class EncodingJobInfo { + public int? OutputAudioBitrate; + public int? OutputAudioChannels; + + private TranscodeReason[] _transcodeReasons = null; + + public EncodingJobInfo(TranscodingJobType jobType) + { + TranscodingType = jobType; + RemoteHttpHeaders = new Dictionary(StringComparer.OrdinalIgnoreCase); + SupportedAudioCodecs = Array.Empty(); + SupportedVideoCodecs = Array.Empty(); + SupportedSubtitleCodecs = Array.Empty(); + } + + public TranscodeReason[] TranscodeReasons + { + get + { + if (_transcodeReasons == null) + { + if (BaseRequest.TranscodeReasons == null) + { + return Array.Empty(); + } + + _transcodeReasons = BaseRequest.TranscodeReasons + .Split(',') + .Where(i => !string.IsNullOrEmpty(i)) + .Select(v => (TranscodeReason)Enum.Parse(typeof(TranscodeReason), v, true)) + .ToArray(); + } + + return _transcodeReasons; + } + } + + public IProgress Progress { get; set; } + public MediaStream VideoStream { get; set; } public VideoType VideoType { get; set; } @@ -58,40 +96,6 @@ namespace MediaBrowser.Controller.MediaEncoding public string MimeType { get; set; } - public string GetMimeType(string outputPath, bool enableStreamDefault = true) - { - if (!string.IsNullOrEmpty(MimeType)) - { - return MimeType; - } - - return MimeTypes.GetMimeType(outputPath, enableStreamDefault); - } - - private TranscodeReason[] _transcodeReasons = null; - - public TranscodeReason[] TranscodeReasons - { - get - { - if (_transcodeReasons == null) - { - if (BaseRequest.TranscodeReasons == null) - { - return Array.Empty(); - } - - _transcodeReasons = BaseRequest.TranscodeReasons - .Split(',') - .Where(i => !string.IsNullOrEmpty(i)) - .Select(v => (TranscodeReason)Enum.Parse(typeof(TranscodeReason), v, true)) - .ToArray(); - } - - return _transcodeReasons; - } - } - public bool IgnoreInputDts => MediaSource.IgnoreDts; public bool IgnoreInputIndex => MediaSource.IgnoreIndex; @@ -144,196 +148,17 @@ namespace MediaBrowser.Controller.MediaEncoding public BaseEncodingJobOptions BaseRequest { get; set; } - public long? StartTimeTicks => BaseRequest.StartTimeTicks; - - public bool CopyTimestamps => BaseRequest.CopyTimestamps; - - public int? OutputAudioBitrate; - public int? OutputAudioChannels; - - public bool DeInterlace(string videoCodec, bool forceDeinterlaceIfSourceIsInterlaced) - { - var videoStream = VideoStream; - var isInputInterlaced = videoStream != null && videoStream.IsInterlaced; - - if (!isInputInterlaced) - { - return false; - } - - // Support general param - if (BaseRequest.DeInterlace) - { - return true; - } - - if (!string.IsNullOrEmpty(videoCodec)) - { - if (string.Equals(BaseRequest.GetOption(videoCodec, "deinterlace"), "true", StringComparison.OrdinalIgnoreCase)) - { - return true; - } - } - - return forceDeinterlaceIfSourceIsInterlaced && isInputInterlaced; - } - - public string[] GetRequestedProfiles(string codec) - { - if (!string.IsNullOrEmpty(BaseRequest.Profile)) - { - return BaseRequest.Profile.Split(new[] { '|', ',' }, StringSplitOptions.RemoveEmptyEntries); - } - - if (!string.IsNullOrEmpty(codec)) - { - var profile = BaseRequest.GetOption(codec, "profile"); - - if (!string.IsNullOrEmpty(profile)) - { - return profile.Split(new[] { '|', ',' }, StringSplitOptions.RemoveEmptyEntries); - } - } - - return Array.Empty(); - } - - public string GetRequestedLevel(string codec) - { - if (!string.IsNullOrEmpty(BaseRequest.Level)) - { - return BaseRequest.Level; - } - - if (!string.IsNullOrEmpty(codec)) - { - return BaseRequest.GetOption(codec, "level"); - } - - return null; - } - - public int? GetRequestedMaxRefFrames(string codec) - { - if (BaseRequest.MaxRefFrames.HasValue) - { - return BaseRequest.MaxRefFrames; - } - - if (!string.IsNullOrEmpty(codec)) - { - var value = BaseRequest.GetOption(codec, "maxrefframes"); - if (!string.IsNullOrEmpty(value) - && int.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out var result)) - { - return result; - } - } - - return null; - } - - public int? GetRequestedVideoBitDepth(string codec) - { - if (BaseRequest.MaxVideoBitDepth.HasValue) - { - return BaseRequest.MaxVideoBitDepth; - } - - if (!string.IsNullOrEmpty(codec)) - { - var value = BaseRequest.GetOption(codec, "videobitdepth"); - if (!string.IsNullOrEmpty(value) - && int.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out var result)) - { - return result; - } - } - - return null; - } - - public int? GetRequestedAudioBitDepth(string codec) - { - if (BaseRequest.MaxAudioBitDepth.HasValue) - { - return BaseRequest.MaxAudioBitDepth; - } - - if (!string.IsNullOrEmpty(codec)) - { - var value = BaseRequest.GetOption(codec, "audiobitdepth"); - if (!string.IsNullOrEmpty(value) - && int.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out var result)) - { - return result; - } - } - - return null; - } - - public int? GetRequestedAudioChannels(string codec) - { - if (!string.IsNullOrEmpty(codec)) - { - var value = BaseRequest.GetOption(codec, "audiochannels"); - if (!string.IsNullOrEmpty(value) - && int.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out var result)) - { - return result; - } - } - - if (BaseRequest.MaxAudioChannels.HasValue) - { - return BaseRequest.MaxAudioChannels; - } - - if (BaseRequest.AudioChannels.HasValue) - { - return BaseRequest.AudioChannels; - } - - if (BaseRequest.TranscodingMaxAudioChannels.HasValue) - { - return BaseRequest.TranscodingMaxAudioChannels; - } - - return null; - } - public bool IsVideoRequest { get; set; } public TranscodingJobType TranscodingType { get; set; } - public EncodingJobInfo(TranscodingJobType jobType) - { - TranscodingType = jobType; - RemoteHttpHeaders = new Dictionary(StringComparer.OrdinalIgnoreCase); - SupportedAudioCodecs = Array.Empty(); - SupportedVideoCodecs = Array.Empty(); - SupportedSubtitleCodecs = Array.Empty(); - } + public long? StartTimeTicks => BaseRequest.StartTimeTicks; + + public bool CopyTimestamps => BaseRequest.CopyTimestamps; public bool IsSegmentedLiveStream => TranscodingType != TranscodingJobType.Progressive && !RunTimeTicks.HasValue; - public bool EnableBreakOnNonKeyFrames(string videoCodec) - { - if (TranscodingType != TranscodingJobType.Progressive) - { - if (IsSegmentedLiveStream) - { - return false; - } - - return BaseRequest.BreakOnNonKeyFrames && EncodingHelper.IsCopyCodec(videoCodec); - } - - return false; - } - public int? TotalOutputBitrate => (OutputAudioBitrate ?? 0) + (OutputVideoBitrate ?? 0); public int? OutputWidth @@ -682,6 +507,21 @@ namespace MediaBrowser.Controller.MediaEncoding public int HlsListSize => 0; + public bool EnableBreakOnNonKeyFrames(string videoCodec) + { + if (TranscodingType != TranscodingJobType.Progressive) + { + if (IsSegmentedLiveStream) + { + return false; + } + + return BaseRequest.BreakOnNonKeyFrames && EncodingHelper.IsCopyCodec(videoCodec); + } + + return false; + } + private int? GetMediaStreamCount(MediaStreamType type, int limit) { var count = MediaSource.GetStreamCount(type); @@ -694,7 +534,167 @@ namespace MediaBrowser.Controller.MediaEncoding return count; } - public IProgress Progress { get; set; } + public string GetMimeType(string outputPath, bool enableStreamDefault = true) + { + if (!string.IsNullOrEmpty(MimeType)) + { + return MimeType; + } + + return MimeTypes.GetMimeType(outputPath, enableStreamDefault); + } + + public bool DeInterlace(string videoCodec, bool forceDeinterlaceIfSourceIsInterlaced) + { + var videoStream = VideoStream; + var isInputInterlaced = videoStream != null && videoStream.IsInterlaced; + + if (!isInputInterlaced) + { + return false; + } + + // Support general param + if (BaseRequest.DeInterlace) + { + return true; + } + + if (!string.IsNullOrEmpty(videoCodec)) + { + if (string.Equals(BaseRequest.GetOption(videoCodec, "deinterlace"), "true", StringComparison.OrdinalIgnoreCase)) + { + return true; + } + } + + return forceDeinterlaceIfSourceIsInterlaced && isInputInterlaced; + } + + public string[] GetRequestedProfiles(string codec) + { + if (!string.IsNullOrEmpty(BaseRequest.Profile)) + { + return BaseRequest.Profile.Split(new[] { '|', ',' }, StringSplitOptions.RemoveEmptyEntries); + } + + if (!string.IsNullOrEmpty(codec)) + { + var profile = BaseRequest.GetOption(codec, "profile"); + + if (!string.IsNullOrEmpty(profile)) + { + return profile.Split(new[] { '|', ',' }, StringSplitOptions.RemoveEmptyEntries); + } + } + + return Array.Empty(); + } + + public string GetRequestedLevel(string codec) + { + if (!string.IsNullOrEmpty(BaseRequest.Level)) + { + return BaseRequest.Level; + } + + if (!string.IsNullOrEmpty(codec)) + { + return BaseRequest.GetOption(codec, "level"); + } + + return null; + } + + public int? GetRequestedMaxRefFrames(string codec) + { + if (BaseRequest.MaxRefFrames.HasValue) + { + return BaseRequest.MaxRefFrames; + } + + if (!string.IsNullOrEmpty(codec)) + { + var value = BaseRequest.GetOption(codec, "maxrefframes"); + if (!string.IsNullOrEmpty(value) + && int.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out var result)) + { + return result; + } + } + + return null; + } + + public int? GetRequestedVideoBitDepth(string codec) + { + if (BaseRequest.MaxVideoBitDepth.HasValue) + { + return BaseRequest.MaxVideoBitDepth; + } + + if (!string.IsNullOrEmpty(codec)) + { + var value = BaseRequest.GetOption(codec, "videobitdepth"); + if (!string.IsNullOrEmpty(value) + && int.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out var result)) + { + return result; + } + } + + return null; + } + + public int? GetRequestedAudioBitDepth(string codec) + { + if (BaseRequest.MaxAudioBitDepth.HasValue) + { + return BaseRequest.MaxAudioBitDepth; + } + + if (!string.IsNullOrEmpty(codec)) + { + var value = BaseRequest.GetOption(codec, "audiobitdepth"); + if (!string.IsNullOrEmpty(value) + && int.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out var result)) + { + return result; + } + } + + return null; + } + + public int? GetRequestedAudioChannels(string codec) + { + if (!string.IsNullOrEmpty(codec)) + { + var value = BaseRequest.GetOption(codec, "audiochannels"); + if (!string.IsNullOrEmpty(value) + && int.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out var result)) + { + return result; + } + } + + if (BaseRequest.MaxAudioChannels.HasValue) + { + return BaseRequest.MaxAudioChannels; + } + + if (BaseRequest.AudioChannels.HasValue) + { + return BaseRequest.AudioChannels; + } + + if (BaseRequest.TranscodingMaxAudioChannels.HasValue) + { + return BaseRequest.TranscodingMaxAudioChannels; + } + + return null; + } public virtual void ReportTranscodingProgress(TimeSpan? transcodingPosition, float? framerate, double? percentComplete, long? bytesTranscoded, int? bitRate) { diff --git a/MediaBrowser.Controller/MediaEncoding/IEncodingManager.cs b/MediaBrowser.Controller/MediaEncoding/IEncodingManager.cs index 773547872..8ce40a58d 100644 --- a/MediaBrowser.Controller/MediaEncoding/IEncodingManager.cs +++ b/MediaBrowser.Controller/MediaEncoding/IEncodingManager.cs @@ -16,6 +16,13 @@ namespace MediaBrowser.Controller.MediaEncoding /// /// Refreshes the chapter images. /// + /// Video to use. + /// Directory service to use. + /// Set of chapters to refresh. + /// Option to extract images. + /// Option to save chapters. + /// CancellationToken to use for operation. + /// true if successful, false if not. Task RefreshChapterImages(Video video, IDirectoryService directoryService, IReadOnlyList chapters, bool extractImages, bool saveChapters, CancellationToken cancellationToken); } } diff --git a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs index 76a9fd7c7..3aacf92cd 100644 --- a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs +++ b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs @@ -71,13 +71,42 @@ namespace MediaBrowser.Controller.MediaEncoding /// /// Extracts the video image. /// + /// Input file. + /// Video container type. + /// Media source information. + /// Media stream information. + /// Video 3D format. + /// Time offset. + /// CancellationToken to use for operation. + /// Location of video image. Task ExtractVideoImage(string inputFile, string container, MediaSourceInfo mediaSource, MediaStream videoStream, Video3DFormat? threedFormat, TimeSpan? offset, CancellationToken cancellationToken); + /// + /// Extracts the video image. + /// + /// Input file. + /// Video container type. + /// Media source information. + /// Media stream information. + /// Time offset. + /// CancellationToken to use for operation. + /// Location of video image. Task ExtractVideoImage(string inputFile, string container, MediaSourceInfo mediaSource, MediaStream imageStream, int? imageStreamIndex, CancellationToken cancellationToken); /// /// Extracts the video images on interval. /// + /// Input file. + /// Video container type. + /// Media stream information. + /// Media source information. + /// Video 3D format. + /// Time interval. + /// Directory to write images. + /// Filename prefix to use. + /// Maximum width of image. + /// CancellationToken to use for operation. + /// A task. Task ExtractVideoImagesOnInterval( string inputFile, string container, @@ -122,10 +151,24 @@ namespace MediaBrowser.Controller.MediaEncoding /// System.String. string EscapeSubtitleFilterPath(string path); + /// + /// Sets the path to find FFmpeg. + /// void SetFFmpegPath(); + /// + /// Updated the encoder path. + /// + /// The path. + /// The type of path. void UpdateEncoderPath(string path, string pathType); + /// + /// Gets the primary playlist of .vob files. + /// + /// The to the .vob files. + /// The title number to start with. + /// A playlist. IEnumerable GetPrimaryPlaylistVobFiles(string path, uint? titleNumber); } } diff --git a/MediaBrowser.Controller/MediaEncoding/ISubtitleEncoder.cs b/MediaBrowser.Controller/MediaEncoding/ISubtitleEncoder.cs index 3fb2c47e1..4483cf708 100644 --- a/MediaBrowser.Controller/MediaEncoding/ISubtitleEncoder.cs +++ b/MediaBrowser.Controller/MediaEncoding/ISubtitleEncoder.cs @@ -15,6 +15,14 @@ namespace MediaBrowser.Controller.MediaEncoding /// /// Gets the subtitles. /// + /// Item to use. + /// Media source. + /// Subtitle stream to use. + /// Output format to use. + /// Start time. + /// End time. + /// Option to preserve original timestamps. + /// The cancellation token for the operation. /// Task{Stream}. Task GetSubtitles( BaseItem item, -- cgit v1.2.3 From 19824bff94a9f557c3fb1616e1b5031fd125a53a Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Sun, 15 Aug 2021 17:20:07 +0200 Subject: Minor improvements --- .../Channels/ChannelManager.cs | 2 +- .../Collections/CollectionManager.cs | 32 +++---- .../Localization/LocalizationManager.cs | 63 ++++++------- MediaBrowser.Common/Plugins/BasePluginOfT.cs | 4 +- .../BaseItemManager/BaseItemManager.cs | 8 +- .../BaseItemManager/IBaseItemManager.cs | 4 +- .../Channels/ChannelItemResult.cs | 9 +- .../Collections/CollectionCreationOptions.cs | 2 +- .../Collections/CollectionModifiedEventArgs.cs | 2 - .../Collections/ICollectionManager.cs | 8 +- .../Configuration/IServerConfigurationManager.cs | 2 - .../MediaEncoding/EncodingHelper.cs | 3 - .../Globalization/ILocalizationManager.cs | 11 +-- MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs | 102 ++++++++++----------- .../Parsers/EpisodeNfoParser.cs | 92 +++++++++---------- .../Localization/LocalizationManagerTests.cs | 2 +- 16 files changed, 151 insertions(+), 195 deletions(-) (limited to 'MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs') diff --git a/Emby.Server.Implementations/Channels/ChannelManager.cs b/Emby.Server.Implementations/Channels/ChannelManager.cs index 093607dd5..aa54510a7 100644 --- a/Emby.Server.Implementations/Channels/ChannelManager.cs +++ b/Emby.Server.Implementations/Channels/ChannelManager.cs @@ -880,7 +880,7 @@ namespace Emby.Server.Implementations.Channels } } - private async Task CacheResponse(object result, string path) + private async Task CacheResponse(ChannelItemResult result, string path) { try { diff --git a/Emby.Server.Implementations/Collections/CollectionManager.cs b/Emby.Server.Implementations/Collections/CollectionManager.cs index 08acd1767..8270c2e84 100644 --- a/Emby.Server.Implementations/Collections/CollectionManager.cs +++ b/Emby.Server.Implementations/Collections/CollectionManager.cs @@ -1,5 +1,3 @@ -#nullable disable - using System; using System.Collections.Generic; using System.IO; @@ -63,13 +61,13 @@ namespace Emby.Server.Implementations.Collections } /// - public event EventHandler CollectionCreated; + public event EventHandler? CollectionCreated; /// - public event EventHandler ItemsAddedToCollection; + public event EventHandler? ItemsAddedToCollection; /// - public event EventHandler ItemsRemovedFromCollection; + public event EventHandler? ItemsRemovedFromCollection; private IEnumerable FindFolders(string path) { @@ -80,7 +78,7 @@ namespace Emby.Server.Implementations.Collections .Where(i => _fileSystem.AreEqual(path, i.Path) || _fileSystem.ContainsSubPath(i.Path, path)); } - internal async Task EnsureLibraryFolder(string path, bool createIfNeeded) + internal async Task EnsureLibraryFolder(string path, bool createIfNeeded) { var existingFolder = FindFolders(path).FirstOrDefault(); if (existingFolder != null) @@ -114,7 +112,7 @@ namespace Emby.Server.Implementations.Collections return Path.Combine(_appPaths.DataPath, "collections"); } - private Task GetCollectionsFolder(bool createIfNeeded) + private Task GetCollectionsFolder(bool createIfNeeded) { return EnsureLibraryFolder(GetCollectionsFolderPath(), createIfNeeded); } @@ -203,8 +201,7 @@ namespace Emby.Server.Implementations.Collections private async Task AddToCollectionAsync(Guid collectionId, IEnumerable ids, bool fireEvent, MetadataRefreshOptions refreshOptions) { - var collection = _libraryManager.GetItemById(collectionId) as BoxSet; - if (collection == null) + if (_libraryManager.GetItemById(collectionId) is not BoxSet collection) { throw new ArgumentException("No collection exists with the supplied Id"); } @@ -256,9 +253,7 @@ namespace Emby.Server.Implementations.Collections /// public async Task RemoveFromCollectionAsync(Guid collectionId, IEnumerable itemIds) { - var collection = _libraryManager.GetItemById(collectionId) as BoxSet; - - if (collection == null) + if (_libraryManager.GetItemById(collectionId) is not BoxSet collection) { throw new ArgumentException("No collection exists with the supplied Id"); } @@ -312,11 +307,7 @@ namespace Emby.Server.Implementations.Collections foreach (var item in items) { - if (item is not ISupportsBoxSetGrouping) - { - results[item.Id] = item; - } - else + if (item is ISupportsBoxSetGrouping) { var itemId = item.Id; @@ -340,6 +331,7 @@ namespace Emby.Server.Implementations.Collections } var alreadyInResults = false; + // this is kind of a performance hack because only Video has alternate versions that should be in a box set? if (item is Video video) { @@ -355,11 +347,13 @@ namespace Emby.Server.Implementations.Collections } } - if (!alreadyInResults) + if (alreadyInResults) { - results[itemId] = item; + continue; } } + + results[item.Id] = item; } return results.Values; diff --git a/Emby.Server.Implementations/Localization/LocalizationManager.cs b/Emby.Server.Implementations/Localization/LocalizationManager.cs index 9808e47de..03919197e 100644 --- a/Emby.Server.Implementations/Localization/LocalizationManager.cs +++ b/Emby.Server.Implementations/Localization/LocalizationManager.cs @@ -1,5 +1,3 @@ -#nullable disable - using System; using System.Collections.Concurrent; using System.Collections.Generic; @@ -38,10 +36,10 @@ namespace Emby.Server.Implementations.Localization private readonly ConcurrentDictionary> _dictionaries = new ConcurrentDictionary>(StringComparer.OrdinalIgnoreCase); - private List _cultures; - private readonly JsonSerializerOptions _jsonOptions = JsonDefaults.Options; + private List _cultures = new List(); + /// /// Initializes a new instance of the class. /// @@ -72,8 +70,8 @@ namespace Emby.Server.Implementations.Localization string countryCode = resource.Substring(RatingsPath.Length, 2); var dict = new Dictionary(StringComparer.OrdinalIgnoreCase); - await using var str = _assembly.GetManifestResourceStream(resource); - using var reader = new StreamReader(str); + await using var stream = _assembly.GetManifestResourceStream(resource); + using var reader = new StreamReader(stream!); // shouldn't be null here, we just got the resource path from Assembly.GetManifestResourceNames() await foreach (var line in reader.ReadAllLinesAsync().ConfigureAwait(false)) { if (string.IsNullOrWhiteSpace(line)) @@ -113,7 +111,8 @@ namespace Emby.Server.Implementations.Localization { List list = new List(); - await using var stream = _assembly.GetManifestResourceStream(CulturesPath); + await using var stream = _assembly.GetManifestResourceStream(CulturesPath) + ?? throw new InvalidOperationException($"Invalid resource path: '{CulturesPath}'"); using var reader = new StreamReader(stream); await foreach (var line in reader.ReadAllLinesAsync().ConfigureAwait(false)) { @@ -162,7 +161,7 @@ namespace Emby.Server.Implementations.Localization } /// - public CultureDto FindLanguageInfo(string language) + public CultureDto? FindLanguageInfo(string language) { // TODO language should ideally be a ReadOnlySpan but moq cannot mock ref structs for (var i = 0; i < _cultures.Count; i++) @@ -183,9 +182,10 @@ namespace Emby.Server.Implementations.Localization /// public IEnumerable GetCountries() { - using StreamReader reader = new StreamReader(_assembly.GetManifestResourceStream(CountriesPath)); - - return JsonSerializer.Deserialize>(reader.ReadToEnd(), _jsonOptions); + using StreamReader reader = new StreamReader( + _assembly.GetManifestResourceStream(CountriesPath) ?? throw new InvalidOperationException($"Invalid resource path: '{CountriesPath}'")); + return JsonSerializer.Deserialize>(reader.ReadToEnd(), _jsonOptions) + ?? throw new InvalidOperationException($"Resource contains invalid data: '{CountriesPath}'"); } /// @@ -205,7 +205,9 @@ namespace Emby.Server.Implementations.Localization countryCode = "us"; } - return GetRatings(countryCode) ?? GetRatings("us"); + return GetRatings(countryCode) + ?? GetRatings("us") + ?? throw new InvalidOperationException($"Invalid resource path: '{CountriesPath}'"); } /// @@ -213,7 +215,7 @@ namespace Emby.Server.Implementations.Localization /// /// The country code. /// The ratings. - private Dictionary GetRatings(string countryCode) + private Dictionary? GetRatings(string countryCode) { _allParentalRatings.TryGetValue(countryCode, out var value); @@ -238,7 +240,7 @@ namespace Emby.Server.Implementations.Localization var ratingsDictionary = GetParentalRatingsDictionary(); - if (ratingsDictionary.TryGetValue(rating, out ParentalRating value)) + if (ratingsDictionary.TryGetValue(rating, out ParentalRating? value)) { return value.Value; } @@ -268,20 +270,6 @@ namespace Emby.Server.Implementations.Localization return null; } - /// - public bool HasUnicodeCategory(string value, UnicodeCategory category) - { - foreach (var chr in value) - { - if (char.GetUnicodeCategory(chr) == category) - { - return true; - } - } - - return false; - } - /// public string GetLocalizedString(string phrase) { @@ -347,18 +335,21 @@ namespace Emby.Server.Implementations.Localization { await using var stream = _assembly.GetManifestResourceStream(resourcePath); // If a Culture doesn't have a translation the stream will be null and it defaults to en-us further up the chain - if (stream != null) + if (stream == null) { - var dict = await JsonSerializer.DeserializeAsync>(stream, _jsonOptions).ConfigureAwait(false); + _logger.LogError("Missing translation/culture resource: {ResourcePath}", resourcePath); + return; + } - foreach (var key in dict.Keys) - { - dictionary[key] = dict[key]; - } + var dict = await JsonSerializer.DeserializeAsync>(stream, _jsonOptions).ConfigureAwait(false); + if (dict == null) + { + throw new InvalidOperationException($"Resource contains invalid data: '{stream}'"); } - else + + foreach (var key in dict.Keys) { - _logger.LogError("Missing translation/culture resource: {ResourcePath}", resourcePath); + dictionary[key] = dict[key]; } } diff --git a/MediaBrowser.Common/Plugins/BasePluginOfT.cs b/MediaBrowser.Common/Plugins/BasePluginOfT.cs index 8a6d28e0f..afda83a7c 100644 --- a/MediaBrowser.Common/Plugins/BasePluginOfT.cs +++ b/MediaBrowser.Common/Plugins/BasePluginOfT.cs @@ -47,10 +47,10 @@ namespace MediaBrowser.Common.Plugins var assemblyFilePath = assembly.Location; var dataFolderPath = Path.Combine(ApplicationPaths.PluginsPath, Path.GetFileNameWithoutExtension(assemblyFilePath)); - if (!Directory.Exists(dataFolderPath) && Version != null) + if (Version != null && !Directory.Exists(dataFolderPath)) { // Try again with the version number appended to the folder name. - dataFolderPath = dataFolderPath + "_" + Version.ToString(); + dataFolderPath += "_" + Version.ToString(); } SetAttributes(assemblyFilePath, dataFolderPath, assemblyName.Version); diff --git a/MediaBrowser.Controller/BaseItemManager/BaseItemManager.cs b/MediaBrowser.Controller/BaseItemManager/BaseItemManager.cs index 97f40b537..abfdb41d8 100644 --- a/MediaBrowser.Controller/BaseItemManager/BaseItemManager.cs +++ b/MediaBrowser.Controller/BaseItemManager/BaseItemManager.cs @@ -1,6 +1,5 @@ -#nullable disable - using System; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Threading; using Jellyfin.Extensions; @@ -16,7 +15,7 @@ namespace MediaBrowser.Controller.BaseItemManager { private readonly IServerConfigurationManager _serverConfigurationManager; - private int _metadataRefreshConcurrency = 0; + private int _metadataRefreshConcurrency; /// /// Initializes a new instance of the class. @@ -101,7 +100,7 @@ namespace MediaBrowser.Controller.BaseItemManager /// Called when the configuration is updated. /// It will refresh the metadata throttler if the relevant config changed. /// - private void OnConfigurationUpdated(object sender, EventArgs e) + private void OnConfigurationUpdated(object? sender, EventArgs e) { int newMetadataRefreshConcurrency = GetMetadataRefreshConcurrency(); if (_metadataRefreshConcurrency != newMetadataRefreshConcurrency) @@ -114,6 +113,7 @@ namespace MediaBrowser.Controller.BaseItemManager /// /// Creates the metadata refresh throttler. /// + [MemberNotNull(nameof(MetadataRefreshThrottler))] private void SetupMetadataThrottler() { MetadataRefreshThrottler = new SemaphoreSlim(_metadataRefreshConcurrency); diff --git a/MediaBrowser.Controller/BaseItemManager/IBaseItemManager.cs b/MediaBrowser.Controller/BaseItemManager/IBaseItemManager.cs index b2b36c040..e18994214 100644 --- a/MediaBrowser.Controller/BaseItemManager/IBaseItemManager.cs +++ b/MediaBrowser.Controller/BaseItemManager/IBaseItemManager.cs @@ -1,5 +1,3 @@ -#nullable disable - using System.Threading; using MediaBrowser.Controller.Entities; using MediaBrowser.Model.Configuration; @@ -34,4 +32,4 @@ namespace MediaBrowser.Controller.BaseItemManager /// true if image fetcher is enabled, else false. bool IsImageFetcherEnabled(BaseItem baseItem, LibraryOptions libraryOptions, string name); } -} \ No newline at end of file +} diff --git a/MediaBrowser.Controller/Channels/ChannelItemResult.cs b/MediaBrowser.Controller/Channels/ChannelItemResult.cs index 7a0addd9f..ca7721991 100644 --- a/MediaBrowser.Controller/Channels/ChannelItemResult.cs +++ b/MediaBrowser.Controller/Channels/ChannelItemResult.cs @@ -1,7 +1,6 @@ -#nullable disable - -#pragma warning disable CA1002, CA2227, CS1591 +#pragma warning disable CS1591 +using System; using System.Collections.Generic; namespace MediaBrowser.Controller.Channels @@ -10,10 +9,10 @@ namespace MediaBrowser.Controller.Channels { public ChannelItemResult() { - Items = new List(); + Items = Array.Empty(); } - public List Items { get; set; } + public IReadOnlyList Items { get; set; } public int? TotalRecordCount { get; set; } } diff --git a/MediaBrowser.Controller/Collections/CollectionCreationOptions.cs b/MediaBrowser.Controller/Collections/CollectionCreationOptions.cs index 76ad335c5..30f5f4efa 100644 --- a/MediaBrowser.Controller/Collections/CollectionCreationOptions.cs +++ b/MediaBrowser.Controller/Collections/CollectionCreationOptions.cs @@ -1,6 +1,6 @@ #nullable disable -#pragma warning disable CA2227, CS1591 +#pragma warning disable CS1591 using System; using System.Collections.Generic; diff --git a/MediaBrowser.Controller/Collections/CollectionModifiedEventArgs.cs b/MediaBrowser.Controller/Collections/CollectionModifiedEventArgs.cs index 8155cf3db..e538fa4b3 100644 --- a/MediaBrowser.Controller/Collections/CollectionModifiedEventArgs.cs +++ b/MediaBrowser.Controller/Collections/CollectionModifiedEventArgs.cs @@ -1,5 +1,3 @@ -#nullable disable - #pragma warning disable CS1591 using System; diff --git a/MediaBrowser.Controller/Collections/ICollectionManager.cs b/MediaBrowser.Controller/Collections/ICollectionManager.cs index 49cc39f04..b8c33ee5a 100644 --- a/MediaBrowser.Controller/Collections/ICollectionManager.cs +++ b/MediaBrowser.Controller/Collections/ICollectionManager.cs @@ -1,5 +1,3 @@ -#nullable disable - #pragma warning disable CS1591 using System; @@ -16,17 +14,17 @@ namespace MediaBrowser.Controller.Collections /// /// Occurs when [collection created]. /// - event EventHandler CollectionCreated; + event EventHandler? CollectionCreated; /// /// Occurs when [items added to collection]. /// - event EventHandler ItemsAddedToCollection; + event EventHandler? ItemsAddedToCollection; /// /// Occurs when [items removed from collection]. /// - event EventHandler ItemsRemovedFromCollection; + event EventHandler? ItemsRemovedFromCollection; /// /// Creates the collection. diff --git a/MediaBrowser.Controller/Configuration/IServerConfigurationManager.cs b/MediaBrowser.Controller/Configuration/IServerConfigurationManager.cs index 44e2c45dd..43ad04dba 100644 --- a/MediaBrowser.Controller/Configuration/IServerConfigurationManager.cs +++ b/MediaBrowser.Controller/Configuration/IServerConfigurationManager.cs @@ -1,5 +1,3 @@ -#nullable disable - using MediaBrowser.Common.Configuration; using MediaBrowser.Model.Configuration; diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 9bae95a27..141bb91c5 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -7,7 +7,6 @@ using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; -using System.Runtime.InteropServices; using System.Text; using System.Text.RegularExpressions; using System.Threading; @@ -16,9 +15,7 @@ using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Dlna; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; -using MediaBrowser.Model.IO; using MediaBrowser.Model.MediaInfo; -using Microsoft.Extensions.Configuration; namespace MediaBrowser.Controller.MediaEncoding { diff --git a/MediaBrowser.Model/Globalization/ILocalizationManager.cs b/MediaBrowser.Model/Globalization/ILocalizationManager.cs index baefeb39c..b213e7aa0 100644 --- a/MediaBrowser.Model/Globalization/ILocalizationManager.cs +++ b/MediaBrowser.Model/Globalization/ILocalizationManager.cs @@ -1,4 +1,3 @@ -#nullable disable using System.Collections.Generic; using System.Globalization; using MediaBrowser.Model.Entities; @@ -56,19 +55,11 @@ namespace MediaBrowser.Model.Globalization /// . IEnumerable GetLocalizationOptions(); - /// - /// Checks if the string contains a character with the specified unicode category. - /// - /// The string. - /// The unicode category. - /// Wether or not the string contains a character with the specified unicode category. - bool HasUnicodeCategory(string value, UnicodeCategory category); - /// /// Returns the correct for the given language. /// /// The language. /// The correct for the given language. - CultureDto FindLanguageInfo(string language); + CultureDto? FindLanguageInfo(string language); } } diff --git a/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs b/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs index 2c86f9242..1125154ac 100644 --- a/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs +++ b/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs @@ -148,80 +148,76 @@ namespace MediaBrowser.XbmcMetadata.Parsers return; } - using (var fileStream = File.OpenRead(metadataFile)) - using (var streamReader = new StreamReader(fileStream, Encoding.UTF8)) - { - item.ResetPeople(); - - // Need to handle a url after the xml data - // http://kodi.wiki/view/NFO_files/movies + item.ResetPeople(); - var xml = streamReader.ReadToEnd(); + // Need to handle a url after the xml data + // http://kodi.wiki/view/NFO_files/movies - // Find last closing Tag - // Need to do this in two steps to account for random > characters after the closing xml - var index = xml.LastIndexOf(@"', index); - } + // Find last closing Tag + // Need to do this in two steps to account for random > characters after the closing xml + var index = xml.LastIndexOf(@"', index); + } - ParseProviderLinks(item.Item, endingXml); + if (index != -1) + { + var endingXml = xml.AsSpan().Slice(index); - // If the file is just an imdb url, don't go any further - if (index == 0) - { - return; - } + ParseProviderLinks(item.Item, endingXml); - xml = xml.Substring(0, index + 1); - } - else + // If the file is just an imdb url, don't go any further + if (index == 0) { - // If the file is just provider urls, handle that - ParseProviderLinks(item.Item, xml); - return; } - // These are not going to be valid xml so no sense in causing the provider to fail and spamming the log with exceptions - try + xml = xml.Substring(0, index + 1); + } + else + { + // If the file is just provider urls, handle that + ParseProviderLinks(item.Item, xml); + + return; + } + + // These are not going to be valid xml so no sense in causing the provider to fail and spamming the log with exceptions + try + { + using (var stringReader = new StringReader(xml)) + using (var reader = XmlReader.Create(stringReader, settings)) { - using (var stringReader = new StringReader(xml)) - using (var reader = XmlReader.Create(stringReader, settings)) + reader.MoveToContent(); + reader.Read(); + + // Loop through each element + while (!reader.EOF && reader.ReadState == ReadState.Interactive) { - reader.MoveToContent(); - reader.Read(); + cancellationToken.ThrowIfCancellationRequested(); - // Loop through each element - while (!reader.EOF && reader.ReadState == ReadState.Interactive) + if (reader.NodeType == XmlNodeType.Element) { - cancellationToken.ThrowIfCancellationRequested(); - - if (reader.NodeType == XmlNodeType.Element) - { - FetchDataFromXmlNode(reader, item); - } - else - { - reader.Read(); - } + FetchDataFromXmlNode(reader, item); + } + else + { + reader.Read(); } } } - catch (XmlException) - { - } + } + catch (XmlException) + { } } - protected void ParseProviderLinks(T item, string xml) + protected void ParseProviderLinks(T item, ReadOnlySpan xml) { if (ProviderIdParsers.TryFindImdbId(xml, out var imdbId)) { diff --git a/MediaBrowser.XbmcMetadata/Parsers/EpisodeNfoParser.cs b/MediaBrowser.XbmcMetadata/Parsers/EpisodeNfoParser.cs index 6b1607530..ca3ec79b7 100644 --- a/MediaBrowser.XbmcMetadata/Parsers/EpisodeNfoParser.cs +++ b/MediaBrowser.XbmcMetadata/Parsers/EpisodeNfoParser.cs @@ -40,72 +40,68 @@ namespace MediaBrowser.XbmcMetadata.Parsers /// protected override void Fetch(MetadataResult item, string metadataFile, XmlReaderSettings settings, CancellationToken cancellationToken) { - using (var fileStream = File.OpenRead(metadataFile)) - using (var streamReader = new StreamReader(fileStream, Encoding.UTF8)) - { - item.ResetPeople(); + item.ResetPeople(); - var xmlFile = streamReader.ReadToEnd(); + var xmlFile = File.ReadAllText(metadataFile); - var srch = ""; - var index = xmlFile.IndexOf(srch, StringComparison.OrdinalIgnoreCase); + var srch = ""; + var index = xmlFile.IndexOf(srch, StringComparison.OrdinalIgnoreCase); - var xml = xmlFile; + var xml = xmlFile; - if (index != -1) - { - xml = xmlFile.Substring(0, index + srch.Length); - xmlFile = xmlFile.Substring(index + srch.Length); - } + if (index != -1) + { + xml = xmlFile.Substring(0, index + srch.Length); + xmlFile = xmlFile.Substring(index + srch.Length); + } - // These are not going to be valid xml so no sense in causing the provider to fail and spamming the log with exceptions - try + // These are not going to be valid xml so no sense in causing the provider to fail and spamming the log with exceptions + try + { + // Extract episode details from the first episodedetails block + using (var stringReader = new StringReader(xml)) + using (var reader = XmlReader.Create(stringReader, settings)) { - // Extract episode details from the first episodedetails block - using (var stringReader = new StringReader(xml)) - using (var reader = XmlReader.Create(stringReader, settings)) + reader.MoveToContent(); + reader.Read(); + + // Loop through each element + while (!reader.EOF && reader.ReadState == ReadState.Interactive) { - reader.MoveToContent(); - reader.Read(); + cancellationToken.ThrowIfCancellationRequested(); - // Loop through each element - while (!reader.EOF && reader.ReadState == ReadState.Interactive) + if (reader.NodeType == XmlNodeType.Element) { - cancellationToken.ThrowIfCancellationRequested(); - - if (reader.NodeType == XmlNodeType.Element) - { - FetchDataFromXmlNode(reader, item); - } - else - { - reader.Read(); - } + FetchDataFromXmlNode(reader, item); + } + else + { + reader.Read(); } } + } - // Extract the last episode number from nfo - // This is needed because XBMC metadata uses multiple episodedetails blocks instead of episodenumberend tag - while ((index = xmlFile.IndexOf(srch, StringComparison.OrdinalIgnoreCase)) != -1) + // Extract the last episode number from nfo + // This is needed because XBMC metadata uses multiple episodedetails blocks instead of episodenumberend tag + while ((index = xmlFile.IndexOf(srch, StringComparison.OrdinalIgnoreCase)) != -1) + { + xml = xmlFile.Substring(0, index + srch.Length); + xmlFile = xmlFile.Substring(index + srch.Length); + + using (var stringReader = new StringReader(xml)) + using (var reader = XmlReader.Create(stringReader, settings)) { - xml = xmlFile.Substring(0, index + srch.Length); - xmlFile = xmlFile.Substring(index + srch.Length); + reader.MoveToContent(); - using (var stringReader = new StringReader(xml)) - using (var reader = XmlReader.Create(stringReader, settings)) + if (reader.ReadToDescendant("episode") && int.TryParse(reader.ReadElementContentAsString(), out var num)) { - reader.MoveToContent(); - - if (reader.ReadToDescendant("episode") && int.TryParse(reader.ReadElementContentAsString(), out var num)) - { - item.Item.IndexNumberEnd = Math.Max(num, item.Item.IndexNumberEnd ?? num); - } + item.Item.IndexNumberEnd = Math.Max(num, item.Item.IndexNumberEnd ?? num); } } } - catch (XmlException) - { - } + } + catch (XmlException) + { } } diff --git a/tests/Jellyfin.Server.Implementations.Tests/Localization/LocalizationManagerTests.cs b/tests/Jellyfin.Server.Implementations.Tests/Localization/LocalizationManagerTests.cs index edd4b1e55..143020d43 100644 --- a/tests/Jellyfin.Server.Implementations.Tests/Localization/LocalizationManagerTests.cs +++ b/tests/Jellyfin.Server.Implementations.Tests/Localization/LocalizationManagerTests.cs @@ -66,7 +66,7 @@ namespace Jellyfin.Server.Implementations.Tests.Localization var germany = localizationManager.FindLanguageInfo(identifier); Assert.NotNull(germany); - Assert.Equal("ger", germany.ThreeLetterISOLanguageName); + Assert.Equal("ger", germany!.ThreeLetterISOLanguageName); Assert.Equal("German", germany.DisplayName); Assert.Equal("German", germany.Name); Assert.Contains("deu", germany.ThreeLetterISOLanguageNames); -- cgit v1.2.3 From cba07b1ca6862ef8450021b0e60ce2f366ff0d33 Mon Sep 17 00:00:00 2001 From: Cody Robibero Date: Sat, 28 Aug 2021 16:32:50 -0600 Subject: Remove more and more warnings --- Emby.Dlna/ContentDirectory/ServerItem.cs | 2 +- Emby.Dlna/Didl/DidlBuilder.cs | 2 +- Emby.Server.Implementations/ApplicationHost.cs | 3 +- .../Channels/ChannelManager.cs | 6 +- .../Data/BaseSqliteRepository.cs | 2 +- .../Data/SqliteItemRepository.cs | 9 +- .../Data/SqliteUserDataRepository.cs | 8 +- Emby.Server.Implementations/Dto/DtoService.cs | 41 +- .../EntryPoints/LibraryChangedNotifier.cs | 4 +- .../EntryPoints/UdpServerEntryPoint.cs | 3 + .../HttpServer/Security/AuthorizationContext.cs | 2 + .../HttpServer/WebSocketConnection.cs | 4 +- Emby.Server.Implementations/IStartupOptions.cs | 2 +- .../Images/CollectionFolderImageProvider.cs | 12 +- .../Library/LibraryManager.cs | 8 +- .../Library/Resolvers/Audio/AudioResolver.cs | 12 +- .../Library/Resolvers/BaseVideoResolver.cs | 26 +- .../Library/Resolvers/GenericVideoResolver.cs | 18 + .../Library/Resolvers/ItemResolver.cs | 2 +- .../Library/Resolvers/Movies/MovieResolver.cs | 4 +- .../Library/Resolvers/PlaylistResolver.cs | 3 +- .../Library/Resolvers/VideoResolver.cs | 18 - .../Library/Validators/StudiosValidator.cs | 9 +- .../LiveTv/EmbyTV/EmbyTV.cs | 2 +- .../LiveTv/EmbyTV/EpgChannelData.cs | 1 - .../LiveTv/Listings/SchedulesDirect.cs | 620 ++++----------------- .../Listings/SchedulesDirectDtos/BroadcasterDto.cs | 36 ++ .../Listings/SchedulesDirectDtos/CaptionDto.cs | 24 + .../LiveTv/Listings/SchedulesDirectDtos/CastDto.cs | 48 ++ .../Listings/SchedulesDirectDtos/ChannelDto.cs | 31 ++ .../SchedulesDirectDtos/ContentRatingDto.cs | 24 + .../LiveTv/Listings/SchedulesDirectDtos/CrewDto.cs | 42 ++ .../LiveTv/Listings/SchedulesDirectDtos/DayDto.cs | 39 ++ .../SchedulesDirectDtos/Description1000Dto.cs | 24 + .../SchedulesDirectDtos/Description100Dto.cs | 24 + .../SchedulesDirectDtos/DescriptionsProgramDto.cs | 25 + .../SchedulesDirectDtos/EventDetailsDto.cs | 18 + .../Listings/SchedulesDirectDtos/GracenoteDto.cs | 24 + .../Listings/SchedulesDirectDtos/HeadendsDto.cs | 37 ++ .../Listings/SchedulesDirectDtos/ImageDataDto.cs | 69 +++ .../Listings/SchedulesDirectDtos/LineupDto.cs | 42 ++ .../Listings/SchedulesDirectDtos/LineupsDto.cs | 37 ++ .../LiveTv/Listings/SchedulesDirectDtos/LogoDto.cs | 36 ++ .../LiveTv/Listings/SchedulesDirectDtos/MapDto.cs | 48 ++ .../Listings/SchedulesDirectDtos/MetadataDto.cs | 30 + .../SchedulesDirectDtos/MetadataProgramsDto.cs | 18 + .../SchedulesDirectDtos/MetadataScheduleDto.cs | 42 ++ .../Listings/SchedulesDirectDtos/MovieDto.cs | 31 ++ .../Listings/SchedulesDirectDtos/MultipartDto.cs | 24 + .../SchedulesDirectDtos/ProgramDetailsDto.cs | 157 ++++++ .../Listings/SchedulesDirectDtos/ProgramDto.cs | 91 +++ .../SchedulesDirectDtos/QualityRatingDto.cs | 42 ++ .../Listings/SchedulesDirectDtos/RatingDto.cs | 24 + .../SchedulesDirectDtos/RecommendationDto.cs | 24 + .../RequestScheduleForChannelDto.cs | 25 + .../Listings/SchedulesDirectDtos/ShowImagesDto.cs | 22 + .../Listings/SchedulesDirectDtos/StationDto.cs | 67 +++ .../Listings/SchedulesDirectDtos/TitleDto.cs | 18 + .../Listings/SchedulesDirectDtos/TokenDto.cs | 36 ++ .../LiveTv/LiveTvManager.cs | 6 +- .../TunerHosts/HdHomerun/HdHomerunManager.cs | 1 + .../Playlists/PlaylistManager.cs | 4 +- .../ScheduledTasks/ScheduledTaskWorker.cs | 3 +- .../Sorting/ArtistComparer.cs | 2 +- Jellyfin.Api/Controllers/ItemUpdateController.cs | 10 +- Jellyfin.Api/Controllers/ItemsController.cs | 4 +- Jellyfin.Api/Controllers/LibraryController.cs | 2 +- Jellyfin.Api/Controllers/TvShowsController.cs | 8 +- Jellyfin.Api/Helpers/StreamingHelpers.cs | 4 - MediaBrowser.Controller/Entities/BaseItem.cs | 4 +- MediaBrowser.Controller/Entities/Folder.cs | 10 +- MediaBrowser.Controller/Entities/TV/Series.cs | 2 +- .../MediaEncoding/EncodingHelper.cs | 12 +- .../MediaEncoding/EncodingJobInfo.cs | 6 +- .../Images/LocalImageProvider.cs | 2 +- MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs | 8 +- MediaBrowser.Model/Dlna/MediaFormatProfile.cs | 2 +- MediaBrowser.Model/Dlna/ResolutionNormalizer.cs | 4 - MediaBrowser.Model/Dlna/StreamBuilder.cs | 33 +- MediaBrowser.Model/Dlna/StreamInfo.cs | 2 +- MediaBrowser.Model/Entities/MediaStream.cs | 2 +- MediaBrowser.Model/IO/IFileSystem.cs | 4 +- MediaBrowser.Providers/Manager/ImageSaver.cs | 2 +- .../Manager/ItemImageProvider.cs | 4 +- MediaBrowser.Providers/Manager/MetadataService.cs | 6 +- MediaBrowser.Providers/Manager/ProviderManager.cs | 10 +- MediaBrowser.Providers/Manager/ProviderUtils.cs | 2 +- MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs | 6 +- MediaBrowser.XbmcMetadata/Savers/MovieNfoSaver.cs | 2 +- MediaBrowser.XbmcMetadata/Savers/SeasonNfoSaver.cs | 2 +- 90 files changed, 1572 insertions(+), 699 deletions(-) create mode 100644 Emby.Server.Implementations/Library/Resolvers/GenericVideoResolver.cs delete mode 100644 Emby.Server.Implementations/Library/Resolvers/VideoResolver.cs create mode 100644 Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/BroadcasterDto.cs create mode 100644 Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/CaptionDto.cs create mode 100644 Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/CastDto.cs create mode 100644 Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ChannelDto.cs create mode 100644 Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ContentRatingDto.cs create mode 100644 Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/CrewDto.cs create mode 100644 Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/DayDto.cs create mode 100644 Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/Description1000Dto.cs create mode 100644 Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/Description100Dto.cs create mode 100644 Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/DescriptionsProgramDto.cs create mode 100644 Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/EventDetailsDto.cs create mode 100644 Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/GracenoteDto.cs create mode 100644 Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/HeadendsDto.cs create mode 100644 Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ImageDataDto.cs create mode 100644 Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/LineupDto.cs create mode 100644 Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/LineupsDto.cs create mode 100644 Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/LogoDto.cs create mode 100644 Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MapDto.cs create mode 100644 Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MetadataDto.cs create mode 100644 Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MetadataProgramsDto.cs create mode 100644 Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MetadataScheduleDto.cs create mode 100644 Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MovieDto.cs create mode 100644 Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MultipartDto.cs create mode 100644 Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ProgramDetailsDto.cs create mode 100644 Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ProgramDto.cs create mode 100644 Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/QualityRatingDto.cs create mode 100644 Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/RatingDto.cs create mode 100644 Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/RecommendationDto.cs create mode 100644 Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/RequestScheduleForChannelDto.cs create mode 100644 Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ShowImagesDto.cs create mode 100644 Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/StationDto.cs create mode 100644 Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/TitleDto.cs create mode 100644 Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/TokenDto.cs (limited to 'MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs') diff --git a/Emby.Dlna/ContentDirectory/ServerItem.cs b/Emby.Dlna/ContentDirectory/ServerItem.cs index 34244000c..ff30e6e4a 100644 --- a/Emby.Dlna/ContentDirectory/ServerItem.cs +++ b/Emby.Dlna/ContentDirectory/ServerItem.cs @@ -17,7 +17,7 @@ namespace Emby.Dlna.ContentDirectory { Item = item; - if (item is IItemByName && !(item is Folder)) + if (item is IItemByName && item is not Folder) { StubType = Dlna.ContentDirectory.StubType.Folder; } diff --git a/Emby.Dlna/Didl/DidlBuilder.cs b/Emby.Dlna/Didl/DidlBuilder.cs index 2982ce97e..c00078499 100644 --- a/Emby.Dlna/Didl/DidlBuilder.cs +++ b/Emby.Dlna/Didl/DidlBuilder.cs @@ -748,7 +748,7 @@ namespace Emby.Dlna.Didl AddValue(writer, "upnp", "publisher", studio, NsUpnp); } - if (!(item is Folder)) + if (item is not Folder) { if (filter.Contains("dc:description")) { diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index bf7ddace2..b640f06c6 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -456,6 +456,7 @@ namespace Emby.Server.Implementations /// /// Runs the startup tasks. /// + /// The cancellation token. /// . public async Task RunStartupTasksAsync(CancellationToken cancellationToken) { @@ -469,7 +470,7 @@ namespace Emby.Server.Implementations _mediaEncoder.SetFFmpegPath(); - Logger.LogInformation("ServerId: {0}", SystemId); + Logger.LogInformation("ServerId: {ServerId}", SystemId); var entryPoints = GetExports(); diff --git a/Emby.Server.Implementations/Channels/ChannelManager.cs b/Emby.Server.Implementations/Channels/ChannelManager.cs index aa54510a7..41d1f9b39 100644 --- a/Emby.Server.Implementations/Channels/ChannelManager.cs +++ b/Emby.Server.Implementations/Channels/ChannelManager.cs @@ -102,7 +102,7 @@ namespace Emby.Server.Implementations.Channels var internalChannel = _libraryManager.GetItemById(item.ChannelId); var channel = Channels.FirstOrDefault(i => GetInternalChannelId(i.Name).Equals(internalChannel.Id)); - return !(channel is IDisableMediaSourceDisplay); + return channel is not IDisableMediaSourceDisplay; } /// @@ -1079,11 +1079,11 @@ namespace Emby.Server.Implementations.Channels // was used for status // if (!string.Equals(item.ExternalEtag ?? string.Empty, info.Etag ?? string.Empty, StringComparison.Ordinal)) - //{ + // { // item.ExternalEtag = info.Etag; // forceUpdate = true; // _logger.LogDebug("Forcing update due to ExternalEtag {0}", item.Name); - //} + // } if (!internalChannelId.Equals(item.ChannelId)) { diff --git a/Emby.Server.Implementations/Data/BaseSqliteRepository.cs b/Emby.Server.Implementations/Data/BaseSqliteRepository.cs index 6f23a0888..01c9fbca8 100644 --- a/Emby.Server.Implementations/Data/BaseSqliteRepository.cs +++ b/Emby.Server.Implementations/Data/BaseSqliteRepository.cs @@ -61,7 +61,7 @@ namespace Emby.Server.Implementations.Data protected virtual int? CacheSize => null; /// - /// Gets the journal mode. + /// Gets the journal mode. . /// /// The journal mode. protected virtual string JournalMode => "TRUNCATE"; diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs index 2cb10765f..ab1b55164 100644 --- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs @@ -72,9 +72,16 @@ namespace Emby.Server.Implementations.Data _mediaAttachmentInsertPrefix = queryPrefixText.ToString(); } + /// /// Initializes a new instance of the class. /// + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. + /// config is null. public SqliteItemRepository( IServerConfigurationManager config, IServerApplicationHost appHost, @@ -4879,7 +4886,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type foreach (var t in _knownTypes) { - dict[t.Name] = t.FullName ; + dict[t.Name] = t.FullName; } dict["Program"] = typeof(LiveTvProgram).FullName; diff --git a/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs b/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs index ef9af1dcd..613d07d77 100644 --- a/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs @@ -174,7 +174,6 @@ namespace Emby.Server.Implementations.Data /// The key. /// The user data. /// The cancellation token. - /// Task. public void PersistUserData(long internalUserId, string key, UserItemData userData, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); @@ -319,8 +318,8 @@ namespace Emby.Server.Implementations.Data /// /// Return all user-data associated with the given user. /// - /// - /// + /// The internal user id. + /// The list of user item data. public List GetAllUserData(long internalUserId) { if (internalUserId <= 0) @@ -349,7 +348,8 @@ namespace Emby.Server.Implementations.Data /// /// Read a row from the specified reader into the provided userData object. /// - /// + /// The list of result set values. + /// The user item data. private UserItemData ReadRow(IReadOnlyList reader) { var userData = new UserItemData(); diff --git a/Emby.Server.Implementations/Dto/DtoService.cs b/Emby.Server.Implementations/Dto/DtoService.cs index 7411239a1..7c2d02037 100644 --- a/Emby.Server.Implementations/Dto/DtoService.cs +++ b/Emby.Server.Implementations/Dto/DtoService.cs @@ -807,7 +807,7 @@ namespace Emby.Server.Implementations.Dto dto.MediaType = item.MediaType; - if (!(item is LiveTvProgram)) + if (item is not LiveTvProgram) { dto.LocationType = item.LocationType; } @@ -928,9 +928,9 @@ namespace Emby.Server.Implementations.Dto } // if (options.ContainsField(ItemFields.MediaSourceCount)) - //{ + // { // Songs always have one - //} + // } } if (item is IHasArtist hasArtist) @@ -938,10 +938,10 @@ namespace Emby.Server.Implementations.Dto dto.Artists = hasArtist.Artists; // var artistItems = _libraryManager.GetArtists(new InternalItemsQuery - //{ + // { // EnableTotalRecordCount = false, // ItemIds = new[] { item.Id.ToString("N", CultureInfo.InvariantCulture) } - //}); + // }); // dto.ArtistItems = artistItems.Items // .Select(i => @@ -958,7 +958,7 @@ namespace Emby.Server.Implementations.Dto // Include artists that are not in the database yet, e.g., just added via metadata editor // var foundArtists = artistItems.Items.Select(i => i.Item1.Name).ToList(); dto.ArtistItems = hasArtist.Artists - //.Except(foundArtists, new DistinctNameComparer()) + // .Except(foundArtists, new DistinctNameComparer()) .Select(i => { // This should not be necessary but we're seeing some cases of it @@ -990,10 +990,10 @@ namespace Emby.Server.Implementations.Dto dto.AlbumArtist = hasAlbumArtist.AlbumArtists.FirstOrDefault(); // var artistItems = _libraryManager.GetAlbumArtists(new InternalItemsQuery - //{ + // { // EnableTotalRecordCount = false, // ItemIds = new[] { item.Id.ToString("N", CultureInfo.InvariantCulture) } - //}); + // }); // dto.AlbumArtists = artistItems.Items // .Select(i => @@ -1008,7 +1008,7 @@ namespace Emby.Server.Implementations.Dto // .ToList(); dto.AlbumArtists = hasAlbumArtist.AlbumArtists - //.Except(foundArtists, new DistinctNameComparer()) + // .Except(foundArtists, new DistinctNameComparer()) .Select(i => { // This should not be necessary but we're seeing some cases of it @@ -1035,8 +1035,7 @@ namespace Emby.Server.Implementations.Dto } // Add video info - var video = item as Video; - if (video != null) + if (item is Video video) { dto.VideoType = video.VideoType; dto.Video3DFormat = video.Video3DFormat; @@ -1075,9 +1074,7 @@ namespace Emby.Server.Implementations.Dto if (options.ContainsField(ItemFields.MediaStreams)) { // Add VideoInfo - var iHasMediaSources = item as IHasMediaSources; - - if (iHasMediaSources != null) + if (item is IHasMediaSources) { MediaStream[] mediaStreams; @@ -1146,7 +1143,7 @@ namespace Emby.Server.Implementations.Dto // TODO maybe remove the if statement entirely // if (options.ContainsField(ItemFields.SeriesPrimaryImage)) { - episodeSeries = episodeSeries ?? episode.Series; + episodeSeries ??= episode.Series; if (episodeSeries != null) { dto.SeriesPrimaryImageTag = GetTagAndFillBlurhash(dto, episodeSeries, ImageType.Primary); @@ -1159,7 +1156,7 @@ namespace Emby.Server.Implementations.Dto if (options.ContainsField(ItemFields.SeriesStudio)) { - episodeSeries = episodeSeries ?? episode.Series; + episodeSeries ??= episode.Series; if (episodeSeries != null) { dto.SeriesStudio = episodeSeries.Studios.FirstOrDefault(); @@ -1172,7 +1169,7 @@ namespace Emby.Server.Implementations.Dto { dto.AirDays = series.AirDays; dto.AirTime = series.AirTime; - dto.Status = series.Status.HasValue ? series.Status.Value.ToString() : null; + dto.Status = series.Status?.ToString(); } // Add SeasonInfo @@ -1185,7 +1182,7 @@ namespace Emby.Server.Implementations.Dto if (options.ContainsField(ItemFields.SeriesStudio)) { - series = series ?? season.Series; + series ??= season.Series; if (series != null) { dto.SeriesStudio = series.Studios.FirstOrDefault(); @@ -1196,7 +1193,7 @@ namespace Emby.Server.Implementations.Dto // TODO maybe remove the if statement entirely // if (options.ContainsField(ItemFields.SeriesPrimaryImage)) { - series = series ?? season.Series; + series ??= season.Series; if (series != null) { dto.SeriesPrimaryImageTag = GetTagAndFillBlurhash(dto, series, ImageType.Primary); @@ -1283,7 +1280,7 @@ namespace Emby.Server.Implementations.Dto var parent = currentItem.DisplayParent ?? currentItem.GetOwner() ?? currentItem.GetParent(); - if (parent == null && !(originalItem is UserRootFolder) && !(originalItem is UserView) && !(originalItem is AggregateFolder) && !(originalItem is ICollectionFolder) && !(originalItem is Channel)) + if (parent == null && originalItem is not UserRootFolder && originalItem is not UserView && originalItem is not AggregateFolder && originalItem is not ICollectionFolder && originalItem is not Channel) { parent = _libraryManager.GetCollectionFolders(originalItem).FirstOrDefault(); } @@ -1317,7 +1314,7 @@ namespace Emby.Server.Implementations.Dto var imageTags = dto.ImageTags; while (((!(imageTags != null && imageTags.ContainsKey(ImageType.Logo)) && logoLimit > 0) || (!(imageTags != null && imageTags.ContainsKey(ImageType.Art)) && artLimit > 0) || (!(imageTags != null && imageTags.ContainsKey(ImageType.Thumb)) && thumbLimit > 0) || parent is Series) && - (parent = parent ?? (isFirst ? GetImageDisplayParent(item, item) ?? owner : parent)) != null) + (parent ??= (isFirst ? GetImageDisplayParent(item, item) ?? owner : parent)) != null) { if (parent == null) { @@ -1348,7 +1345,7 @@ namespace Emby.Server.Implementations.Dto } } - if (thumbLimit > 0 && !(imageTags != null && imageTags.ContainsKey(ImageType.Thumb)) && (dto.ParentThumbItemId == null || parent is Series) && !(parent is ICollectionFolder) && !(parent is UserView)) + if (thumbLimit > 0 && !(imageTags != null && imageTags.ContainsKey(ImageType.Thumb)) && (dto.ParentThumbItemId == null || parent is Series) && parent is not ICollectionFolder && parent is not UserView) { var image = allImages.FirstOrDefault(i => i.Type == ImageType.Thumb); diff --git a/Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs b/Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs index 5bb4100ba..df48346e3 100644 --- a/Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs +++ b/Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs @@ -149,7 +149,7 @@ namespace Emby.Server.Implementations.EntryPoints private static bool EnableRefreshMessage(BaseItem item) { - if (!(item is Folder folder)) + if (item is not Folder folder) { return false; } @@ -403,7 +403,7 @@ namespace Emby.Server.Implementations.EntryPoints return false; } - if (item is IItemByName && !(item is MusicArtist)) + if (item is IItemByName && item is not MusicArtist) { return false; } diff --git a/Emby.Server.Implementations/EntryPoints/UdpServerEntryPoint.cs b/Emby.Server.Implementations/EntryPoints/UdpServerEntryPoint.cs index 2e72b18f5..feaccf9fa 100644 --- a/Emby.Server.Implementations/EntryPoints/UdpServerEntryPoint.cs +++ b/Emby.Server.Implementations/EntryPoints/UdpServerEntryPoint.cs @@ -37,6 +37,9 @@ namespace Emby.Server.Implementations.EntryPoints /// /// Initializes a new instance of the class. /// + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. public UdpServerEntryPoint( ILogger logger, IServerApplicationHost appHost, diff --git a/Emby.Server.Implementations/HttpServer/Security/AuthorizationContext.cs b/Emby.Server.Implementations/HttpServer/Security/AuthorizationContext.cs index b2625a68c..badc6ce6c 100644 --- a/Emby.Server.Implementations/HttpServer/Security/AuthorizationContext.cs +++ b/Emby.Server.Implementations/HttpServer/Security/AuthorizationContext.cs @@ -74,6 +74,7 @@ namespace Emby.Server.Implementations.HttpServer.Security auth.TryGetValue("Token", out token); } +#pragma warning disable CA1508 // string.IsNullOrEmpty(token) is always false. if (string.IsNullOrEmpty(token)) { token = headers["X-Emby-Token"]; @@ -111,6 +112,7 @@ namespace Emby.Server.Implementations.HttpServer.Security // Request doesn't contain a token. return authInfo; } +#pragma warning restore CA1508 authInfo.HasToken = true; var result = _authRepo.Get(new AuthenticationInfoQuery diff --git a/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs b/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs index 5d38ea0ca..7010a6fb0 100644 --- a/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs +++ b/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs @@ -62,7 +62,7 @@ namespace Emby.Server.Implementations.HttpServer public event EventHandler? Closed; /// - /// Gets or sets the remote end point. + /// Gets the remote end point. /// public IPAddress? RemoteEndPoint { get; } @@ -82,7 +82,7 @@ namespace Emby.Server.Implementations.HttpServer public DateTime LastKeepAliveDate { get; set; } /// - /// Gets or sets the query string. + /// Gets the query string. /// /// The query string. public IQueryCollection QueryString { get; } diff --git a/Emby.Server.Implementations/IStartupOptions.cs b/Emby.Server.Implementations/IStartupOptions.cs index a430b9e72..1d97882db 100644 --- a/Emby.Server.Implementations/IStartupOptions.cs +++ b/Emby.Server.Implementations/IStartupOptions.cs @@ -10,7 +10,7 @@ namespace Emby.Server.Implementations string? FFmpegPath { get; } /// - /// Gets the value of the --service command line option. + /// Gets a value value indicating whether to run as service by the --service command line option. /// bool IsService { get; } diff --git a/Emby.Server.Implementations/Images/CollectionFolderImageProvider.cs b/Emby.Server.Implementations/Images/CollectionFolderImageProvider.cs index ff5f26ce0..0229fbae7 100644 --- a/Emby.Server.Implementations/Images/CollectionFolderImageProvider.cs +++ b/Emby.Server.Implementations/Images/CollectionFolderImageProvider.cs @@ -30,27 +30,27 @@ namespace Emby.Server.Implementations.Images string[] includeItemTypes; - if (string.Equals(viewType, CollectionType.Movies)) + if (string.Equals(viewType, CollectionType.Movies, StringComparison.Ordinal)) { includeItemTypes = new string[] { "Movie" }; } - else if (string.Equals(viewType, CollectionType.TvShows)) + else if (string.Equals(viewType, CollectionType.TvShows, StringComparison.Ordinal)) { includeItemTypes = new string[] { "Series" }; } - else if (string.Equals(viewType, CollectionType.Music)) + else if (string.Equals(viewType, CollectionType.Music, StringComparison.Ordinal)) { includeItemTypes = new string[] { "MusicAlbum" }; } - else if (string.Equals(viewType, CollectionType.Books)) + else if (string.Equals(viewType, CollectionType.Books, StringComparison.Ordinal)) { includeItemTypes = new string[] { "Book", "AudioBook" }; } - else if (string.Equals(viewType, CollectionType.BoxSets)) + else if (string.Equals(viewType, CollectionType.BoxSets, StringComparison.Ordinal)) { includeItemTypes = new string[] { "BoxSet" }; } - else if (string.Equals(viewType, CollectionType.HomeVideos) || string.Equals(viewType, CollectionType.Photos)) + else if (string.Equals(viewType, CollectionType.HomeVideos, StringComparison.Ordinal) || string.Equals(viewType, CollectionType.Photos, StringComparison.Ordinal)) { includeItemTypes = new string[] { "Video", "Photo" }; } diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index 13fb8b2fd..6a2983d9b 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -287,14 +287,14 @@ namespace Emby.Server.Implementations.Library if (item is IItemByName) { - if (!(item is MusicArtist)) + if (item is not MusicArtist) { return; } } else if (!item.IsFolder) { - if (!(item is Video) && !(item is LiveTvChannel)) + if (item is not Video && item is not LiveTvChannel) { return; } @@ -866,7 +866,7 @@ namespace Emby.Server.Implementations.Library { var path = Person.GetPath(name); var id = GetItemByNameId(path); - if (!(GetItemById(id) is Person item)) + if (GetItemById(id) is not Person item) { item = new Person { @@ -2118,7 +2118,7 @@ namespace Emby.Server.Implementations.Library public LibraryOptions GetLibraryOptions(BaseItem item) { - if (!(item is CollectionFolder collectionFolder)) + if (item is not CollectionFolder collectionFolder) { // List.Find is more performant than FirstOrDefault due to enumerator allocation collectionFolder = GetCollectionFolders(item) diff --git a/Emby.Server.Implementations/Library/Resolvers/Audio/AudioResolver.cs b/Emby.Server.Implementations/Library/Resolvers/Audio/AudioResolver.cs index e893d6335..fd9747b4b 100644 --- a/Emby.Server.Implementations/Library/Resolvers/Audio/AudioResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/Audio/AudioResolver.cs @@ -21,11 +21,11 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio /// public class AudioResolver : ItemResolver, IMultiItemResolver { - private readonly ILibraryManager LibraryManager; + private readonly ILibraryManager _libraryManager; public AudioResolver(ILibraryManager libraryManager) { - LibraryManager = libraryManager; + _libraryManager = libraryManager; } /// @@ -88,13 +88,13 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio } var files = args.FileSystemChildren - .Where(i => !LibraryManager.IgnoreFile(i, args.Parent)) + .Where(i => !_libraryManager.IgnoreFile(i, args.Parent)) .ToList(); return FindAudio(args, args.Path, args.Parent, files, args.DirectoryService, collectionType, false); } - if (LibraryManager.IsAudioFile(args.Path)) + if (_libraryManager.IsAudioFile(args.Path)) { var extension = Path.GetExtension(args.Path); @@ -107,7 +107,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio var isMixedCollectionType = string.IsNullOrEmpty(collectionType); // For conflicting extensions, give priority to videos - if (isMixedCollectionType && LibraryManager.IsVideoFile(args.Path)) + if (isMixedCollectionType && _libraryManager.IsVideoFile(args.Path)) { return null; } @@ -182,7 +182,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio } } - var namingOptions = ((LibraryManager)LibraryManager).GetNamingOptions(); + var namingOptions = ((LibraryManager)_libraryManager).GetNamingOptions(); var resolver = new AudioBookListResolver(namingOptions); var resolverResult = resolver.Resolve(files).ToList(); diff --git a/Emby.Server.Implementations/Library/Resolvers/BaseVideoResolver.cs b/Emby.Server.Implementations/Library/Resolvers/BaseVideoResolver.cs index cdb492022..e00332808 100644 --- a/Emby.Server.Implementations/Library/Resolvers/BaseVideoResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/BaseVideoResolver.cs @@ -16,7 +16,7 @@ namespace Emby.Server.Implementations.Library.Resolvers /// /// Resolves a Path into a Video or Video subclass. /// - /// + /// The type of item to resolve. public abstract class BaseVideoResolver : MediaBrowser.Controller.Resolvers.ItemResolver where T : Video, new() { @@ -80,7 +80,7 @@ namespace Emby.Server.Implementations.Library.Resolvers break; } - if (IsBluRayDirectory(child.FullName, filename, args.DirectoryService)) + if (IsBluRayDirectory(filename)) { videoInfo = VideoResolver.ResolveDirectory(args.Path, namingOptions); @@ -279,25 +279,13 @@ namespace Emby.Server.Implementations.Library.Resolvers } /// - /// Determines whether [is blu ray directory] [the specified directory name]. + /// Determines whether [is bluray directory] [the specified directory name]. /// - protected bool IsBluRayDirectory(string fullPath, string directoryName, IDirectoryService directoryService) + /// The directory name. + /// Whether the directory is a bluray directory. + protected bool IsBluRayDirectory(string directoryName) { - if (!string.Equals(directoryName, "bdmv", StringComparison.OrdinalIgnoreCase)) - { - return false; - } - - return true; - // var blurayExtensions = new[] - //{ - // ".mts", - // ".m2ts", - // ".bdmv", - // ".mpls" - //}; - - // return directoryService.GetFiles(fullPath).Any(i => blurayExtensions.Contains(i.Extension ?? string.Empty, StringComparer.OrdinalIgnoreCase)); + return string.Equals(directoryName, "bdmv", StringComparison.OrdinalIgnoreCase); } } } diff --git a/Emby.Server.Implementations/Library/Resolvers/GenericVideoResolver.cs b/Emby.Server.Implementations/Library/Resolvers/GenericVideoResolver.cs new file mode 100644 index 000000000..9599faea4 --- /dev/null +++ b/Emby.Server.Implementations/Library/Resolvers/GenericVideoResolver.cs @@ -0,0 +1,18 @@ +#nullable disable + +#pragma warning disable CS1591 + +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Library; + +namespace Emby.Server.Implementations.Library.Resolvers +{ + public class GenericVideoResolver : BaseVideoResolver + where T : Video, new() + { + public GenericVideoResolver(ILibraryManager libraryManager) + : base(libraryManager) + { + } + } +} diff --git a/Emby.Server.Implementations/Library/Resolvers/ItemResolver.cs b/Emby.Server.Implementations/Library/Resolvers/ItemResolver.cs index fa45ccf84..3f29ab191 100644 --- a/Emby.Server.Implementations/Library/Resolvers/ItemResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/ItemResolver.cs @@ -9,7 +9,7 @@ namespace Emby.Server.Implementations.Library.Resolvers /// /// Class ItemResolver. /// - /// + /// The type of BaseItem. public abstract class ItemResolver : IItemResolver where T : BaseItem, new() { diff --git a/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs b/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs index 889e29a6b..8b55a7744 100644 --- a/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs @@ -400,7 +400,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies return movie; } - if (IsBluRayDirectory(child.FullName, filename, directoryService)) + if (IsBluRayDirectory(filename)) { var movie = new T { @@ -481,7 +481,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies return true; } - if (subfolders.Any(s => IsBluRayDirectory(s.FullName, s.Name, directoryService))) + if (subfolders.Any(s => IsBluRayDirectory(s.Name))) { videoTypes.Add(VideoType.BluRay); return true; diff --git a/Emby.Server.Implementations/Library/Resolvers/PlaylistResolver.cs b/Emby.Server.Implementations/Library/Resolvers/PlaylistResolver.cs index ecd44be47..2c4ead719 100644 --- a/Emby.Server.Implementations/Library/Resolvers/PlaylistResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/PlaylistResolver.cs @@ -18,7 +18,8 @@ namespace Emby.Server.Implementations.Library.Resolvers /// public class PlaylistResolver : FolderResolver { - private string[] _musicPlaylistCollectionTypes = new string[] { + private string[] _musicPlaylistCollectionTypes = + { string.Empty, CollectionType.Music }; diff --git a/Emby.Server.Implementations/Library/Resolvers/VideoResolver.cs b/Emby.Server.Implementations/Library/Resolvers/VideoResolver.cs deleted file mode 100644 index 9599faea4..000000000 --- a/Emby.Server.Implementations/Library/Resolvers/VideoResolver.cs +++ /dev/null @@ -1,18 +0,0 @@ -#nullable disable - -#pragma warning disable CS1591 - -using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Library; - -namespace Emby.Server.Implementations.Library.Resolvers -{ - public class GenericVideoResolver : BaseVideoResolver - where T : Video, new() - { - public GenericVideoResolver(ILibraryManager libraryManager) - : base(libraryManager) - { - } - } -} diff --git a/Emby.Server.Implementations/Library/Validators/StudiosValidator.cs b/Emby.Server.Implementations/Library/Validators/StudiosValidator.cs index 9a8c5f39d..16bdf720c 100644 --- a/Emby.Server.Implementations/Library/Validators/StudiosValidator.cs +++ b/Emby.Server.Implementations/Library/Validators/StudiosValidator.cs @@ -87,12 +87,15 @@ namespace Emby.Server.Implementations.Library.Validators foreach (var item in deadEntities) { - _logger.LogInformation("Deleting dead {2} {0} {1}.", item.Id.ToString("N", CultureInfo.InvariantCulture), item.Name, item.GetType().Name); + _logger.LogInformation("Deleting dead {ItemType} {ItemId} {ItemName}", item.Id.ToString("N", CultureInfo.InvariantCulture), item.Name, item.GetType().Name); - _libraryManager.DeleteItem(item, new DeleteOptions + _libraryManager.DeleteItem( + item, + new DeleteOptions { DeleteFileLocation = false - }, false); + }, + false); } progress.Report(100); diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index 797063120..a6be40745 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -1458,7 +1458,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV if (item.GetType() == typeof(Folder) && string.Equals(item.Path, parentPath, StringComparison.OrdinalIgnoreCase)) { var parentItem = item.GetParent(); - if (parentItem != null && !(parentItem is AggregateFolder)) + if (parentItem != null && parentItem is not AggregateFolder) { item = parentItem; } diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EpgChannelData.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EpgChannelData.cs index 0ec52a959..20a8213a7 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/EpgChannelData.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EpgChannelData.cs @@ -8,7 +8,6 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV { internal class EpgChannelData { - private readonly Dictionary _channelsById; private readonly Dictionary _channelsByNumber; diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs index b7639a51c..bcfc4011c 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs @@ -14,6 +14,7 @@ using System.Text; using System.Text.Json; using System.Threading; using System.Threading.Tasks; +using Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos; using MediaBrowser.Common; using Jellyfin.Extensions.Json; using MediaBrowser.Common.Net; @@ -96,12 +97,12 @@ namespace Emby.Server.Implementations.LiveTv.Listings var dates = GetScheduleRequestDates(startDateUtc, endDateUtc); _logger.LogInformation("Channel Station ID is: {ChannelID}", channelId); - var requestList = new List() + var requestList = new List() { - new ScheduleDirect.RequestScheduleForChannel() + new RequestScheduleForChannelDto() { - stationID = channelId, - date = dates + StationId = channelId, + Date = dates } }; @@ -113,61 +114,61 @@ namespace Emby.Server.Implementations.LiveTv.Listings options.Headers.TryAddWithoutValidation("token", token); using var response = await Send(options, true, info, cancellationToken).ConfigureAwait(false); await using var responseStream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); - var dailySchedules = await JsonSerializer.DeserializeAsync>(responseStream, _jsonOptions, cancellationToken).ConfigureAwait(false); + var dailySchedules = await JsonSerializer.DeserializeAsync>(responseStream, _jsonOptions, cancellationToken).ConfigureAwait(false); _logger.LogDebug("Found {ScheduleCount} programs on {ChannelID} ScheduleDirect", dailySchedules.Count, channelId); using var programRequestOptions = new HttpRequestMessage(HttpMethod.Post, ApiUrl + "/programs"); programRequestOptions.Headers.TryAddWithoutValidation("token", token); - var programsID = dailySchedules.SelectMany(d => d.programs.Select(s => s.programID)).Distinct(); + var programsID = dailySchedules.SelectMany(d => d.Programs.Select(s => s.ProgramId)).Distinct(); programRequestOptions.Content = new StringContent("[\"" + string.Join("\", \"", programsID) + "\"]", Encoding.UTF8, MediaTypeNames.Application.Json); using var innerResponse = await Send(programRequestOptions, true, info, cancellationToken).ConfigureAwait(false); await using var innerResponseStream = await innerResponse.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); - var programDetails = await JsonSerializer.DeserializeAsync>(innerResponseStream, _jsonOptions, cancellationToken).ConfigureAwait(false); - var programDict = programDetails.ToDictionary(p => p.programID, y => y); + var programDetails = await JsonSerializer.DeserializeAsync>(innerResponseStream, _jsonOptions, cancellationToken).ConfigureAwait(false); + var programDict = programDetails.ToDictionary(p => p.ProgramId, y => y); var programIdsWithImages = programDetails - .Where(p => p.hasImageArtwork).Select(p => p.programID) + .Where(p => p.HasImageArtwork).Select(p => p.ProgramId) .ToList(); var images = await GetImageForPrograms(info, programIdsWithImages, cancellationToken).ConfigureAwait(false); var programsInfo = new List(); - foreach (ScheduleDirect.Program schedule in dailySchedules.SelectMany(d => d.programs)) + foreach (ProgramDto schedule in dailySchedules.SelectMany(d => d.Programs)) { // _logger.LogDebug("Proccesing Schedule for statio ID " + stationID + // " which corresponds to channel " + channelNumber + " and program id " + - // schedule.programID + " which says it has images? " + - // programDict[schedule.programID].hasImageArtwork); + // schedule.ProgramId + " which says it has images? " + + // programDict[schedule.ProgramId].hasImageArtwork); if (images != null) { - var imageIndex = images.FindIndex(i => i.programID == schedule.programID.Substring(0, 10)); + var imageIndex = images.FindIndex(i => i.ProgramId == schedule.ProgramId[..10]); if (imageIndex > -1) { - var programEntry = programDict[schedule.programID]; + var programEntry = programDict[schedule.ProgramId]; - var allImages = images[imageIndex].data ?? new List(); - var imagesWithText = allImages.Where(i => string.Equals(i.text, "yes", StringComparison.OrdinalIgnoreCase)); - var imagesWithoutText = allImages.Where(i => string.Equals(i.text, "no", StringComparison.OrdinalIgnoreCase)); + var allImages = images[imageIndex].Data ?? new List(); + var imagesWithText = allImages.Where(i => string.Equals(i.Text, "yes", StringComparison.OrdinalIgnoreCase)); + var imagesWithoutText = allImages.Where(i => string.Equals(i.Text, "no", StringComparison.OrdinalIgnoreCase)); const double DesiredAspect = 2.0 / 3; - programEntry.primaryImage = GetProgramImage(ApiUrl, imagesWithText, true, DesiredAspect) ?? + programEntry.PrimaryImage = GetProgramImage(ApiUrl, imagesWithText, true, DesiredAspect) ?? GetProgramImage(ApiUrl, allImages, true, DesiredAspect); const double WideAspect = 16.0 / 9; - programEntry.thumbImage = GetProgramImage(ApiUrl, imagesWithText, true, WideAspect); + programEntry.ThumbImage = GetProgramImage(ApiUrl, imagesWithText, true, WideAspect); // Don't supply the same image twice - if (string.Equals(programEntry.primaryImage, programEntry.thumbImage, StringComparison.Ordinal)) + if (string.Equals(programEntry.PrimaryImage, programEntry.ThumbImage, StringComparison.Ordinal)) { - programEntry.thumbImage = null; + programEntry.ThumbImage = null; } - programEntry.backdropImage = GetProgramImage(ApiUrl, imagesWithoutText, true, WideAspect); + programEntry.BackdropImage = GetProgramImage(ApiUrl, imagesWithoutText, true, WideAspect); // programEntry.bannerImage = GetProgramImage(ApiUrl, data, "Banner", false) ?? // GetProgramImage(ApiUrl, data, "Banner-L1", false) ?? @@ -176,15 +177,15 @@ namespace Emby.Server.Implementations.LiveTv.Listings } } - programsInfo.Add(GetProgram(channelId, schedule, programDict[schedule.programID])); + programsInfo.Add(GetProgram(channelId, schedule, programDict[schedule.ProgramId])); } return programsInfo; } - private static int GetSizeOrder(ScheduleDirect.ImageData image) + private static int GetSizeOrder(ImageDataDto image) { - if (int.TryParse(image.height, out int value)) + if (int.TryParse(image.Height, out int value)) { return value; } @@ -192,53 +193,53 @@ namespace Emby.Server.Implementations.LiveTv.Listings return 0; } - private static string GetChannelNumber(ScheduleDirect.Map map) + private static string GetChannelNumber(MapDto map) { - var channelNumber = map.logicalChannelNumber; + var channelNumber = map.LogicalChannelNumber; if (string.IsNullOrWhiteSpace(channelNumber)) { - channelNumber = map.channel; + channelNumber = map.Channel; } if (string.IsNullOrWhiteSpace(channelNumber)) { - channelNumber = map.atscMajor + "." + map.atscMinor; + channelNumber = map.AtscMajor + "." + map.AtscMinor; } return channelNumber.TrimStart('0'); } - private static bool IsMovie(ScheduleDirect.ProgramDetails programInfo) + private static bool IsMovie(ProgramDetailsDto programInfo) { - return string.Equals(programInfo.entityType, "movie", StringComparison.OrdinalIgnoreCase); + return string.Equals(programInfo.EntityType, "movie", StringComparison.OrdinalIgnoreCase); } - private ProgramInfo GetProgram(string channelId, ScheduleDirect.Program programInfo, ScheduleDirect.ProgramDetails details) + private ProgramInfo GetProgram(string channelId, ProgramDto programInfo, ProgramDetailsDto details) { - var startAt = GetDate(programInfo.airDateTime); - var endAt = startAt.AddSeconds(programInfo.duration); + var startAt = GetDate(programInfo.AirDateTime); + var endAt = startAt.AddSeconds(programInfo.Duration); var audioType = ProgramAudio.Stereo; - var programId = programInfo.programID ?? string.Empty; + var programId = programInfo.ProgramId ?? string.Empty; string newID = programId + "T" + startAt.Ticks + "C" + channelId; - if (programInfo.audioProperties != null) + if (programInfo.AudioProperties != null) { - if (programInfo.audioProperties.Exists(item => string.Equals(item, "atmos", StringComparison.OrdinalIgnoreCase))) + if (programInfo.AudioProperties.Exists(item => string.Equals(item, "atmos", StringComparison.OrdinalIgnoreCase))) { audioType = ProgramAudio.Atmos; } - else if (programInfo.audioProperties.Exists(item => string.Equals(item, "dd 5.1", StringComparison.OrdinalIgnoreCase))) + else if (programInfo.AudioProperties.Exists(item => string.Equals(item, "dd 5.1", StringComparison.OrdinalIgnoreCase))) { audioType = ProgramAudio.DolbyDigital; } - else if (programInfo.audioProperties.Exists(item => string.Equals(item, "dd", StringComparison.OrdinalIgnoreCase))) + else if (programInfo.AudioProperties.Exists(item => string.Equals(item, "dd", StringComparison.OrdinalIgnoreCase))) { audioType = ProgramAudio.DolbyDigital; } - else if (programInfo.audioProperties.Exists(item => string.Equals(item, "stereo", StringComparison.OrdinalIgnoreCase))) + else if (programInfo.AudioProperties.Exists(item => string.Equals(item, "stereo", StringComparison.OrdinalIgnoreCase))) { audioType = ProgramAudio.Stereo; } @@ -249,9 +250,9 @@ namespace Emby.Server.Implementations.LiveTv.Listings } string episodeTitle = null; - if (details.episodeTitle150 != null) + if (details.EpisodeTitle150 != null) { - episodeTitle = details.episodeTitle150; + episodeTitle = details.EpisodeTitle150; } var info = new ProgramInfo @@ -260,22 +261,22 @@ namespace Emby.Server.Implementations.LiveTv.Listings Id = newID, StartDate = startAt, EndDate = endAt, - Name = details.titles[0].title120 ?? "Unknown", + Name = details.Titles[0].Title120 ?? "Unknown", OfficialRating = null, CommunityRating = null, EpisodeTitle = episodeTitle, Audio = audioType, // IsNew = programInfo.@new ?? false, - IsRepeat = programInfo.@new == null, - IsSeries = string.Equals(details.entityType, "episode", StringComparison.OrdinalIgnoreCase), - ImageUrl = details.primaryImage, - ThumbImageUrl = details.thumbImage, - IsKids = string.Equals(details.audience, "children", StringComparison.OrdinalIgnoreCase), - IsSports = string.Equals(details.entityType, "sports", StringComparison.OrdinalIgnoreCase), + IsRepeat = programInfo.New == null, + IsSeries = string.Equals(details.EntityType, "episode", StringComparison.OrdinalIgnoreCase), + ImageUrl = details.PrimaryImage, + ThumbImageUrl = details.ThumbImage, + IsKids = string.Equals(details.Audience, "children", StringComparison.OrdinalIgnoreCase), + IsSports = string.Equals(details.EntityType, "sports", StringComparison.OrdinalIgnoreCase), IsMovie = IsMovie(details), - Etag = programInfo.md5, - IsLive = string.Equals(programInfo.liveTapeDelay, "live", StringComparison.OrdinalIgnoreCase), - IsPremiere = programInfo.premiere || (programInfo.isPremiereOrFinale ?? string.Empty).IndexOf("premiere", StringComparison.OrdinalIgnoreCase) != -1 + Etag = programInfo.Md5, + IsLive = string.Equals(programInfo.LiveTapeDelay, "live", StringComparison.OrdinalIgnoreCase), + IsPremiere = programInfo.Premiere || (programInfo.IsPremiereOrFinale ?? string.Empty).IndexOf("premiere", StringComparison.OrdinalIgnoreCase) != -1 }; var showId = programId; @@ -298,15 +299,15 @@ namespace Emby.Server.Implementations.LiveTv.Listings info.ShowId = showId; - if (programInfo.videoProperties != null) + if (programInfo.VideoProperties != null) { - info.IsHD = programInfo.videoProperties.Contains("hdtv", StringComparer.OrdinalIgnoreCase); - info.Is3D = programInfo.videoProperties.Contains("3d", StringComparer.OrdinalIgnoreCase); + info.IsHD = programInfo.VideoProperties.Contains("hdtv", StringComparer.OrdinalIgnoreCase); + info.Is3D = programInfo.VideoProperties.Contains("3d", StringComparer.OrdinalIgnoreCase); } - if (details.contentRating != null && details.contentRating.Count > 0) + if (details.ContentRating != null && details.ContentRating.Count > 0) { - info.OfficialRating = details.contentRating[0].code.Replace("TV", "TV-", StringComparison.Ordinal) + info.OfficialRating = details.ContentRating[0].Code.Replace("TV", "TV-", StringComparison.Ordinal) .Replace("--", "-", StringComparison.Ordinal); var invalid = new[] { "N/A", "Approved", "Not Rated", "Passed" }; @@ -316,15 +317,15 @@ namespace Emby.Server.Implementations.LiveTv.Listings } } - if (details.descriptions != null) + if (details.Descriptions != null) { - if (details.descriptions.description1000 != null && details.descriptions.description1000.Count > 0) + if (details.Descriptions.Description1000 != null && details.Descriptions.Description1000.Count > 0) { - info.Overview = details.descriptions.description1000[0].description; + info.Overview = details.Descriptions.Description1000[0].Description; } - else if (details.descriptions.description100 != null && details.descriptions.description100.Count > 0) + else if (details.Descriptions.Description100 != null && details.Descriptions.Description100.Count > 0) { - info.Overview = details.descriptions.description100[0].description; + info.Overview = details.Descriptions.Description100[0].Description; } } @@ -334,18 +335,18 @@ namespace Emby.Server.Implementations.LiveTv.Listings info.SeriesProviderIds[MetadataProvider.Zap2It.ToString()] = info.SeriesId; - if (details.metadata != null) + if (details.Metadata != null) { - foreach (var metadataProgram in details.metadata) + foreach (var metadataProgram in details.Metadata) { var gracenote = metadataProgram.Gracenote; if (gracenote != null) { - info.SeasonNumber = gracenote.season; + info.SeasonNumber = gracenote.Season; - if (gracenote.episode > 0) + if (gracenote.Episode > 0) { - info.EpisodeNumber = gracenote.episode; + info.EpisodeNumber = gracenote.Episode; } break; @@ -354,25 +355,25 @@ namespace Emby.Server.Implementations.LiveTv.Listings } } - if (!string.IsNullOrWhiteSpace(details.originalAirDate)) + if (!string.IsNullOrWhiteSpace(details.OriginalAirDate)) { - info.OriginalAirDate = DateTime.Parse(details.originalAirDate, CultureInfo.InvariantCulture); + info.OriginalAirDate = DateTime.Parse(details.OriginalAirDate, CultureInfo.InvariantCulture); info.ProductionYear = info.OriginalAirDate.Value.Year; } - if (details.movie != null) + if (details.Movie != null) { - if (!string.IsNullOrEmpty(details.movie.year) - && int.TryParse(details.movie.year, out int year)) + if (!string.IsNullOrEmpty(details.Movie.Year) + && int.TryParse(details.Movie.Year, out int year)) { info.ProductionYear = year; } } - if (details.genres != null) + if (details.Genres != null) { - info.Genres = details.genres.Where(g => !string.IsNullOrWhiteSpace(g)).ToList(); - info.IsNews = details.genres.Contains("news", StringComparer.OrdinalIgnoreCase); + info.Genres = details.Genres.Where(g => !string.IsNullOrWhiteSpace(g)).ToList(); + info.IsNews = details.Genres.Contains("news", StringComparer.OrdinalIgnoreCase); if (info.Genres.Contains("children", StringComparer.OrdinalIgnoreCase)) { @@ -395,11 +396,11 @@ namespace Emby.Server.Implementations.LiveTv.Listings return date; } - private string GetProgramImage(string apiUrl, IEnumerable images, bool returnDefaultImage, double desiredAspect) + private string GetProgramImage(string apiUrl, IEnumerable images, bool returnDefaultImage, double desiredAspect) { var match = images .OrderBy(i => Math.Abs(desiredAspect - GetAspectRatio(i))) - .ThenByDescending(GetSizeOrder) + .ThenByDescending(i => GetSizeOrder(i)) .FirstOrDefault(); if (match == null) @@ -407,7 +408,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings return null; } - var uri = match.uri; + var uri = match.Uri; if (string.IsNullOrWhiteSpace(uri)) { @@ -423,19 +424,19 @@ namespace Emby.Server.Implementations.LiveTv.Listings } } - private static double GetAspectRatio(ScheduleDirect.ImageData i) + private static double GetAspectRatio(ImageDataDto i) { int width = 0; int height = 0; - if (!string.IsNullOrWhiteSpace(i.width)) + if (!string.IsNullOrWhiteSpace(i.Width)) { - int.TryParse(i.width, out width); + _ = int.TryParse(i.Width, out width); } - if (!string.IsNullOrWhiteSpace(i.height)) + if (!string.IsNullOrWhiteSpace(i.Height)) { - int.TryParse(i.height, out height); + _ = int.TryParse(i.Height, out height); } if (height == 0 || width == 0) @@ -448,14 +449,14 @@ namespace Emby.Server.Implementations.LiveTv.Listings return result; } - private async Task> GetImageForPrograms( + private async Task> GetImageForPrograms( ListingsProviderInfo info, IReadOnlyList programIds, CancellationToken cancellationToken) { if (programIds.Count == 0) { - return new List(); + return new List(); } StringBuilder str = new StringBuilder("[", 1 + (programIds.Count * 13)); @@ -479,13 +480,13 @@ namespace Emby.Server.Implementations.LiveTv.Listings { using var innerResponse2 = await Send(message, true, info, cancellationToken).ConfigureAwait(false); await using var response = await innerResponse2.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); - return await JsonSerializer.DeserializeAsync>(response, _jsonOptions, cancellationToken).ConfigureAwait(false); + return await JsonSerializer.DeserializeAsync>(response, _jsonOptions, cancellationToken).ConfigureAwait(false); } catch (Exception ex) { _logger.LogError(ex, "Error getting image info from schedules direct"); - return new List(); + return new List(); } } @@ -508,18 +509,18 @@ namespace Emby.Server.Implementations.LiveTv.Listings using var httpResponse = await Send(options, false, info, cancellationToken).ConfigureAwait(false); await using var response = await httpResponse.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); - var root = await JsonSerializer.DeserializeAsync>(response, _jsonOptions, cancellationToken).ConfigureAwait(false); + var root = await JsonSerializer.DeserializeAsync>(response, _jsonOptions, cancellationToken).ConfigureAwait(false); if (root != null) { - foreach (ScheduleDirect.Headends headend in root) + foreach (HeadendsDto headend in root) { - foreach (ScheduleDirect.Lineup lineup in headend.lineups) + foreach (LineupDto lineup in headend.Lineups) { lineups.Add(new NameIdPair { - Name = string.IsNullOrWhiteSpace(lineup.name) ? lineup.lineup : lineup.name, - Id = lineup.uri.Substring(18) + Name = string.IsNullOrWhiteSpace(lineup.Name) ? lineup.Lineup : lineup.Name, + Id = lineup.Uri[18..] }); } } @@ -649,14 +650,14 @@ namespace Emby.Server.Implementations.LiveTv.Listings using var response = await Send(options, false, null, cancellationToken).ConfigureAwait(false); response.EnsureSuccessStatusCode(); await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); - var root = await JsonSerializer.DeserializeAsync(stream, _jsonOptions, cancellationToken).ConfigureAwait(false); - if (string.Equals(root.message, "OK", StringComparison.Ordinal)) + var root = await JsonSerializer.DeserializeAsync(stream, _jsonOptions, cancellationToken).ConfigureAwait(false); + if (string.Equals(root.Message, "OK", StringComparison.Ordinal)) { - _logger.LogInformation("Authenticated with Schedules Direct token: " + root.token); - return root.token; + _logger.LogInformation("Authenticated with Schedules Direct token: {Token}", root.Token); + return root.Token; } - throw new Exception("Could not authenticate with Schedules Direct Error: " + root.message); + throw new Exception("Could not authenticate with Schedules Direct Error: " + root.Message); } private async Task AddLineupToAccount(ListingsProviderInfo info, CancellationToken cancellationToken) @@ -705,9 +706,9 @@ namespace Emby.Server.Implementations.LiveTv.Listings httpResponse.EnsureSuccessStatusCode(); await using var stream = await httpResponse.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); using var response = httpResponse.Content; - var root = await JsonSerializer.DeserializeAsync(stream, _jsonOptions, cancellationToken).ConfigureAwait(false); + var root = await JsonSerializer.DeserializeAsync(stream, _jsonOptions, cancellationToken).ConfigureAwait(false); - return root.lineups.Any(i => string.Equals(info.ListingsId, i.lineup, StringComparison.OrdinalIgnoreCase)); + return root.Lineups.Any(i => string.Equals(info.ListingsId, i.Lineup, StringComparison.OrdinalIgnoreCase)); } catch (HttpRequestException ex) { @@ -777,35 +778,35 @@ namespace Emby.Server.Implementations.LiveTv.Listings using var httpResponse = await Send(options, true, info, cancellationToken).ConfigureAwait(false); await using var stream = await httpResponse.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); - var root = await JsonSerializer.DeserializeAsync(stream, _jsonOptions, cancellationToken).ConfigureAwait(false); - _logger.LogInformation("Found {ChannelCount} channels on the lineup on ScheduleDirect", root.map.Count); + var root = await JsonSerializer.DeserializeAsync(stream, _jsonOptions, cancellationToken).ConfigureAwait(false); + _logger.LogInformation("Found {ChannelCount} channels on the lineup on ScheduleDirect", root.Map.Count); _logger.LogInformation("Mapping Stations to Channel"); - var allStations = root.stations ?? new List(); + var allStations = root.Stations ?? new List(); - var map = root.map; + var map = root.Map; var list = new List(map.Count); foreach (var channel in map) { var channelNumber = GetChannelNumber(channel); - var station = allStations.Find(item => string.Equals(item.stationID, channel.stationID, StringComparison.OrdinalIgnoreCase)) - ?? new ScheduleDirect.Station + var station = allStations.Find(item => string.Equals(item.StationId, channel.StationId, StringComparison.OrdinalIgnoreCase)) + ?? new StationDto { - stationID = channel.stationID + StationId = channel.StationId }; var channelInfo = new ChannelInfo { - Id = station.stationID, - CallSign = station.callsign, + Id = station.StationId, + CallSign = station.Callsign, Number = channelNumber, - Name = string.IsNullOrWhiteSpace(station.name) ? channelNumber : station.name + Name = string.IsNullOrWhiteSpace(station.Name) ? channelNumber : station.Name }; - if (station.logo != null) + if (station.Logo != null) { - channelInfo.ImageUrl = station.logo.URL; + channelInfo.ImageUrl = station.Logo.Url; } list.Add(channelInfo); @@ -818,402 +819,5 @@ namespace Emby.Server.Implementations.LiveTv.Listings { return value.Replace(" ", string.Empty, StringComparison.Ordinal).Replace("-", string.Empty, StringComparison.Ordinal); } - - public class ScheduleDirect - { - public class Token - { - public int code { get; set; } - - public string message { get; set; } - - public string serverID { get; set; } - - public string token { get; set; } - } - - public class Lineup - { - public string lineup { get; set; } - - public string name { get; set; } - - public string transport { get; set; } - - public string location { get; set; } - - public string uri { get; set; } - } - - public class Lineups - { - public int code { get; set; } - - public string serverID { get; set; } - - public string datetime { get; set; } - - public List lineups { get; set; } - } - - public class Headends - { - public string headend { get; set; } - - public string transport { get; set; } - - public string location { get; set; } - - public List lineups { get; set; } - } - - public class Map - { - public string stationID { get; set; } - - public string channel { get; set; } - - public string logicalChannelNumber { get; set; } - - public int uhfVhf { get; set; } - - public int atscMajor { get; set; } - - public int atscMinor { get; set; } - } - - public class Broadcaster - { - public string city { get; set; } - - public string state { get; set; } - - public string postalcode { get; set; } - - public string country { get; set; } - } - - public class Logo - { - public string URL { get; set; } - - public int height { get; set; } - - public int width { get; set; } - - public string md5 { get; set; } - } - - public class Station - { - public string stationID { get; set; } - - public string name { get; set; } - - public string callsign { get; set; } - - public List broadcastLanguage { get; set; } - - public List descriptionLanguage { get; set; } - - public Broadcaster broadcaster { get; set; } - - public string affiliate { get; set; } - - public Logo logo { get; set; } - - public bool? isCommercialFree { get; set; } - } - - public class Metadata - { - public string lineup { get; set; } - - public string modified { get; set; } - - public string transport { get; set; } - } - - public class Channel - { - public List map { get; set; } - - public List stations { get; set; } - - public Metadata metadata { get; set; } - } - - public class RequestScheduleForChannel - { - public string stationID { get; set; } - - public List date { get; set; } - } - - public class Rating - { - public string body { get; set; } - - public string code { get; set; } - } - - public class Multipart - { - public int partNumber { get; set; } - - public int totalParts { get; set; } - } - - public class Program - { - public string programID { get; set; } - - public string airDateTime { get; set; } - - public int duration { get; set; } - - public string md5 { get; set; } - - public List audioProperties { get; set; } - - public List videoProperties { get; set; } - - public List ratings { get; set; } - - public bool? @new { get; set; } - - public Multipart multipart { get; set; } - - public string liveTapeDelay { get; set; } - - public bool premiere { get; set; } - - public bool repeat { get; set; } - - public string isPremiereOrFinale { get; set; } - } - - public class MetadataSchedule - { - public string modified { get; set; } - - public string md5 { get; set; } - - public string startDate { get; set; } - - public string endDate { get; set; } - - public int days { get; set; } - } - - public class Day - { - public string stationID { get; set; } - - public List programs { get; set; } - - public MetadataSchedule metadata { get; set; } - - public Day() - { - programs = new List(); - } - } - - public class Title - { - public string title120 { get; set; } - } - - public class EventDetails - { - public string subType { get; set; } - } - - public class Description100 - { - public string descriptionLanguage { get; set; } - - public string description { get; set; } - } - - public class Description1000 - { - public string descriptionLanguage { get; set; } - - public string description { get; set; } - } - - public class DescriptionsProgram - { - public List description100 { get; set; } - - public List description1000 { get; set; } - } - - public class Gracenote - { - public int season { get; set; } - - public int episode { get; set; } - } - - public class MetadataPrograms - { - public Gracenote Gracenote { get; set; } - } - - public class ContentRating - { - public string body { get; set; } - - public string code { get; set; } - } - - public class Cast - { - public string billingOrder { get; set; } - - public string role { get; set; } - - public string nameId { get; set; } - - public string personId { get; set; } - - public string name { get; set; } - - public string characterName { get; set; } - } - - public class Crew - { - public string billingOrder { get; set; } - - public string role { get; set; } - - public string nameId { get; set; } - - public string personId { get; set; } - - public string name { get; set; } - } - - public class QualityRating - { - public string ratingsBody { get; set; } - - public string rating { get; set; } - - public string minRating { get; set; } - - public string maxRating { get; set; } - - public string increment { get; set; } - } - - public class Movie - { - public string year { get; set; } - - public int duration { get; set; } - - public List qualityRating { get; set; } - } - - public class Recommendation - { - public string programID { get; set; } - - public string title120 { get; set; } - } - - public class ProgramDetails - { - public string audience { get; set; } - - public string programID { get; set; } - - public List titles { get; set; } - - public EventDetails eventDetails { get; set; } - - public DescriptionsProgram descriptions { get; set; } - - public string originalAirDate { get; set; } - - public List<string> genres { get; set; } - - public string episodeTitle150 { get; set; } - - public List<MetadataPrograms> metadata { get; set; } - - public List<ContentRating> contentRating { get; set; } - - public List<Cast> cast { get; set; } - - public List<Crew> crew { get; set; } - - public string entityType { get; set; } - - public string showType { get; set; } - - public bool hasImageArtwork { get; set; } - - public string primaryImage { get; set; } - - public string thumbImage { get; set; } - - public string backdropImage { get; set; } - - public string bannerImage { get; set; } - - public string imageID { get; set; } - - public string md5 { get; set; } - - public List<string> contentAdvisory { get; set; } - - public Movie movie { get; set; } - - public List<Recommendation> recommendations { get; set; } - } - - public class Caption - { - public string content { get; set; } - - public string lang { get; set; } - } - - public class ImageData - { - public string width { get; set; } - - public string height { get; set; } - - public string uri { get; set; } - - public string size { get; set; } - - public string aspect { get; set; } - - public string category { get; set; } - - public string text { get; set; } - - public string primary { get; set; } - - public string tier { get; set; } - - public Caption caption { get; set; } - } - - public class ShowImages - { - public string programID { get; set; } - - public List<ImageData> data { get; set; } - } - } } } diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/BroadcasterDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/BroadcasterDto.cs new file mode 100644 index 000000000..b881b307c --- /dev/null +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/BroadcasterDto.cs @@ -0,0 +1,36 @@ +#nullable disable + +using System.Text.Json.Serialization; + +namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos +{ + /// <summary> + /// Broadcaster dto. + /// </summary> + public class BroadcasterDto + { + /// <summary> + /// Gets or sets the city. + /// </summary> + [JsonPropertyName("city")] + public string City { get; set; } + + /// <summary> + /// Gets or sets the state. + /// </summary> + [JsonPropertyName("state")] + public string State { get; set; } + + /// <summary> + /// Gets or sets the postal code. + /// </summary> + [JsonPropertyName("postalCode")] + public string Postalcode { get; set; } + + /// <summary> + /// Gets or sets the country. + /// </summary> + [JsonPropertyName("country")] + public string Country { get; set; } + } +} diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/CaptionDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/CaptionDto.cs new file mode 100644 index 000000000..96b67d1eb --- /dev/null +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/CaptionDto.cs @@ -0,0 +1,24 @@ +#nullable disable + +using System.Text.Json.Serialization; + +namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos +{ + /// <summary> + /// Caption dto. + /// </summary> + public class CaptionDto + { + /// <summary> + /// Gets or sets the content. + /// </summary> + [JsonPropertyName("content")] + public string Content { get; set; } + + /// <summary> + /// Gets or sets the lang. + /// </summary> + [JsonPropertyName("lang")] + public string Lang { get; set; } + } +} diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/CastDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/CastDto.cs new file mode 100644 index 000000000..dac6f5f3e --- /dev/null +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/CastDto.cs @@ -0,0 +1,48 @@ +#nullable disable + +using System.Text.Json.Serialization; + +namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos +{ + /// <summary> + /// Cast dto. + /// </summary> + public class CastDto + { + /// <summary> + /// Gets or sets the billing order. + /// </summary> + [JsonPropertyName("billingOrder")] + public string BillingOrder { get; set; } + + /// <summary> + /// Gets or sets the role. + /// </summary> + [JsonPropertyName("role")] + public string Role { get; set; } + + /// <summary> + /// Gets or sets the name id. + /// </summary> + [JsonPropertyName("nameId")] + public string NameId { get; set; } + + /// <summary> + /// Gets or sets the person id. + /// </summary> + [JsonPropertyName("personId")] + public string PersonId { get; set; } + + /// <summary> + /// Gets or sets the name. + /// </summary> + [JsonPropertyName("name")] + public string Name { get; set; } + + /// <summary> + /// Gets or sets the character name. + /// </summary> + [JsonPropertyName("characterName")] + public string CharacterName { get; set; } + } +} diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ChannelDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ChannelDto.cs new file mode 100644 index 000000000..8c9c2c1fc --- /dev/null +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ChannelDto.cs @@ -0,0 +1,31 @@ +#nullable disable + +using System.Collections.Generic; +using System.Text.Json.Serialization; + +namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos +{ + /// <summary> + /// Channel dto. + /// </summary> + public class ChannelDto + { + /// <summary> + /// Gets or sets the list of maps. + /// </summary> + [JsonPropertyName("map")] + public List<MapDto> Map { get; set; } + + /// <summary> + /// Gets or sets the list of stations. + /// </summary> + [JsonPropertyName("stations")] + public List<StationDto> Stations { get; set; } + + /// <summary> + /// Gets or sets the metadata. + /// </summary> + [JsonPropertyName("metadata")] + public MetadataDto Metadata { get; set; } + } +} diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ContentRatingDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ContentRatingDto.cs new file mode 100644 index 000000000..135b5bb08 --- /dev/null +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ContentRatingDto.cs @@ -0,0 +1,24 @@ +#nullable disable + +using System.Text.Json.Serialization; + +namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos +{ + /// <summary> + /// Content rating dto. + /// </summary> + public class ContentRatingDto + { + /// <summary> + /// Gets or sets the body. + /// </summary> + [JsonPropertyName("body")] + public string Body { get; set; } + + /// <summary> + /// Gets or sets the code. + /// </summary> + [JsonPropertyName("code")] + public string Code { get; set; } + } +} diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/CrewDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/CrewDto.cs new file mode 100644 index 000000000..82d1001c8 --- /dev/null +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/CrewDto.cs @@ -0,0 +1,42 @@ +#nullable disable + +using System.Text.Json.Serialization; + +namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos +{ + /// <summary> + /// Crew dto. + /// </summary> + public class CrewDto + { + /// <summary> + /// Gets or sets the billing order. + /// </summary> + [JsonPropertyName("billingOrder")] + public string BillingOrder { get; set; } + + /// <summary> + /// Gets or sets the role. + /// </summary> + [JsonPropertyName("role")] + public string Role { get; set; } + + /// <summary> + /// Gets or sets the name id. + /// </summary> + [JsonPropertyName("nameId")] + public string NameId { get; set; } + + /// <summary> + /// Gets or sets the person id. + /// </summary> + [JsonPropertyName("personId")] + public string PersonId { get; set; } + + /// <summary> + /// Gets or sets the name. + /// </summary> + [JsonPropertyName("name")] + public string Name { get; set; } + } +} diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/DayDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/DayDto.cs new file mode 100644 index 000000000..68876b068 --- /dev/null +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/DayDto.cs @@ -0,0 +1,39 @@ +#nullable disable + +using System.Collections.Generic; +using System.Text.Json.Serialization; + +namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos +{ + /// <summary> + /// Day dto. + /// </summary> + public class DayDto + { + /// <summary> + /// Initializes a new instance of the <see cref="DayDto"/> class. + /// </summary> + public DayDto() + { + Programs = new List<ProgramDto>(); + } + + /// <summary> + /// Gets or sets the station id. + /// </summary> + [JsonPropertyName("stationID")] + public string StationId { get; set; } + + /// <summary> + /// Gets or sets the list of programs. + /// </summary> + [JsonPropertyName("programs")] + public List<ProgramDto> Programs { get; set; } + + /// <summary> + /// Gets or sets the metadata schedule. + /// </summary> + [JsonPropertyName("metadata")] + public MetadataScheduleDto Metadata { get; set; } + } +} diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/Description1000Dto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/Description1000Dto.cs new file mode 100644 index 000000000..d3e6ff393 --- /dev/null +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/Description1000Dto.cs @@ -0,0 +1,24 @@ +#nullable disable + +using System.Text.Json.Serialization; + +namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos +{ + /// <summary> + /// Description 1_000 dto. + /// </summary> + public class Description1000Dto + { + /// <summary> + /// Gets or sets the description language. + /// </summary> + [JsonPropertyName("descriptionLanguage")] + public string DescriptionLanguage { get; set; } + + /// <summary> + /// Gets or sets the description. + /// </summary> + [JsonPropertyName("description")] + public string Description { get; set; } + } +} diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/Description100Dto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/Description100Dto.cs new file mode 100644 index 000000000..04360266c --- /dev/null +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/Description100Dto.cs @@ -0,0 +1,24 @@ +#nullable disable + +using System.Text.Json.Serialization; + +namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos +{ + /// <summary> + /// Description 100 dto. + /// </summary> + public class Description100Dto + { + /// <summary> + /// Gets or sets the description language. + /// </summary> + [JsonPropertyName("descriptionLanguage")] + public string DescriptionLanguage { get; set; } + + /// <summary> + /// Gets or sets the description. + /// </summary> + [JsonPropertyName("description")] + public string Description { get; set; } + } +} diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/DescriptionsProgramDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/DescriptionsProgramDto.cs new file mode 100644 index 000000000..3af36ae96 --- /dev/null +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/DescriptionsProgramDto.cs @@ -0,0 +1,25 @@ +#nullable disable + +using System.Collections.Generic; +using System.Text.Json.Serialization; + +namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos +{ + /// <summary> + /// Descriptions program dto. + /// </summary> + public class DescriptionsProgramDto + { + /// <summary> + /// Gets or sets the list of description 100. + /// </summary> + [JsonPropertyName("description100")] + public List<Description100Dto> Description100 { get; set; } + + /// <summary> + /// Gets or sets the list of description1000. + /// </summary> + [JsonPropertyName("description1000")] + public List<Description1000Dto> Description1000 { get; set; } + } +} diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/EventDetailsDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/EventDetailsDto.cs new file mode 100644 index 000000000..c3b2bd9c1 --- /dev/null +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/EventDetailsDto.cs @@ -0,0 +1,18 @@ +#nullable disable + +using System.Text.Json.Serialization; + +namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos +{ + /// <summary> + /// Event details dto. + /// </summary> + public class EventDetailsDto + { + /// <summary> + /// Gets or sets the sub type. + /// </summary> + [JsonPropertyName("subType")] + public string SubType { get; set; } + } +} diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/GracenoteDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/GracenoteDto.cs new file mode 100644 index 000000000..3d8bea362 --- /dev/null +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/GracenoteDto.cs @@ -0,0 +1,24 @@ +#nullable disable + +using System.Text.Json.Serialization; + +namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos +{ + /// <summary> + /// Gracenote dto. + /// </summary> + public class GracenoteDto + { + /// <summary> + /// Gets or sets the season. + /// </summary> + [JsonPropertyName("season")] + public int Season { get; set; } + + /// <summary> + /// Gets or sets the episode. + /// </summary> + [JsonPropertyName("episode")] + public int Episode { get; set; } + } +} diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/HeadendsDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/HeadendsDto.cs new file mode 100644 index 000000000..1fb3decb2 --- /dev/null +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/HeadendsDto.cs @@ -0,0 +1,37 @@ +#nullable disable + +using System.Collections.Generic; +using System.Text.Json.Serialization; + +namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos +{ + /// <summary> + /// Headends dto. + /// </summary> + public class HeadendsDto + { + /// <summary> + /// Gets or sets the headend. + /// </summary> + [JsonPropertyName("headend")] + public string Headend { get; set; } + + /// <summary> + /// Gets or sets the transport. + /// </summary> + [JsonPropertyName("transport")] + public string Transport { get; set; } + + /// <summary> + /// Gets or sets the location. + /// </summary> + [JsonPropertyName("location")] + public string Location { get; set; } + + /// <summary> + /// Gets or sets the list of lineups. + /// </summary> + [JsonPropertyName("lineups")] + public List<LineupDto> Lineups { get; set; } + } +} diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ImageDataDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ImageDataDto.cs new file mode 100644 index 000000000..b80ac624c --- /dev/null +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ImageDataDto.cs @@ -0,0 +1,69 @@ +#nullable disable + +using System.Text.Json.Serialization; + +namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos +{ + public class ImageDataDto + { + /// <summary> + /// Gets or sets the width. + /// </summary> + [JsonPropertyName("width")] + public string Width { get; set; } + + /// <summary> + /// Gets or sets the height. + /// </summary> + [JsonPropertyName("height")] + public string Height { get; set; } + + /// <summary> + /// Gets or sets the uri. + /// </summary> + [JsonPropertyName("uri")] + public string Uri { get; set; } + + /// <summary> + /// Gets or sets the size. + /// </summary> + [JsonPropertyName("size")] + public string Size { get; set; } + + /// <summary> + /// Gets or sets the aspect. + /// </summary> + [JsonPropertyName("aspect")] + public string aspect { get; set; } + + /// <summary> + /// Gets or sets the category. + /// </summary> + [JsonPropertyName("category")] + public string Category { get; set; } + + /// <summary> + /// Gets or sets the text. + /// </summary> + [JsonPropertyName("text")] + public string Text { get; set; } + + /// <summary> + /// Gets or sets the primary. + /// </summary> + [JsonPropertyName("primary")] + public string Primary { get; set; } + + /// <summary> + /// Gets or sets the tier. + /// </summary> + [JsonPropertyName("tier")] + public string Tier { get; set; } + + /// <summary> + /// Gets or sets the caption. + /// </summary> + [JsonPropertyName("caption")] + public CaptionDto Caption { get; set; } + } +} diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/LineupDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/LineupDto.cs new file mode 100644 index 000000000..b8f27a8ac --- /dev/null +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/LineupDto.cs @@ -0,0 +1,42 @@ +#nullable disable + +using System.Text.Json.Serialization; + +namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos +{ + /// <summary> + /// The lineup dto. + /// </summary> + public class LineupDto + { + /// <summary> + /// Gets or sets the linup. + /// </summary> + [JsonPropertyName("lineup")] + public string Lineup { get; set; } + + /// <summary> + /// Gets or sets the lineup name. + /// </summary> + [JsonPropertyName("name")] + public string Name { get; set; } + + /// <summary> + /// Gets or sets the transport. + /// </summary> + [JsonPropertyName("transport.")] + public string Transport { get; set; } + + /// <summary> + /// Gets or sets the location. + /// </summary> + [JsonPropertyName("location")] + public string Location { get; set; } + + /// <summary> + /// Gets or sets the uri. + /// </summary> + [JsonPropertyName("uri")] + public string Uri { get; set; } + } +} diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/LineupsDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/LineupsDto.cs new file mode 100644 index 000000000..15139ba3b --- /dev/null +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/LineupsDto.cs @@ -0,0 +1,37 @@ +#nullable disable + +using System.Collections.Generic; +using System.Text.Json.Serialization; + +namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos +{ + /// <summary> + /// Lineups dto. + /// </summary> + public class LineupsDto + { + /// <summary> + /// Gets or sets the response code. + /// </summary> + [JsonPropertyName("code")] + public int Code { get; set; } + + /// <summary> + /// Gets or sets the server id. + /// </summary> + [JsonPropertyName("serverID")] + public string ServerId { get; set; } + + /// <summary> + /// Gets or sets the datetime. + /// </summary> + [JsonPropertyName("datetime")] + public string Datetime { get; set; } + + /// <summary> + /// Gets or sets the list of lineups. + /// </summary> + [JsonPropertyName("lineups")] + public List<LineupDto> Lineups { get; set; } + } +} diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/LogoDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/LogoDto.cs new file mode 100644 index 000000000..7b235ed7f --- /dev/null +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/LogoDto.cs @@ -0,0 +1,36 @@ +#nullable disable + +using System.Text.Json.Serialization; + +namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos +{ + /// <summary> + /// Logo dto. + /// </summary> + public class LogoDto + { + /// <summary> + /// Gets or sets the url. + /// </summary> + [JsonPropertyName("URL")] + public string Url { get; set; } + + /// <summary> + /// Gets or sets the height. + /// </summary> + [JsonPropertyName("height")] + public int Height { get; set; } + + /// <summary> + /// Gets or sets the width. + /// </summary> + [JsonPropertyName("width")] + public int Width { get; set; } + + /// <summary> + /// Gets or sets the md5. + /// </summary> + [JsonPropertyName("md5")] + public string Md5 { get; set; } + } +} diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MapDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MapDto.cs new file mode 100644 index 000000000..8d45e8fff --- /dev/null +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MapDto.cs @@ -0,0 +1,48 @@ +#nullable disable + +using System.Text.Json.Serialization; + +namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos +{ + /// <summary> + /// Map dto. + /// </summary> + public class MapDto + { + /// <summary> + /// Gets or sets the station id. + /// </summary> + [JsonPropertyName("stationID")] + public string StationId { get; set; } + + /// <summary> + /// Gets or sets the channel. + /// </summary> + [JsonPropertyName("channel")] + public string Channel { get; set; } + + /// <summary> + /// Gets or sets the logical channel number. + /// </summary> + [JsonPropertyName("logicalChannelNumber")] + public string LogicalChannelNumber { get; set; } + + /// <summary> + /// Gets or sets the uhfvhf. + /// </summary> + [JsonPropertyName("uhfVhf")] + public int UhfVhf { get; set; } + + /// <summary> + /// Gets or sets the astc major. + /// </summary> + [JsonPropertyName("astcMajor")] + public int AtscMajor { get; set; } + + /// <summary> + /// Gets or sets the astc minor. + /// </summary> + [JsonPropertyName("astcMinor")] + public int AtscMinor { get; set; } + } +} diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MetadataDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MetadataDto.cs new file mode 100644 index 000000000..5a3893a35 --- /dev/null +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MetadataDto.cs @@ -0,0 +1,30 @@ +#nullable disable + +using System.Text.Json.Serialization; + +namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos +{ + /// <summary> + /// Metadata dto. + /// </summary> + public class MetadataDto + { + /// <summary> + /// Gets or sets the linup. + /// </summary> + [JsonPropertyName("lineup")] + public string Lineup { get; set; } + + /// <summary> + /// Gets or sets the modified timestamp. + /// </summary> + [JsonPropertyName("modified")] + public string Modified { get; set; } + + /// <summary> + /// Gets or sets the transport. + /// </summary> + [JsonPropertyName("transport")] + public string Transport { get; set; } + } +} diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MetadataProgramsDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MetadataProgramsDto.cs new file mode 100644 index 000000000..4057e9802 --- /dev/null +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MetadataProgramsDto.cs @@ -0,0 +1,18 @@ +#nullable disable + +using System.Text.Json.Serialization; + +namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos +{ + /// <summary> + /// Metadata programs dto. + /// </summary> + public class MetadataProgramsDto + { + /// <summary> + /// Gets or sets the gracenote object. + /// </summary> + [JsonPropertyName("gracenote")] + public GracenoteDto Gracenote { get; set; } + } +} diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MetadataScheduleDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MetadataScheduleDto.cs new file mode 100644 index 000000000..4979296da --- /dev/null +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MetadataScheduleDto.cs @@ -0,0 +1,42 @@ +#nullable disable + +using System.Text.Json.Serialization; + +namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos +{ + /// <summary> + /// Metadata schedule dto. + /// </summary> + public class MetadataScheduleDto + { + /// <summary> + /// Gets or sets the modified timestamp. + /// </summary> + [JsonPropertyName("modified")] + public string Modified { get; set; } + + /// <summary> + /// Gets or sets the md5. + /// </summary> + [JsonPropertyName("md5")] + public string Md5 { get; set; } + + /// <summary> + /// Gets or sets the start date. + /// </summary> + [JsonPropertyName("startDate")] + public string StartDate { get; set; } + + /// <summary> + /// Gets or sets the end date. + /// </summary> + [JsonPropertyName("endDate")] + public string EndDate { get; set; } + + /// <summary> + /// Gets or sets the days count. + /// </summary> + [JsonPropertyName("days")] + public int Days { get; set; } + } +} diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MovieDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MovieDto.cs new file mode 100644 index 000000000..48d731d89 --- /dev/null +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MovieDto.cs @@ -0,0 +1,31 @@ +#nullable disable + +using System.Collections.Generic; +using System.Text.Json.Serialization; + +namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos +{ + /// <summary> + /// Movie dto. + /// </summary> + public class MovieDto + { + /// <summary> + /// Gets or sets the year. + /// </summary> + [JsonPropertyName("year")] + public string Year { get; set; } + + /// <summary> + /// Gets or sets the duration. + /// </summary> + [JsonPropertyName("duration")] + public int Duration { get; set; } + + /// <summary> + /// Gets or sets the list of quality rating. + /// </summary> + [JsonPropertyName("qualityRating")] + public List<QualityRatingDto> QualityRating { get; set; } + } +} diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MultipartDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MultipartDto.cs new file mode 100644 index 000000000..42eddfff2 --- /dev/null +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MultipartDto.cs @@ -0,0 +1,24 @@ +#nullable disable + +using System.Text.Json.Serialization; + +namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos +{ + /// <summary> + /// Multipart dto. + /// </summary> + public class MultipartDto + { + /// <summary> + /// Gets or sets the part number. + /// </summary> + [JsonPropertyName("partNumber")] + public int PartNumber { get; set; } + + /// <summary> + /// Gets or sets the total parts. + /// </summary> + [JsonPropertyName("totalParts")] + public int TotalParts { get; set; } + } +} diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ProgramDetailsDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ProgramDetailsDto.cs new file mode 100644 index 000000000..a84c47c12 --- /dev/null +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ProgramDetailsDto.cs @@ -0,0 +1,157 @@ +#nullable disable + +using System.Collections.Generic; +using System.Text.Json.Serialization; + +namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos +{ + /// <summary> + /// Program details dto. + /// </summary> + public class ProgramDetailsDto + { + /// <summary> + /// Gets or sets the audience. + /// </summary> + [JsonPropertyName("audience")] + public string Audience { get; set; } + + /// <summary> + /// Gets or sets the program id. + /// </summary> + [JsonPropertyName("programID")] + public string ProgramId { get; set; } + + /// <summary> + /// Gets or sets the list of titles. + /// </summary> + [JsonPropertyName("titles")] + public List<TitleDto> Titles { get; set; } + + /// <summary> + /// Gets or sets the event details object. + /// </summary> + [JsonPropertyName("eventDetails")] + public EventDetailsDto EventDetails { get; set; } + + /// <summary> + /// Gets or sets the descriptions. + /// </summary> + [JsonPropertyName("descriptions")] + public DescriptionsProgramDto Descriptions { get; set; } + + /// <summary> + /// Gets or sets the original air date. + /// </summary> + [JsonPropertyName("originalAirDate")] + public string OriginalAirDate { get; set; } + + /// <summary> + /// Gets or sets the list of genres. + /// </summary> + [JsonPropertyName("genres")] + public List<string> Genres { get; set; } + + /// <summary> + /// Gets or sets the episode title. + /// </summary> + [JsonPropertyName("episodeTitle150")] + public string EpisodeTitle150 { get; set; } + + /// <summary> + /// Gets or sets the list of metadata. + /// </summary> + [JsonPropertyName("metadata")] + public List<MetadataProgramsDto> Metadata { get; set; } + + /// <summary> + /// Gets or sets the list of content raitings. + /// </summary> + [JsonPropertyName("contentRating")] + public List<ContentRatingDto> ContentRating { get; set; } + + /// <summary> + /// Gets or sets the list of cast. + /// </summary> + [JsonPropertyName("cast")] + public List<CastDto> Cast { get; set; } + + /// <summary> + /// Gets or sets the list of crew. + /// </summary> + [JsonPropertyName("crew")] + public List<CrewDto> Crew { get; set; } + + /// <summary> + /// Gets or sets the entity type. + /// </summary> + [JsonPropertyName("entityType")] + public string EntityType { get; set; } + + /// <summary> + /// Gets or sets the show type. + /// </summary> + [JsonPropertyName("showType")] + public string ShowType { get; set; } + + /// <summary> + /// Gets or sets a value indicating whether there is image artwork. + /// </summary> + [JsonPropertyName("hasImageArtwork")] + public bool HasImageArtwork { get; set; } + + /// <summary> + /// Gets or sets the primary image. + /// </summary> + [JsonPropertyName("primaryImage")] + public string PrimaryImage { get; set; } + + /// <summary> + /// Gets or sets the thumb image. + /// </summary> + [JsonPropertyName("thumbImage")] + public string ThumbImage { get; set; } + + /// <summary> + /// Gets or sets the backdrop image. + /// </summary> + [JsonPropertyName("backdropImage")] + public string BackdropImage { get; set; } + + /// <summary> + /// Gets or sets the banner image. + /// </summary> + [JsonPropertyName("bannerImage")] + public string BannerImage { get; set; } + + /// <summary> + /// Gets or sets the image id. + /// </summary> + [JsonPropertyName("imageID")] + public string ImageId { get; set; } + + /// <summary> + /// Gets or sets the md5. + /// </summary> + [JsonPropertyName("md5")] + public string Md5 { get; set; } + + /// <summary> + /// Gets or sets the list of content advisory. + /// </summary> + [JsonPropertyName("contentAdvisory")] + public List<string> ContentAdvisory { get; set; } + + /// <summary> + /// Gets or sets the movie object. + /// </summary> + [JsonPropertyName("movie")] + public MovieDto Movie { get; set; } + + /// <summary> + /// Gets or sets the list of recommendations. + /// </summary> + [JsonPropertyName("recommendations")] + public List<RecommendationDto> Recommendations { get; set; } + } +} diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ProgramDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ProgramDto.cs new file mode 100644 index 000000000..ad5389100 --- /dev/null +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ProgramDto.cs @@ -0,0 +1,91 @@ +#nullable disable + +using System.Collections.Generic; +using System.Text.Json.Serialization; + +namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos +{ + /// <summary> + /// Program dto. + /// </summary> + public class ProgramDto + { + /// <summary> + /// Gets or sets the program id. + /// </summary> + [JsonPropertyName("programID")] + public string ProgramId { get; set; } + + /// <summary> + /// Gets or sets the air date time. + /// </summary> + [JsonPropertyName("airDateTime")] + public string AirDateTime { get; set; } + + /// <summary> + /// Gets or sets the duration. + /// </summary> + [JsonPropertyName("duration")] + public int Duration { get; set; } + + /// <summary> + /// Gets or sets the md5. + /// </summary> + [JsonPropertyName("md5")] + public string Md5 { get; set; } + + /// <summary> + /// Gets or sets the list of audio properties. + /// </summary> + [JsonPropertyName("audioProperties")] + public List<string> AudioProperties { get; set; } + + /// <summary> + /// Gets or sets the list of video properties. + /// </summary> + [JsonPropertyName("videoProperties")] + public List<string> VideoProperties { get; set; } + + /// <summary> + /// Gets or sets the list of ratings. + /// </summary> + [JsonPropertyName("ratings")] + public List<RatingDto> Ratings { get; set; } + + /// <summary> + /// Gets or sets a value indicating whether this program is new. + /// </summary> + [JsonPropertyName("new")] + public bool? New { get; set; } + + /// <summary> + /// Gets or sets the multipart object. + /// </summary> + [JsonPropertyName("multipart")] + public MultipartDto Multipart { get; set; } + + /// <summary> + /// Gets or sets the live tape delay. + /// </summary> + [JsonPropertyName("liveTapeDelay")] + public string LiveTapeDelay { get; set; } + + /// <summary> + /// Gets or sets a value indicating whether this is the premiere. + /// </summary> + [JsonPropertyName("premiere")] + public bool Premiere { get; set; } + + /// <summary> + /// Gets or sets a value indicating whether this is a repeat. + /// </summary> + [JsonPropertyName("repeat")] + public bool Repeat { get; set; } + + /// <summary> + /// Gets or sets the premiere or finale. + /// </summary> + [JsonPropertyName("isPremiereOrFinale")] + public string IsPremiereOrFinale { get; set; } + } +} diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/QualityRatingDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/QualityRatingDto.cs new file mode 100644 index 000000000..5cd0a7459 --- /dev/null +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/QualityRatingDto.cs @@ -0,0 +1,42 @@ +#nullable disable + +using System.Text.Json.Serialization; + +namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos +{ + /// <summary> + /// Quality rating dto. + /// </summary> + public class QualityRatingDto + { + /// <summary> + /// Gets or sets the ratings body. + /// </summary> + [JsonPropertyName("ratingsBody")] + public string RatingsBody { get; set; } + + /// <summary> + /// Gets or sets the rating. + /// </summary> + [JsonPropertyName("rating")] + public string Rating { get; set; } + + /// <summary> + /// Gets or sets the min rating. + /// </summary> + [JsonPropertyName("minRating")] + public string MinRating { get; set; } + + /// <summary> + /// Gets or sets the max rating. + /// </summary> + [JsonPropertyName("maxRating")] + public string MaxRating { get; set; } + + /// <summary> + /// Gets or sets the increment. + /// </summary> + [JsonPropertyName("increment")] + public string Increment { get; set; } + } +} diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/RatingDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/RatingDto.cs new file mode 100644 index 000000000..948b83144 --- /dev/null +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/RatingDto.cs @@ -0,0 +1,24 @@ +#nullable disable + +using System.Text.Json.Serialization; + +namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos +{ + /// <summary> + /// Rating dto. + /// </summary> + public class RatingDto + { + /// <summary> + /// Gets or sets the body. + /// </summary> + [JsonPropertyName("body")] + public string Body { get; set; } + + /// <summary> + /// Gets or sets the code. + /// </summary> + [JsonPropertyName("code")] + public string Code { get; set; } + } +} diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/RecommendationDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/RecommendationDto.cs new file mode 100644 index 000000000..1308f45ce --- /dev/null +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/RecommendationDto.cs @@ -0,0 +1,24 @@ +#nullable disable + +using System.Text.Json.Serialization; + +namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos +{ + /// <summary> + /// Recommendation dto. + /// </summary> + public class RecommendationDto + { + /// <summary> + /// Gets or sets the program id. + /// </summary> + [JsonPropertyName("programID")] + public string ProgramId { get; set; } + + /// <summary> + /// Gets or sets the title. + /// </summary> + [JsonPropertyName("title120")] + public string Title120 { get; set; } + } +} diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/RequestScheduleForChannelDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/RequestScheduleForChannelDto.cs new file mode 100644 index 000000000..fb7a31ac8 --- /dev/null +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/RequestScheduleForChannelDto.cs @@ -0,0 +1,25 @@ +#nullable disable + +using System.Collections.Generic; +using System.Text.Json.Serialization; + +namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos +{ + /// <summary> + /// Request schedule for channel dto. + /// </summary> + public class RequestScheduleForChannelDto + { + /// <summary> + /// Gets or sets the station id. + /// </summary> + [JsonPropertyName("stationID")] + public string StationId { get; set; } + + /// <summary> + /// Gets or sets the list of dates. + /// </summary> + [JsonPropertyName("date")] + public List<string> Date { get; set; } + } +} diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ShowImagesDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ShowImagesDto.cs new file mode 100644 index 000000000..332edf7c3 --- /dev/null +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ShowImagesDto.cs @@ -0,0 +1,22 @@ +#nullable disable + +using System.Collections.Generic; +using System.Text.Json.Serialization; + +namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos +{ + public class ShowImagesDto + { + /// <summary> + /// Gets or sets the program id. + /// </summary> + [JsonPropertyName("programID")] + public string ProgramId { get; set; } + + /// <summary> + /// Gets or sets the list of data. + /// </summary> + [JsonPropertyName("data")] + public List<ImageDataDto> Data { get; set; } + } +} diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/StationDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/StationDto.cs new file mode 100644 index 000000000..12f3576c6 --- /dev/null +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/StationDto.cs @@ -0,0 +1,67 @@ +#nullable disable + +using System.Collections.Generic; +using System.Text.Json.Serialization; + +namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos +{ + /// <summary> + /// Station dto. + /// </summary> + public class StationDto + { + /// <summary> + /// Gets or sets the station id. + /// </summary> + [JsonPropertyName("stationID")] + public string StationId { get; set; } + + /// <summary> + /// Gets or sets the name. + /// </summary> + [JsonPropertyName("name")] + public string Name { get; set; } + + /// <summary> + /// Gets or sets the callsign. + /// </summary> + [JsonPropertyName("callsign")] + public string Callsign { get; set; } + + /// <summary> + /// Gets or sets the broadcast language. + /// </summary> + [JsonPropertyName("broadcastLanguage")] + public List<string> BroadcastLanguage { get; set; } + + /// <summary> + /// Gets or sets the description language. + /// </summary> + [JsonPropertyName("descriptionLanguage")] + public List<string> DescriptionLanguage { get; set; } + + /// <summary> + /// Gets or sets the broadcaster. + /// </summary> + [JsonPropertyName("broadcaster")] + public BroadcasterDto Broadcaster { get; set; } + + /// <summary> + /// Gets or sets the affiliate. + /// </summary> + [JsonPropertyName("affiliate")] + public string Affiliate { get; set; } + + /// <summary> + /// Gets or sets the logo. + /// </summary> + [JsonPropertyName("logo")] + public LogoDto Logo { get; set; } + + /// <summary> + /// Gets or set a value indicating whether it is commercial free. + /// </summary> + [JsonPropertyName("isCommercialFree")] + public bool? IsCommercialFree { get; set; } + } +} diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/TitleDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/TitleDto.cs new file mode 100644 index 000000000..06c95524b --- /dev/null +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/TitleDto.cs @@ -0,0 +1,18 @@ +#nullable disable + +using System.Text.Json.Serialization; + +namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos +{ + /// <summary> + /// Title dto. + /// </summary> + public class TitleDto + { + /// <summary> + /// Gets or sets the title. + /// </summary> + [JsonPropertyName("title120")] + public string Title120 { get; set; } + } +} diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/TokenDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/TokenDto.cs new file mode 100644 index 000000000..c3ec1c7d6 --- /dev/null +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/TokenDto.cs @@ -0,0 +1,36 @@ +#nullable disable + +using System.Text.Json.Serialization; + +namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos +{ + /// <summary> + /// The token dto. + /// </summary> + public class TokenDto + { + /// <summary> + /// Gets or sets the response code. + /// </summary> + [JsonPropertyName("code")] + public int Code { get; set; } + + /// <summary> + /// Gets or sets the response message. + /// </summary> + [JsonPropertyName("message")] + public string Message { get; set; } + + /// <summary> + /// Gets or sets the server id. + /// </summary> + [JsonPropertyName("serverID")] + public string ServerId { get; set; } + + /// <summary> + /// Gets or sets the token. + /// </summary> + [JsonPropertyName("token")] + public string Token { get; set; } + } +} diff --git a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs index d964769b5..ce585d0fb 100644 --- a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs @@ -403,7 +403,7 @@ namespace Emby.Server.Implementations.LiveTv // Set the total bitrate if not already supplied mediaSource.InferTotalBitrate(); - if (!(service is EmbyTV.EmbyTV)) + if (service is not EmbyTV.EmbyTV) { // We can't trust that we'll be able to direct stream it through emby server, no matter what the provider says // mediaSource.SupportsDirectPlay = false; @@ -1724,7 +1724,7 @@ namespace Emby.Server.Implementations.LiveTv await service.CancelTimerAsync(timer.ExternalId, CancellationToken.None).ConfigureAwait(false); - if (!(service is EmbyTV.EmbyTV)) + if (service is not EmbyTV.EmbyTV) { TimerCancelled?.Invoke(this, new GenericEventArgs<TimerEventInfo>(new TimerEventInfo(id))); } @@ -2050,7 +2050,7 @@ namespace Emby.Server.Implementations.LiveTv _logger.LogInformation("New recording scheduled"); - if (!(service is EmbyTV.EmbyTV)) + if (service is not EmbyTV.EmbyTV) { TimerCreated?.Invoke(this, new GenericEventArgs<TimerEventInfo>( new TimerEventInfo(newTimerId) diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunManager.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunManager.cs index 3016eeda2..b2e555c7d 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunManager.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunManager.cs @@ -27,6 +27,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun { private string _channel; private string _program; + public LegacyHdHomerunChannelCommands(string url) { // parse url for channel and program diff --git a/Emby.Server.Implementations/Playlists/PlaylistManager.cs b/Emby.Server.Implementations/Playlists/PlaylistManager.cs index 8cafde38e..b07798fa4 100644 --- a/Emby.Server.Implementations/Playlists/PlaylistManager.cs +++ b/Emby.Server.Implementations/Playlists/PlaylistManager.cs @@ -260,7 +260,7 @@ namespace Emby.Server.Implementations.Playlists public async Task RemoveFromPlaylistAsync(string playlistId, IEnumerable<string> entryIds) { - if (!(_libraryManager.GetItemById(playlistId) is Playlist playlist)) + if (_libraryManager.GetItemById(playlistId) is not Playlist playlist) { throw new ArgumentException("No Playlist exists with the supplied Id"); } @@ -293,7 +293,7 @@ namespace Emby.Server.Implementations.Playlists public async Task MoveItemAsync(string playlistId, string entryId, int newIndex) { - if (!(_libraryManager.GetItemById(playlistId) is Playlist playlist)) + if (_libraryManager.GetItemById(playlistId) is not Playlist playlist) { throw new ArgumentException("No Playlist exists with the supplied Id"); } diff --git a/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs b/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs index b34325041..fb93c375d 100644 --- a/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs +++ b/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs @@ -24,7 +24,6 @@ namespace Emby.Server.Implementations.ScheduledTasks /// </summary> public class ScheduledTaskWorker : IScheduledTaskWorker { - /// <summary> /// Gets or sets the application paths. /// </summary> @@ -267,7 +266,7 @@ namespace Emby.Server.Implementations.ScheduledTasks } /// <summary> - /// Gets the triggers that define when the task will run. + /// Gets or sets the triggers that define when the task will run. /// </summary> /// <value>The triggers.</value> /// <exception cref="ArgumentNullException"><c>value</c> is <c>null</c>.</exception> diff --git a/Emby.Server.Implementations/Sorting/ArtistComparer.cs b/Emby.Server.Implementations/Sorting/ArtistComparer.cs index 98bee3fd9..7b7ba5753 100644 --- a/Emby.Server.Implementations/Sorting/ArtistComparer.cs +++ b/Emby.Server.Implementations/Sorting/ArtistComparer.cs @@ -27,7 +27,7 @@ namespace Emby.Server.Implementations.Sorting /// <returns>System.String.</returns> private static string? GetValue(BaseItem? x) { - if (!(x is Audio audio)) + if (x is not Audio audio) { return string.Empty; } diff --git a/Jellyfin.Api/Controllers/ItemUpdateController.cs b/Jellyfin.Api/Controllers/ItemUpdateController.cs index a9f4a5a58..64d7b2f3e 100644 --- a/Jellyfin.Api/Controllers/ItemUpdateController.cs +++ b/Jellyfin.Api/Controllers/ItemUpdateController.cs @@ -154,11 +154,11 @@ namespace Jellyfin.Api.Controllers }; if (!item.IsVirtualItem - && !(item is ICollectionFolder) - && !(item is UserView) - && !(item is AggregateFolder) - && !(item is LiveTvChannel) - && !(item is IItemByName) + && item is not ICollectionFolder + && item is not UserView + && item is not AggregateFolder + && item is not LiveTvChannel + && item is not IItemByName && item.SourceType == SourceType.Library) { var inheritedContentType = _libraryManager.GetInheritedContentType(item); diff --git a/Jellyfin.Api/Controllers/ItemsController.cs b/Jellyfin.Api/Controllers/ItemsController.cs index 35c27dd0e..52eefc5c2 100644 --- a/Jellyfin.Api/Controllers/ItemsController.cs +++ b/Jellyfin.Api/Controllers/ItemsController.cs @@ -241,7 +241,7 @@ namespace Jellyfin.Api.Controllers var item = _libraryManager.GetParentItem(parentId, userId); QueryResult<BaseItem> result; - if (!(item is Folder folder)) + if (item is not Folder folder) { folder = _libraryManager.GetUserRootFolder(); } @@ -285,7 +285,7 @@ namespace Jellyfin.Api.Controllers return Unauthorized($"{user.Username} is not permitted to access Library {item.Name}."); } - if ((recursive.HasValue && recursive.Value) || ids.Length != 0 || !(item is UserRootFolder)) + if ((recursive.HasValue && recursive.Value) || ids.Length != 0 || item is not UserRootFolder) { var query = new InternalItemsQuery(user!) { diff --git a/Jellyfin.Api/Controllers/LibraryController.cs b/Jellyfin.Api/Controllers/LibraryController.cs index 4ed15e1d5..8cc369a5c 100644 --- a/Jellyfin.Api/Controllers/LibraryController.cs +++ b/Jellyfin.Api/Controllers/LibraryController.cs @@ -700,7 +700,7 @@ namespace Jellyfin.Api.Controllers : _libraryManager.RootFolder) : _libraryManager.GetItemById(itemId); - if (item is Episode || (item is IItemByName && !(item is MusicArtist))) + if (item is Episode || (item is IItemByName && item is not MusicArtist)) { return new QueryResult<BaseItemDto>(); } diff --git a/Jellyfin.Api/Controllers/TvShowsController.cs b/Jellyfin.Api/Controllers/TvShowsController.cs index 51d40994e..7c5b8a43b 100644 --- a/Jellyfin.Api/Controllers/TvShowsController.cs +++ b/Jellyfin.Api/Controllers/TvShowsController.cs @@ -228,7 +228,7 @@ namespace Jellyfin.Api.Controllers if (seasonId.HasValue) // Season id was supplied. Get episodes by season id. { var item = _libraryManager.GetItemById(seasonId.Value); - if (!(item is Season seasonItem)) + if (item is not Season seasonItem) { return NotFound("No season exists with Id " + seasonId); } @@ -237,7 +237,7 @@ namespace Jellyfin.Api.Controllers } else if (season.HasValue) // Season number was supplied. Get episodes by season number { - if (!(_libraryManager.GetItemById(seriesId) is Series series)) + if (_libraryManager.GetItemById(seriesId) is not Series series) { return NotFound("Series not found"); } @@ -252,7 +252,7 @@ namespace Jellyfin.Api.Controllers } else // No season number or season id was supplied. Returning all episodes. { - if (!(_libraryManager.GetItemById(seriesId) is Series series)) + if (_libraryManager.GetItemById(seriesId) is not Series series) { return NotFound("Series not found"); } @@ -336,7 +336,7 @@ namespace Jellyfin.Api.Controllers ? _userManager.GetUserById(userId.Value) : null; - if (!(_libraryManager.GetItemById(seriesId) is Series series)) + if (_libraryManager.GetItemById(seriesId) is not Series series) { return NotFound("Series not found"); } diff --git a/Jellyfin.Api/Helpers/StreamingHelpers.cs b/Jellyfin.Api/Helpers/StreamingHelpers.cs index 8cffe9c4c..5b14b6468 100644 --- a/Jellyfin.Api/Helpers/StreamingHelpers.cs +++ b/Jellyfin.Api/Helpers/StreamingHelpers.cs @@ -222,11 +222,7 @@ namespace Jellyfin.Api.Helpers { var resolution = ResolutionNormalizer.Normalize( state.VideoStream?.BitRate, - state.VideoStream?.Width, - state.VideoStream?.Height, state.OutputVideoBitrate.Value, - state.VideoStream?.Codec, - state.OutputVideoCodec, state.VideoRequest.MaxWidth, state.VideoRequest.MaxHeight); diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index 067fecd87..3b182f7c9 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -112,7 +112,7 @@ namespace MediaBrowser.Controller.Entities private string _name; - public static char SlugChar = '-'; + public const char SlugChar = '-'; protected BaseItem() { @@ -2050,7 +2050,7 @@ namespace MediaBrowser.Controller.Entities public virtual string GetClientTypeName() { - if (IsFolder && SourceType == SourceType.Channel && !(this is Channel)) + if (IsFolder && SourceType == SourceType.Channel && this is not Channel) { return "ChannelFolderItem"; } diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index d45a02cf2..dd08c31ed 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -233,7 +233,7 @@ namespace MediaBrowser.Controller.Entities public override bool IsVisible(User user) { - if (this is ICollectionFolder && !(this is BasePluginFolder)) + if (this is ICollectionFolder && this is not BasePluginFolder) { var blockedMediaFolders = user.GetPreferenceValues<Guid>(PreferenceKind.BlockedMediaFolders); if (blockedMediaFolders.Length > 0) @@ -673,7 +673,7 @@ namespace MediaBrowser.Controller.Entities { if (LinkedChildren.Length > 0) { - if (!(this is ICollectionFolder)) + if (this is not ICollectionFolder) { return GetChildren(user, true).Count; } @@ -730,7 +730,7 @@ namespace MediaBrowser.Controller.Entities return PostFilterAndSort(items, query, true); } - if (!(this is UserRootFolder) && !(this is AggregateFolder) && query.ParentId == Guid.Empty) + if (this is not UserRootFolder && this is not AggregateFolder && query.ParentId == Guid.Empty) { query.Parent = this; } @@ -805,7 +805,7 @@ namespace MediaBrowser.Controller.Entities { if (LinkedChildren.Length > 0) { - if (!(this is ICollectionFolder)) + if (this is not ICollectionFolder) { Logger.LogDebug("Query requires post-filtering due to LinkedChildren. Type: " + GetType().Name); return true; @@ -1545,7 +1545,7 @@ namespace MediaBrowser.Controller.Entities var childOwner = child.GetOwner() ?? child; - if (childOwner != null && !(child is IItemByName)) + if (child is not IItemByName) { var childProtocol = childOwner.PathProtocol; if (!childProtocol.HasValue || childProtocol.Value != Model.MediaInfo.MediaProtocol.File) diff --git a/MediaBrowser.Controller/Entities/TV/Series.cs b/MediaBrowser.Controller/Entities/TV/Series.cs index beda504b9..e4933e968 100644 --- a/MediaBrowser.Controller/Entities/TV/Series.cs +++ b/MediaBrowser.Controller/Entities/TV/Series.cs @@ -296,7 +296,7 @@ namespace MediaBrowser.Controller.Entities.TV // Refresh seasons foreach (var item in items) { - if (!(item is Season)) + if (item is not Season) { continue; } diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 141bb91c5..3e577ebb7 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -504,7 +504,9 @@ namespace MediaBrowser.Controller.MediaEncoding var arg = new StringBuilder(); var videoDecoder = GetHardwareAcceleratedVideoDecoder(state, encodingOptions) ?? string.Empty; var outputVideoCodec = GetVideoEncoder(state, encodingOptions) ?? string.Empty; +#pragma warning disable CA1508 // Defaults to string.Empty var isSwDecoder = string.IsNullOrEmpty(videoDecoder); +#pragma warning restore CA1508 var isD3d11vaDecoder = videoDecoder.IndexOf("d3d11va", StringComparison.OrdinalIgnoreCase) != -1; var isVaapiDecoder = videoDecoder.IndexOf("vaapi", StringComparison.OrdinalIgnoreCase) != -1; var isVaapiEncoder = outputVideoCodec.IndexOf("vaapi", StringComparison.OrdinalIgnoreCase) != -1; @@ -1759,7 +1761,7 @@ namespace MediaBrowser.Controller.MediaEncoding var request = state.BaseRequest; - var inputChannels = audioStream?.Channels; + var inputChannels = audioStream.Channels; if (inputChannels <= 0) { @@ -2027,8 +2029,8 @@ namespace MediaBrowser.Controller.MediaEncoding { // Adjust the size of graphical subtitles to fit the video stream. var videoStream = state.VideoStream; - var inputWidth = videoStream?.Width; - var inputHeight = videoStream?.Height; + var inputWidth = videoStream.Width; + var inputHeight = videoStream.Height; var (width, height) = GetFixedOutputSize(inputWidth, inputHeight, request.Width, request.Height, request.MaxWidth, request.MaxHeight); if (width.HasValue && height.HasValue) @@ -3101,7 +3103,7 @@ namespace MediaBrowser.Controller.MediaEncoding inputModifier += " " + videoDecoder; if (!IsCopyCodec(state.OutputVideoCodec) - && (videoDecoder ?? string.Empty).IndexOf("cuvid", StringComparison.OrdinalIgnoreCase) != -1) + && videoDecoder.IndexOf("cuvid", StringComparison.OrdinalIgnoreCase) != -1) { var videoStream = state.VideoStream; var inputWidth = videoStream?.Width; @@ -3110,7 +3112,7 @@ namespace MediaBrowser.Controller.MediaEncoding var (width, height) = GetFixedOutputSize(inputWidth, inputHeight, request.Width, request.Height, request.MaxWidth, request.MaxHeight); - if ((videoDecoder ?? string.Empty).IndexOf("cuvid", StringComparison.OrdinalIgnoreCase) != -1 + if (videoDecoder.IndexOf("cuvid", StringComparison.OrdinalIgnoreCase) != -1 && width.HasValue && height.HasValue) { diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs b/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs index fa9f40d60..b09b7dba6 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs @@ -422,7 +422,7 @@ namespace MediaBrowser.Controller.MediaEncoding if (EncodingHelper.IsCopyCodec(OutputVideoCodec)) { - return VideoStream?.Codec; + return VideoStream.Codec; } return OutputVideoCodec; @@ -440,7 +440,7 @@ namespace MediaBrowser.Controller.MediaEncoding if (EncodingHelper.IsCopyCodec(OutputAudioCodec)) { - return AudioStream?.Codec; + return AudioStream.Codec; } return OutputAudioCodec; @@ -568,7 +568,7 @@ namespace MediaBrowser.Controller.MediaEncoding } } - return forceDeinterlaceIfSourceIsInterlaced && isInputInterlaced; + return forceDeinterlaceIfSourceIsInterlaced; } public string[] GetRequestedProfiles(string codec) diff --git a/MediaBrowser.LocalMetadata/Images/LocalImageProvider.cs b/MediaBrowser.LocalMetadata/Images/LocalImageProvider.cs index 31475e22f..b7398880e 100644 --- a/MediaBrowser.LocalMetadata/Images/LocalImageProvider.cs +++ b/MediaBrowser.LocalMetadata/Images/LocalImageProvider.cs @@ -283,7 +283,7 @@ namespace MediaBrowser.LocalMetadata.Images { imageFileNames = _seriesImageFileNames; } - else if (item is Video && !(item is Episode)) + else if (item is Video && item is not Episode) { imageFileNames = _videoImageFileNames; } diff --git a/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs b/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs index dd824206f..6a3896eb6 100644 --- a/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs +++ b/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs @@ -223,7 +223,7 @@ namespace MediaBrowser.LocalMetadata.Savers writer.WriteElementString("CustomRating", item.CustomRating); } - if (!string.IsNullOrEmpty(item.Name) && !(item is Episode)) + if (!string.IsNullOrEmpty(item.Name) && item is not Episode) { writer.WriteElementString("LocalTitle", item.Name); } @@ -240,7 +240,7 @@ namespace MediaBrowser.LocalMetadata.Savers { writer.WriteElementString("BirthDate", item.PremiereDate.Value.ToLocalTime().ToString("yyyy-MM-dd", CultureInfo.InvariantCulture)); } - else if (!(item is Episode)) + else if (item is not Episode) { writer.WriteElementString("PremiereDate", item.PremiereDate.Value.ToLocalTime().ToString("yyyy-MM-dd", CultureInfo.InvariantCulture)); } @@ -252,7 +252,7 @@ namespace MediaBrowser.LocalMetadata.Savers { writer.WriteElementString("DeathDate", item.EndDate.Value.ToLocalTime().ToString("yyyy-MM-dd", CultureInfo.InvariantCulture)); } - else if (!(item is Episode)) + else if (item is not Episode) { writer.WriteElementString("EndDate", item.EndDate.Value.ToLocalTime().ToString("yyyy-MM-dd", CultureInfo.InvariantCulture)); } @@ -292,7 +292,7 @@ namespace MediaBrowser.LocalMetadata.Savers writer.WriteElementString("Rating", item.CommunityRating.Value.ToString(_usCulture)); } - if (item.ProductionYear.HasValue && !(item is Person)) + if (item.ProductionYear.HasValue && item is not Person) { writer.WriteElementString("ProductionYear", item.ProductionYear.Value.ToString(_usCulture)); } diff --git a/MediaBrowser.Model/Dlna/MediaFormatProfile.cs b/MediaBrowser.Model/Dlna/MediaFormatProfile.cs index 20e05b8a9..06f6660f4 100644 --- a/MediaBrowser.Model/Dlna/MediaFormatProfile.cs +++ b/MediaBrowser.Model/Dlna/MediaFormatProfile.cs @@ -1,4 +1,4 @@ -#pragma warning disable CS1591 +#pragma warning disable CS1591, CA1707 namespace MediaBrowser.Model.Dlna { diff --git a/MediaBrowser.Model/Dlna/ResolutionNormalizer.cs b/MediaBrowser.Model/Dlna/ResolutionNormalizer.cs index 65fccbdd4..806877ff0 100644 --- a/MediaBrowser.Model/Dlna/ResolutionNormalizer.cs +++ b/MediaBrowser.Model/Dlna/ResolutionNormalizer.cs @@ -21,11 +21,7 @@ namespace MediaBrowser.Model.Dlna public static ResolutionOptions Normalize( int? inputBitrate, - int? unused1, - int? unused2, int outputBitrate, - string inputCodec, - string outputCodec, int? maxWidth, int? maxHeight) { diff --git a/MediaBrowser.Model/Dlna/StreamBuilder.cs b/MediaBrowser.Model/Dlna/StreamBuilder.cs index f4c69fe8f..635420a76 100644 --- a/MediaBrowser.Model/Dlna/StreamBuilder.cs +++ b/MediaBrowser.Model/Dlna/StreamBuilder.cs @@ -694,7 +694,7 @@ namespace MediaBrowser.Model.Dlna if (isEligibleForDirectPlay || isEligibleForDirectStream) { // See if it can be direct played - var directPlayInfo = GetVideoDirectPlayProfile(options, item, videoStream, audioStream, isEligibleForDirectPlay, isEligibleForDirectStream); + var directPlayInfo = GetVideoDirectPlayProfile(options, item, videoStream, audioStream, isEligibleForDirectStream); var directPlay = directPlayInfo.Item1; if (directPlay != null) @@ -810,7 +810,7 @@ namespace MediaBrowser.Model.Dlna // Honor requested max channels playlistItem.GlobalMaxAudioChannels = options.MaxAudioChannels; - int audioBitrate = GetAudioBitrate(playlistItem.SubProtocol, options.GetMaxBitrate(false) ?? 0, playlistItem.TargetAudioCodec, audioStream, playlistItem); + int audioBitrate = GetAudioBitrate(options.GetMaxBitrate(false) ?? 0, playlistItem.TargetAudioCodec, audioStream, playlistItem); playlistItem.AudioBitrate = Math.Min(playlistItem.AudioBitrate ?? audioBitrate, audioBitrate); isFirstAppliedCodecProfile = true; @@ -907,7 +907,7 @@ namespace MediaBrowser.Model.Dlna return 192000; } - private static int GetAudioBitrate(string subProtocol, long maxTotalBitrate, string[] targetAudioCodecs, MediaStream audioStream, StreamInfo item) + private static int GetAudioBitrate(long maxTotalBitrate, string[] targetAudioCodecs, MediaStream audioStream, StreamInfo item) { string targetAudioCodec = targetAudioCodecs.Length == 0 ? null : targetAudioCodecs[0]; @@ -1005,7 +1005,6 @@ namespace MediaBrowser.Model.Dlna MediaSourceInfo mediaSource, MediaStream videoStream, MediaStream audioStream, - bool isEligibleForDirectPlay, bool isEligibleForDirectStream) { if (options.ForceDirectPlay) @@ -1146,7 +1145,7 @@ namespace MediaBrowser.Model.Dlna { string audioCodec = audioStream.Codec; conditions = new List<ProfileCondition>(); - bool? isSecondaryAudio = audioStream == null ? null : mediaSource.IsSecondaryAudio(audioStream); + bool? isSecondaryAudio = mediaSource.IsSecondaryAudio(audioStream); foreach (var i in profile.CodecProfiles) { @@ -1262,7 +1261,7 @@ namespace MediaBrowser.Model.Dlna continue; } - if (playMethod == PlayMethod.Transcode && !IsSubtitleEmbedSupported(subtitleStream, profile, transcodingSubProtocol, outputContainer)) + if (playMethod == PlayMethod.Transcode && !IsSubtitleEmbedSupported(outputContainer)) { continue; } @@ -1291,7 +1290,7 @@ namespace MediaBrowser.Model.Dlna continue; } - if (playMethod == PlayMethod.Transcode && !IsSubtitleEmbedSupported(subtitleStream, profile, transcodingSubProtocol, outputContainer)) + if (playMethod == PlayMethod.Transcode && !IsSubtitleEmbedSupported(outputContainer)) { continue; } @@ -1313,7 +1312,7 @@ namespace MediaBrowser.Model.Dlna }; } - private static bool IsSubtitleEmbedSupported(MediaStream subtitleStream, SubtitleProfile subtitleProfile, string transcodingSubProtocol, string transcodingContainer) + private static bool IsSubtitleEmbedSupported(string transcodingContainer) { if (!string.IsNullOrEmpty(transcodingContainer)) { @@ -1728,18 +1727,14 @@ namespace MediaBrowser.Model.Dlna continue; } - if (!string.IsNullOrEmpty(value)) - { - // change from split by | to comma - - // strip spaces to avoid having to encode - var values = value - .Split('|', StringSplitOptions.RemoveEmptyEntries); + // change from split by | to comma + // strip spaces to avoid having to encode + var values = value + .Split('|', StringSplitOptions.RemoveEmptyEntries); - if (condition.Condition == ProfileConditionType.Equals || condition.Condition == ProfileConditionType.EqualsAny) - { - item.SetOption(qualifier, "profile", string.Join(',', values)); - } + if (condition.Condition == ProfileConditionType.Equals || condition.Condition == ProfileConditionType.EqualsAny) + { + item.SetOption(qualifier, "profile", string.Join(',', values)); } break; diff --git a/MediaBrowser.Model/Dlna/StreamInfo.cs b/MediaBrowser.Model/Dlna/StreamInfo.cs index 252872847..432c1c1d6 100644 --- a/MediaBrowser.Model/Dlna/StreamInfo.cs +++ b/MediaBrowser.Model/Dlna/StreamInfo.cs @@ -636,7 +636,7 @@ namespace MediaBrowser.Model.Dlna continue; } - var encodedValue = pair.Value.Replace(" ", "%20"); + var encodedValue = pair.Value.Replace(" ", "%20", StringComparison.Ordinal); list.Add(string.Format(CultureInfo.InvariantCulture, "{0}={1}", pair.Name, encodedValue)); } diff --git a/MediaBrowser.Model/Entities/MediaStream.cs b/MediaBrowser.Model/Entities/MediaStream.cs index 9653a8ece..de9fe6ff6 100644 --- a/MediaBrowser.Model/Entities/MediaStream.cs +++ b/MediaBrowser.Model/Entities/MediaStream.cs @@ -261,7 +261,7 @@ namespace MediaBrowser.Model.Entities foreach (var tag in attributes) { // Keep Tags that are not already in Title. - if (Title.IndexOf(tag, StringComparison.OrdinalIgnoreCase) == -1) + if (!Title.Contains(tag, StringComparison.OrdinalIgnoreCase)) { result.Append(" - ").Append(tag); } diff --git a/MediaBrowser.Model/IO/IFileSystem.cs b/MediaBrowser.Model/IO/IFileSystem.cs index be4f1e16b..0f77d6b5b 100644 --- a/MediaBrowser.Model/IO/IFileSystem.cs +++ b/MediaBrowser.Model/IO/IFileSystem.cs @@ -51,7 +51,7 @@ namespace MediaBrowser.Model.IO /// <returns>A <see cref="FileSystemMetadata" /> object.</returns> /// <remarks><para>If the specified path points to a directory, the returned <see cref="FileSystemMetadata" /> object's /// <see cref="FileSystemMetadata.IsDirectory" /> property and the <see cref="FileSystemMetadata.Exists" /> property will both be set to false.</para> - /// <para>For automatic handling of files <b>and</b> directories, use <see cref="M:IFileSystem.GetFileSystemInfo(System.String)" />.</para></remarks> + /// <para>For automatic handling of files <b>and</b> directories, use <see cref="GetFileSystemInfo(string)" />.</para></remarks> FileSystemMetadata GetFileInfo(string path); /// <summary> @@ -61,7 +61,7 @@ namespace MediaBrowser.Model.IO /// <returns>A <see cref="FileSystemMetadata" /> object.</returns> /// <remarks><para>If the specified path points to a file, the returned <see cref="FileSystemMetadata" /> object's /// <see cref="FileSystemMetadata.IsDirectory" /> property will be set to true and the <see cref="FileSystemMetadata.Exists" /> property will be set to false.</para> - /// <para>For automatic handling of files <b>and</b> directories, use <see cref="M:IFileSystem.GetFileSystemInfo(System.String)" />.</para></remarks> + /// <para>For automatic handling of files <b>and</b> directories, use <see cref="GetFileSystemInfo(string)" />.</para></remarks> FileSystemMetadata GetDirectoryInfo(string path); /// <summary> diff --git a/MediaBrowser.Providers/Manager/ImageSaver.cs b/MediaBrowser.Providers/Manager/ImageSaver.cs index fb1d4f490..7d259a9d3 100644 --- a/MediaBrowser.Providers/Manager/ImageSaver.cs +++ b/MediaBrowser.Providers/Manager/ImageSaver.cs @@ -91,7 +91,7 @@ namespace MediaBrowser.Providers.Manager throw new ArgumentNullException(nameof(mimeType)); } - var saveLocally = item.SupportsLocalMetadata && item.IsSaveLocalMetadataEnabled() && !item.ExtraType.HasValue && !(item is Audio); + var saveLocally = item.SupportsLocalMetadata && item.IsSaveLocalMetadataEnabled() && !item.ExtraType.HasValue && item is not Audio; if (type != ImageType.Primary && item is Episode) { diff --git a/MediaBrowser.Providers/Manager/ItemImageProvider.cs b/MediaBrowser.Providers/Manager/ItemImageProvider.cs index 607fd127b..cc4c75d7d 100644 --- a/MediaBrowser.Providers/Manager/ItemImageProvider.cs +++ b/MediaBrowser.Providers/Manager/ItemImageProvider.cs @@ -57,7 +57,7 @@ namespace MediaBrowser.Providers.Manager { var hasChanges = false; - if (!(item is Photo)) + if (item is not Photo) { var images = providers.OfType<ILocalImageProvider>() .SelectMany(i => i.GetImages(item, directoryService)) @@ -529,7 +529,7 @@ namespace MediaBrowser.Providers.Manager return true; } - if (item is IItemByName && !(item is MusicArtist)) + if (item is IItemByName && item is not MusicArtist) { var hasDualAccess = item as IHasDualAccess; if (hasDualAccess == null || hasDualAccess.IsAccessedByName) diff --git a/MediaBrowser.Providers/Manager/MetadataService.cs b/MediaBrowser.Providers/Manager/MetadataService.cs index 3a42eb4c1..ab8d3a2a6 100644 --- a/MediaBrowser.Providers/Manager/MetadataService.cs +++ b/MediaBrowser.Providers/Manager/MetadataService.cs @@ -584,7 +584,7 @@ namespace MediaBrowser.Providers.Manager protected virtual IEnumerable<IImageProvider> GetNonLocalImageProviders(BaseItem item, IEnumerable<IImageProvider> allImageProviders, ImageRefreshOptions options) { // Get providers to refresh - var providers = allImageProviders.Where(i => !(i is ILocalImageProvider)); + var providers = allImageProviders.Where(i => i is not ILocalImageProvider); var dateLastImageRefresh = item.DateLastRefreshed; @@ -729,7 +729,7 @@ namespace MediaBrowser.Providers.Manager refreshResult.Failures += remoteResult.Failures; } - if (providers.Any(i => !(i is ICustomMetadataProvider))) + if (providers.Any(i => i is not ICustomMetadataProvider)) { if (refreshResult.UpdateType > ItemUpdateType.None) { @@ -748,7 +748,7 @@ namespace MediaBrowser.Providers.Manager // var isUnidentified = failedProviderCount > 0 && successfulProviderCount == 0; - foreach (var provider in customProviders.Where(i => !(i is IPreRefreshProvider))) + foreach (var provider in customProviders.Where(i => i is not IPreRefreshProvider)) { await RunCustomProvider(provider, item, logName, options, refreshResult, cancellationToken).ConfigureAwait(false); } diff --git a/MediaBrowser.Providers/Manager/ProviderManager.cs b/MediaBrowser.Providers/Manager/ProviderManager.cs index 2dfaa372c..7e60eced0 100644 --- a/MediaBrowser.Providers/Manager/ProviderManager.cs +++ b/MediaBrowser.Providers/Manager/ProviderManager.cs @@ -323,7 +323,7 @@ namespace MediaBrowser.Providers.Manager .OrderBy(i => { // See if there's a user-defined order - if (!(i is ILocalImageProvider)) + if (i is not ILocalImageProvider) { var fetcherOrder = typeFetcherOrder ?? currentOptions.ImageFetcherOrder; var index = Array.IndexOf(fetcherOrder, i.Name); @@ -390,7 +390,7 @@ namespace MediaBrowser.Providers.Manager if (!includeDisabled) { // If locked only allow local providers - if (item.IsLocked && !(provider is ILocalMetadataProvider) && !(provider is IForcedProvider)) + if (item.IsLocked && provider is not ILocalMetadataProvider && provider is not IForcedProvider) { return false; } @@ -431,7 +431,7 @@ namespace MediaBrowser.Providers.Manager if (!includeDisabled) { // If locked only allow local providers - if (item.IsLocked && !(provider is ILocalImageProvider)) + if (item.IsLocked && provider is not ILocalImageProvider) { if (refreshOptions.ImageRefreshMode != MetadataRefreshMode.FullRefresh) { @@ -466,7 +466,7 @@ namespace MediaBrowser.Providers.Manager /// <returns>System.Int32.</returns> private int GetOrder(IImageProvider provider) { - if (!(provider is IHasOrder hasOrder)) + if (provider is not IHasOrder hasOrder) { return 0; } @@ -745,7 +745,7 @@ namespace MediaBrowser.Providers.Manager { // Manual edit occurred // Even if save local is off, save locally anyway if the metadata file already exists - if (!(saver is IMetadataFileSaver fileSaver) || !File.Exists(fileSaver.GetSavePath(item))) + if (saver is not IMetadataFileSaver fileSaver || !File.Exists(fileSaver.GetSavePath(item))) { return false; } diff --git a/MediaBrowser.Providers/Manager/ProviderUtils.cs b/MediaBrowser.Providers/Manager/ProviderUtils.cs index aceba2215..6d088e6e7 100644 --- a/MediaBrowser.Providers/Manager/ProviderUtils.cs +++ b/MediaBrowser.Providers/Manager/ProviderUtils.cs @@ -135,7 +135,7 @@ namespace MediaBrowser.Providers.Manager { if (replaceData || !target.RunTimeTicks.HasValue) { - if (!(target is Audio) && !(target is Video)) + if (target is not Audio && target is not Video) { target.RunTimeTicks = source.RunTimeTicks; } diff --git a/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs b/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs index 3be35e2d9..38726a6f0 100644 --- a/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs +++ b/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs @@ -555,7 +555,7 @@ namespace MediaBrowser.XbmcMetadata.Savers } // Series xml saver already saves this - if (!(item is Series)) + if (item is not Series) { var tvdb = item.GetProviderId(MetadataProvider.Tvdb); if (!string.IsNullOrEmpty(tvdb)) @@ -582,7 +582,7 @@ namespace MediaBrowser.XbmcMetadata.Savers writer.WriteElementString("countrycode", item.PreferredMetadataCountryCode); } - if (item.PremiereDate.HasValue && !(item is Episode)) + if (item.PremiereDate.HasValue && item is not Episode) { var formatString = options.ReleaseDateFormat; @@ -605,7 +605,7 @@ namespace MediaBrowser.XbmcMetadata.Savers if (item.EndDate.HasValue) { - if (!(item is Episode)) + if (item is not Episode) { var formatString = options.ReleaseDateFormat; diff --git a/MediaBrowser.XbmcMetadata/Savers/MovieNfoSaver.cs b/MediaBrowser.XbmcMetadata/Savers/MovieNfoSaver.cs index 412e8031b..21e7e2335 100644 --- a/MediaBrowser.XbmcMetadata/Savers/MovieNfoSaver.cs +++ b/MediaBrowser.XbmcMetadata/Savers/MovieNfoSaver.cs @@ -82,7 +82,7 @@ namespace MediaBrowser.XbmcMetadata.Savers } // Check parent for null to avoid running this against things like video backdrops - if (item is Video video && !(item is Episode) && !video.ExtraType.HasValue) + if (item is Video video && item is not Episode && !video.ExtraType.HasValue) { return updateType >= MinimumUpdateType; } diff --git a/MediaBrowser.XbmcMetadata/Savers/SeasonNfoSaver.cs b/MediaBrowser.XbmcMetadata/Savers/SeasonNfoSaver.cs index b9d73ba82..e97550630 100644 --- a/MediaBrowser.XbmcMetadata/Savers/SeasonNfoSaver.cs +++ b/MediaBrowser.XbmcMetadata/Savers/SeasonNfoSaver.cs @@ -52,7 +52,7 @@ namespace MediaBrowser.XbmcMetadata.Savers return false; } - if (!(item is Season)) + if (item is not Season) { return false; } -- cgit v1.2.3 From 3f2c7065756682c96c90189ab5157b96fdb92bd0 Mon Sep 17 00:00:00 2001 From: Cody Robibero <cody@robibe.ro> Date: Fri, 3 Sep 2021 07:19:50 -0600 Subject: Apply suggestions from code review Co-authored-by: Claus Vium <cvium@users.noreply.github.com> --- MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs') diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 5444e8905..1be3a1ca4 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -3306,7 +3306,7 @@ namespace MediaBrowser.Controller.MediaEncoding inputModifier += " " + videoDecoder; if (!IsCopyCodec(state.OutputVideoCodec) - && videoDecoder.IndexOf("cuvid", StringComparison.OrdinalIgnoreCase) != -1) + && videoDecoder.Contains("cuvid", StringComparison.OrdinalIgnoreCase)) { var videoStream = state.VideoStream; var inputWidth = videoStream?.Width; @@ -3315,7 +3315,7 @@ namespace MediaBrowser.Controller.MediaEncoding var (width, height) = GetFixedOutputSize(inputWidth, inputHeight, request.Width, request.Height, request.MaxWidth, request.MaxHeight); - if (videoDecoder.IndexOf("cuvid", StringComparison.OrdinalIgnoreCase) != -1 + if (videoDecoder.Contains("cuvid", StringComparison.OrdinalIgnoreCase) && width.HasValue && height.HasValue) { -- cgit v1.2.3 From b205d5a03201de59240aefbce468b21199cf2b3d Mon Sep 17 00:00:00 2001 From: Chris Tam <ohgodtamit@gmail.com> Date: Fri, 20 Aug 2021 14:22:21 -0400 Subject: Disambiguate vpx to vp8 or vp9 --- CONTRIBUTORS.md | 1 + Jellyfin.Api/Controllers/AudioController.cs | 4 +- Jellyfin.Api/Controllers/DynamicHlsController.cs | 8 +- Jellyfin.Api/Controllers/VideoHlsController.cs | 2 +- Jellyfin.Api/Controllers/VideosController.cs | 16 +-- Jellyfin.Api/Helpers/StreamingHelpers.cs | 4 +- .../MediaEncoding/EncodingHelper.cs | 150 +++++++++++++-------- 7 files changed, 114 insertions(+), 71 deletions(-) (limited to 'MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs') diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 1fe255385..cb52cafed 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -46,6 +46,7 @@ - [fruhnow](https://github.com/fruhnow) - [geilername](https://github.com/geilername) - [gnattu](https://github.com/gnattu) + - [GodTamIt](https://github.com/GodTamIt) - [grafixeyehero](https://github.com/grafixeyehero) - [h1nk](https://github.com/h1nk) - [hawken93](https://github.com/hawken93) diff --git a/Jellyfin.Api/Controllers/AudioController.cs b/Jellyfin.Api/Controllers/AudioController.cs index a6e70e72d..54ac06276 100644 --- a/Jellyfin.Api/Controllers/AudioController.cs +++ b/Jellyfin.Api/Controllers/AudioController.cs @@ -76,7 +76,7 @@ namespace Jellyfin.Api.Controllers /// <param name="cpuCoreLimit">Optional. The limit of how many cpu cores to use.</param> /// <param name="liveStreamId">The live stream id.</param> /// <param name="enableMpegtsM2TsMode">Optional. Whether to enable the MpegtsM2Ts mode.</param> - /// <param name="videoCodec">Optional. Specify a video codec to encode to, e.g. h264. If omitted the server will auto-select using the url's extension. Options: h265, h264, mpeg4, theora, vpx, wmv.</param> + /// <param name="videoCodec">Optional. Specify a video codec to encode to, e.g. h264. If omitted the server will auto-select using the url's extension. Options: h265, h264, mpeg4, theora, vp8, vp9, vpx (deprecated), wmv.</param> /// <param name="subtitleCodec">Optional. Specify a subtitle codec to encode to.</param> /// <param name="transcodeReasons">Optional. The transcoding reason.</param> /// <param name="audioStreamIndex">Optional. The index of the audio stream to use. If omitted the first audio stream will be used.</param> @@ -241,7 +241,7 @@ namespace Jellyfin.Api.Controllers /// <param name="cpuCoreLimit">Optional. The limit of how many cpu cores to use.</param> /// <param name="liveStreamId">The live stream id.</param> /// <param name="enableMpegtsM2TsMode">Optional. Whether to enable the MpegtsM2Ts mode.</param> - /// <param name="videoCodec">Optional. Specify a video codec to encode to, e.g. h264. If omitted the server will auto-select using the url's extension. Options: h265, h264, mpeg4, theora, vpx, wmv.</param> + /// <param name="videoCodec">Optional. Specify a video codec to encode to, e.g. h264. If omitted the server will auto-select using the url's extension. Options: h265, h264, mpeg4, theora, vp8, vp9, vpx (deprecated), wmv.</param> /// <param name="subtitleCodec">Optional. Specify a subtitle codec to encode to.</param> /// <param name="transcodeReasons">Optional. The transcoding reason.</param> /// <param name="audioStreamIndex">Optional. The index of the audio stream to use. If omitted the first audio stream will be used.</param> diff --git a/Jellyfin.Api/Controllers/DynamicHlsController.cs b/Jellyfin.Api/Controllers/DynamicHlsController.cs index 35435b007..fbfb47215 100644 --- a/Jellyfin.Api/Controllers/DynamicHlsController.cs +++ b/Jellyfin.Api/Controllers/DynamicHlsController.cs @@ -150,7 +150,7 @@ namespace Jellyfin.Api.Controllers /// <param name="cpuCoreLimit">Optional. The limit of how many cpu cores to use.</param> /// <param name="liveStreamId">The live stream id.</param> /// <param name="enableMpegtsM2TsMode">Optional. Whether to enable the MpegtsM2Ts mode.</param> - /// <param name="videoCodec">Optional. Specify a video codec to encode to, e.g. h264. If omitted the server will auto-select using the url's extension. Options: h265, h264, mpeg4, theora, vpx, wmv.</param> + /// <param name="videoCodec">Optional. Specify a video codec to encode to, e.g. h264. If omitted the server will auto-select using the url's extension. Options: h265, h264, mpeg4, theora, vp8, vp9, vpx (deprecated), wmv.</param> /// <param name="subtitleCodec">Optional. Specify a subtitle codec to encode to.</param> /// <param name="transcodeReasons">Optional. The transcoding reason.</param> /// <param name="audioStreamIndex">Optional. The index of the audio stream to use. If omitted the first audio stream will be used.</param> @@ -316,7 +316,7 @@ namespace Jellyfin.Api.Controllers /// <param name="cpuCoreLimit">Optional. The limit of how many cpu cores to use.</param> /// <param name="liveStreamId">The live stream id.</param> /// <param name="enableMpegtsM2TsMode">Optional. Whether to enable the MpegtsM2Ts mode.</param> - /// <param name="videoCodec">Optional. Specify a video codec to encode to, e.g. h264. If omitted the server will auto-select using the url's extension. Options: h265, h264, mpeg4, theora, vpx, wmv.</param> + /// <param name="videoCodec">Optional. Specify a video codec to encode to, e.g. h264. If omitted the server will auto-select using the url's extension. Options: h265, h264, mpeg4, theora, vp8, vp9, vpx (deprecated), wmv.</param> /// <param name="subtitleCodec">Optional. Specify a subtitle codec to encode to.</param> /// <param name="transcodeReasons">Optional. The transcoding reason.</param> /// <param name="audioStreamIndex">Optional. The index of the audio stream to use. If omitted the first audio stream will be used.</param> @@ -482,7 +482,7 @@ namespace Jellyfin.Api.Controllers /// <param name="cpuCoreLimit">Optional. The limit of how many cpu cores to use.</param> /// <param name="liveStreamId">The live stream id.</param> /// <param name="enableMpegtsM2TsMode">Optional. Whether to enable the MpegtsM2Ts mode.</param> - /// <param name="videoCodec">Optional. Specify a video codec to encode to, e.g. h264. If omitted the server will auto-select using the url's extension. Options: h265, h264, mpeg4, theora, vpx, wmv.</param> + /// <param name="videoCodec">Optional. Specify a video codec to encode to, e.g. h264. If omitted the server will auto-select using the url's extension. Options: h265, h264, mpeg4, theora, vp8, vp9, vpx (deprecated), wmv.</param> /// <param name="subtitleCodec">Optional. Specify a subtitle codec to encode to.</param> /// <param name="transcodeReasons">Optional. The transcoding reason.</param> /// <param name="audioStreamIndex">Optional. The index of the audio stream to use. If omitted the first audio stream will be used.</param> @@ -813,7 +813,7 @@ namespace Jellyfin.Api.Controllers /// <param name="cpuCoreLimit">Optional. The limit of how many cpu cores to use.</param> /// <param name="liveStreamId">The live stream id.</param> /// <param name="enableMpegtsM2TsMode">Optional. Whether to enable the MpegtsM2Ts mode.</param> - /// <param name="videoCodec">Optional. Specify a video codec to encode to, e.g. h264. If omitted the server will auto-select using the url's extension. Options: h265, h264, mpeg4, theora, vpx, wmv.</param> + /// <param name="videoCodec">Optional. Specify a video codec to encode to, e.g. h264. If omitted the server will auto-select using the url's extension. Options: h265, h264, mpeg4, theora, vp8, vp9, vpx (deprecated), wmv.</param> /// <param name="subtitleCodec">Optional. Specify a subtitle codec to encode to.</param> /// <param name="transcodeReasons">Optional. The transcoding reason.</param> /// <param name="audioStreamIndex">Optional. The index of the audio stream to use. If omitted the first audio stream will be used.</param> diff --git a/Jellyfin.Api/Controllers/VideoHlsController.cs b/Jellyfin.Api/Controllers/VideoHlsController.cs index 5c941b276..8560df2ea 100644 --- a/Jellyfin.Api/Controllers/VideoHlsController.cs +++ b/Jellyfin.Api/Controllers/VideoHlsController.cs @@ -140,7 +140,7 @@ namespace Jellyfin.Api.Controllers /// <param name="cpuCoreLimit">Optional. The limit of how many cpu cores to use.</param> /// <param name="liveStreamId">The live stream id.</param> /// <param name="enableMpegtsM2TsMode">Optional. Whether to enable the MpegtsM2Ts mode.</param> - /// <param name="videoCodec">Optional. Specify a video codec to encode to, e.g. h264. If omitted the server will auto-select using the url's extension. Options: h265, h264, mpeg4, theora, vpx, wmv.</param> + /// <param name="videoCodec">Optional. Specify a video codec to encode to, e.g. h264. If omitted the server will auto-select using the url's extension. Options: h265, h264, mpeg4, theora, vp8, vp9, vpx (deprecated), wmv.</param> /// <param name="subtitleCodec">Optional. Specify a subtitle codec to encode to.</param> /// <param name="transcodeReasons">Optional. The transcoding reason.</param> /// <param name="audioStreamIndex">Optional. The index of the audio stream to use. If omitted the first audio stream will be used.</param> diff --git a/Jellyfin.Api/Controllers/VideosController.cs b/Jellyfin.Api/Controllers/VideosController.cs index 29a25fa6a..5c5057c83 100644 --- a/Jellyfin.Api/Controllers/VideosController.cs +++ b/Jellyfin.Api/Controllers/VideosController.cs @@ -310,7 +310,7 @@ namespace Jellyfin.Api.Controllers /// <param name="cpuCoreLimit">Optional. The limit of how many cpu cores to use.</param> /// <param name="liveStreamId">The live stream id.</param> /// <param name="enableMpegtsM2TsMode">Optional. Whether to enable the MpegtsM2Ts mode.</param> - /// <param name="videoCodec">Optional. Specify a video codec to encode to, e.g. h264. If omitted the server will auto-select using the url's extension. Options: h265, h264, mpeg4, theora, vpx, wmv.</param> + /// <param name="videoCodec">Optional. Specify a video codec to encode to, e.g. h264. If omitted the server will auto-select using the url's extension. Options: h265, h264, mpeg4, theora, vp8, vp9, vpx (deprecated), wmv.</param> /// <param name="subtitleCodec">Optional. Specify a subtitle codec to encode to.</param> /// <param name="transcodeReasons">Optional. The transcoding reason.</param> /// <param name="audioStreamIndex">Optional. The index of the audio stream to use. If omitted the first audio stream will be used.</param> @@ -456,9 +456,9 @@ namespace Jellyfin.Api.Controllers StreamingHelpers.AddDlnaHeaders(state, Response.Headers, true, startTimeTicks, Request, _dlnaManager); await new ProgressiveFileCopier(state.DirectStreamProvider, null, _transcodingJobHelper, CancellationToken.None) - { - AllowEndOfFile = false - }.WriteToAsync(Response.Body, CancellationToken.None) + { + AllowEndOfFile = false + }.WriteToAsync(Response.Body, CancellationToken.None) .ConfigureAwait(false); // TODO (moved from MediaBrowser.Api): Don't hardcode contentType @@ -495,9 +495,9 @@ namespace Jellyfin.Api.Controllers if (state.MediaSource.IsInfiniteStream) { await new ProgressiveFileCopier(state.MediaPath, null, _transcodingJobHelper, CancellationToken.None) - { - AllowEndOfFile = false - }.WriteToAsync(Response.Body, CancellationToken.None) + { + AllowEndOfFile = false + }.WriteToAsync(Response.Body, CancellationToken.None) .ConfigureAwait(false); return File(Response.Body, contentType); @@ -570,7 +570,7 @@ namespace Jellyfin.Api.Controllers /// <param name="cpuCoreLimit">Optional. The limit of how many cpu cores to use.</param> /// <param name="liveStreamId">The live stream id.</param> /// <param name="enableMpegtsM2TsMode">Optional. Whether to enable the MpegtsM2Ts mode.</param> - /// <param name="videoCodec">Optional. Specify a video codec to encode to, e.g. h264. If omitted the server will auto-select using the url's extension. Options: h265, h264, mpeg4, theora, vpx, wmv.</param> + /// <param name="videoCodec">Optional. Specify a video codec to encode to, e.g. h264. If omitted the server will auto-select using the url's extension. Options: h265, h264, mpeg4, theora, vp8, vp9, vpx (deprecated), wmv.</param> /// <param name="subtitleCodec">Optional. Specify a subtitle codec to encode to.</param> /// <param name="transcodeReasons">Optional. The transcoding reason.</param> /// <param name="audioStreamIndex">Optional. The index of the audio stream to use. If omitted the first audio stream will be used.</param> diff --git a/Jellyfin.Api/Helpers/StreamingHelpers.cs b/Jellyfin.Api/Helpers/StreamingHelpers.cs index 8cffe9c4c..adf4789ec 100644 --- a/Jellyfin.Api/Helpers/StreamingHelpers.cs +++ b/Jellyfin.Api/Helpers/StreamingHelpers.cs @@ -439,7 +439,9 @@ namespace Jellyfin.Api.Helpers return ".ogv"; } - if (string.Equals(videoCodec, "vpx", StringComparison.OrdinalIgnoreCase)) + if (string.Equals(videoCodec, "vp8", StringComparison.OrdinalIgnoreCase) + || string.Equals(videoCodec, "vp9", StringComparison.OrdinalIgnoreCase) + || string.Equals(videoCodec, "vpx", StringComparison.OrdinalIgnoreCase)) { return ".webm"; } diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 8a0fae1f6..6d436bf8a 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -206,11 +206,17 @@ namespace MediaBrowser.Controller.MediaEncoding return GetH264Encoder(state, encodingOptions); } - if (string.Equals(codec, "vpx", StringComparison.OrdinalIgnoreCase)) + if (string.Equals(codec, "vp8", StringComparison.OrdinalIgnoreCase) + || string.Equals(codec, "vpx", StringComparison.OrdinalIgnoreCase)) { return "libvpx"; } + if (string.Equals(codec, "vp9", StringComparison.OrdinalIgnoreCase)) + { + return "libvpx-vp9"; + } + if (string.Equals(codec, "wmv", StringComparison.OrdinalIgnoreCase)) { return "wmv2"; @@ -442,7 +448,8 @@ namespace MediaBrowser.Controller.MediaEncoding if (string.Equals(ext, ".webm", StringComparison.OrdinalIgnoreCase)) { - return "vpx"; + // TODO: this may not always mean VP8, as the codec ages + return "vp8"; } if (string.Equals(ext, ".ogg", StringComparison.OrdinalIgnoreCase) || string.Equals(ext, ".ogv", StringComparison.OrdinalIgnoreCase)) @@ -558,12 +565,12 @@ namespace MediaBrowser.Controller.MediaEncoding { if (isOpenclTonemappingSupported && !isVppTonemappingSupported) { - arg.Append("-init_hw_device vaapi=va:") - .Append(options.VaapiDevice) - .Append(" -init_hw_device opencl=ocl@va ") - .Append("-hwaccel_device va ") - .Append("-hwaccel_output_format vaapi ") - .Append("-filter_hw_device ocl "); + arg.Append("-init_hw_device vaapi=va:") + .Append(options.VaapiDevice) + .Append(" -init_hw_device opencl=ocl@va ") + .Append("-hwaccel_device va ") + .Append("-hwaccel_output_format vaapi ") + .Append("-filter_hw_device ocl "); } else { @@ -772,49 +779,37 @@ namespace MediaBrowser.Controller.MediaEncoding public string GetVideoBitrateParam(EncodingJobInfo state, string videoCodec) { - var bitrate = state.OutputVideoBitrate; - - if (bitrate.HasValue) + if (state.OutputVideoBitrate == null) { - if (string.Equals(videoCodec, "libvpx", StringComparison.OrdinalIgnoreCase)) - { - // When crf is used with vpx, b:v becomes a max rate - // https://trac.ffmpeg.org/wiki/Encode/VP9 - return string.Format( - CultureInfo.InvariantCulture, - " -maxrate:v {0} -bufsize:v {1} -b:v {0}", - bitrate.Value, - bitrate.Value * 2); - } + return string.Empty; + } - if (string.Equals(videoCodec, "msmpeg4", StringComparison.OrdinalIgnoreCase)) - { - return string.Format( - CultureInfo.InvariantCulture, - " -b:v {0}", - bitrate.Value); - } + int bitrate = state.OutputVideoBitrate.Value; - if (string.Equals(videoCodec, "libx264", StringComparison.OrdinalIgnoreCase) || - string.Equals(videoCodec, "libx265", StringComparison.OrdinalIgnoreCase)) - { - // h264 - return string.Format( - CultureInfo.InvariantCulture, - " -maxrate {0} -bufsize {1}", - bitrate.Value, - bitrate.Value * 2); - } + // Currently use the same buffer size for all encoders + int bufsize = bitrate * 2; - // h264 - return string.Format( - CultureInfo.InvariantCulture, - " -b:v {0} -maxrate {0} -bufsize {1}", - bitrate.Value, - bitrate.Value * 2); + if (string.Equals(videoCodec, "libvpx", StringComparison.OrdinalIgnoreCase) + || string.Equals(videoCodec, "libvpx-vp9", StringComparison.OrdinalIgnoreCase)) + { + // When crf is used with vpx, b:v becomes a max rate + // https://trac.ffmpeg.org/wiki/Encode/VP8 + // https://trac.ffmpeg.org/wiki/Encode/VP9 + return FormattableString.Invariant($" -maxrate:v {bitrate} -bufsize:v {bufsize} -b:v {bitrate}"); } - return string.Empty; + if (string.Equals(videoCodec, "msmpeg4", StringComparison.OrdinalIgnoreCase)) + { + return FormattableString.Invariant($" -b:v {bitrate}"); + } + + if (string.Equals(videoCodec, "libx264", StringComparison.OrdinalIgnoreCase) + || string.Equals(videoCodec, "libx265", StringComparison.OrdinalIgnoreCase)) + { + return FormattableString.Invariant($" -maxrate {bitrate} -bufsize {bufsize}"); + } + + return FormattableString.Invariant($" -b:v {bitrate} -maxrate {bitrate} -bufsize {bufsize}"); } public static string NormalizeTranscodingLevel(EncodingJobInfo state, string level) @@ -1197,7 +1192,7 @@ namespace MediaBrowser.Controller.MediaEncoding param += " -header_insertion_mode gop -gops_per_idr 1"; } } - else if (string.Equals(videoEncoder, "libvpx", StringComparison.OrdinalIgnoreCase)) // webm + else if (string.Equals(videoEncoder, "libvpx", StringComparison.OrdinalIgnoreCase)) // vp8 { // Values 0-3, 0 being highest quality but slower var profileScore = 0; @@ -1225,6 +1220,55 @@ namespace MediaBrowser.Controller.MediaEncoding qmin, qmax); } + else if (string.Equals(videoEncoder, "libvpx-vp9", StringComparison.OrdinalIgnoreCase)) // vp9 + { + // When `-deadline` is set to `good` or `best`, `-cpu-used` ranges from 0-5. + // When `-deadline` is set to `realtime`, `-cpu-used` ranges from 0-15. + // Resources: + // * https://trac.ffmpeg.org/wiki/Encode/VP9 + // * https://superuser.com/questions/1586934 + // * https://developers.google.com/media/vp9 + param += encodingOptions.EncoderPreset switch + { + "veryslow" => " -deadline best -cpu-used 0", + "slower" => " -deadline best -cpu-used 2", + "slow" => " -deadline best -cpu-used 3", + "medium" => " -deadline good -cpu-used 0", + "fast" => " -deadline good -cpu-used 1", + "faster" => " -deadline good -cpu-used 2", + "veryfast" => " -deadline good -cpu-used 3", + "superfast" => " -deadline good -cpu-used 4", + "ultrafast" => " -deadline good -cpu-used 5", + _ => " -deadline good -cpu-used 1" + }; + + // TODO: until VP9 gets its own CRF setting, base CRF on H.265. + int h265Crf = encodingOptions.H265Crf; + int defaultVp9Crf = 31; + if (h265Crf >= 0 && h265Crf <= 51) + { + // This conversion factor is chosen to match the default CRF for H.265 to the + // recommended 1080p CRF from Google. The factor also maps the logarithmic CRF + // scale of x265 [0, 51] to that of VP9 [0, 63] relatively well. + + // Resources: + // * https://developers.google.com/media/vp9/settings/vod + const float H265ToVp9CrfConversionFactor = 1.12F; + + var vp9Crf = Convert.ToInt32(h265Crf * H265ToVp9CrfConversionFactor); + + // Encoder allows for CRF values in the range [0, 63]. + vp9Crf = Math.Clamp(vp9Crf, 0, 63); + + param += FormattableString.Invariant($" -crf {vp9Crf}"); + } + else + { + param += FormattableString.Invariant($" -crf {defaultVp9Crf}"); + } + + param += " -row-mt 1 -profile 1"; + } else if (string.Equals(videoEncoder, "mpeg4", StringComparison.OrdinalIgnoreCase)) { param += " -mbd rd -flags +mv4+aic -trellis 2 -cmp 2 -subcmp 2 -bf 2"; @@ -3149,20 +3193,16 @@ namespace MediaBrowser.Controller.MediaEncoding #nullable enable public static int GetNumberOfThreads(EncodingJobInfo? state, EncodingOptions encodingOptions, string? outputVideoCodec) { - if (string.Equals(outputVideoCodec, "libvpx", StringComparison.OrdinalIgnoreCase)) - { - // per docs: - // -threads number of threads to use for encoding, can't be 0 [auto] with VP8 - // (recommended value : number of real cores - 1) - return Math.Max(Environment.ProcessorCount - 1, 1); - } + // VP8 and VP9 encoders must have their thread counts set. + bool mustSetThreadCount = string.Equals(outputVideoCodec, "libvpx", StringComparison.OrdinalIgnoreCase) + || string.Equals(outputVideoCodec, "libvpx-vp9", StringComparison.OrdinalIgnoreCase); var threads = state?.BaseRequest.CpuCoreLimit ?? encodingOptions.EncodingThreadCount; - // Automatic if (threads <= 0) { - return 0; + // Automatically set thread count + return mustSetThreadCount ? Math.Max(Environment.ProcessorCount - 1, 1) : 0; } else if (threads >= Environment.ProcessorCount) { -- cgit v1.2.3 From 0d16c489985da50ddd13ef228c73b3bcb0ae5f67 Mon Sep 17 00:00:00 2001 From: Bond_009 <bond.009@outlook.com> Date: Thu, 9 Sep 2021 15:59:13 +0200 Subject: Fix some warnings --- MediaBrowser.Controller/Entities/Folder.cs | 6 +++--- MediaBrowser.Controller/Entities/UserRootFolder.cs | 16 ++++++++-------- MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs | 12 ++++++------ .../PlaybackRequests/RemoveFromPlaylistGroupRequest.cs | 1 - MediaBrowser.Model/Configuration/MetadataOptions.cs | 2 +- MediaBrowser.Model/Dlna/ResolutionNormalizer.cs | 2 +- MediaBrowser.Model/Users/UserPolicy.cs | 2 +- MediaBrowser.Providers/MediaBrowser.Providers.csproj | 2 -- jellyfin.ruleset | 10 +++++++--- 9 files changed, 27 insertions(+), 26 deletions(-) (limited to 'MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs') diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index dd08c31ed..18b4ec3c6 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -1015,17 +1015,17 @@ namespace MediaBrowser.Controller.Entities if (!string.IsNullOrEmpty(query.NameStartsWithOrGreater)) { - items = items.Where(i => string.Compare(query.NameStartsWithOrGreater, i.SortName, StringComparison.CurrentCultureIgnoreCase) < 1); + items = items.Where(i => string.Compare(query.NameStartsWithOrGreater, i.SortName, StringComparison.InvariantCultureIgnoreCase) < 1); } if (!string.IsNullOrEmpty(query.NameStartsWith)) { - items = items.Where(i => i.SortName.StartsWith(query.NameStartsWith, StringComparison.CurrentCultureIgnoreCase)); + items = items.Where(i => i.SortName.StartsWith(query.NameStartsWith, StringComparison.InvariantCultureIgnoreCase)); } if (!string.IsNullOrEmpty(query.NameLessThan)) { - items = items.Where(i => string.Compare(query.NameLessThan, i.SortName, StringComparison.CurrentCultureIgnoreCase) == 1); + items = items.Where(i => string.Compare(query.NameLessThan, i.SortName, StringComparison.InvariantCultureIgnoreCase) == 1); } // This must be the last filter diff --git a/MediaBrowser.Controller/Entities/UserRootFolder.cs b/MediaBrowser.Controller/Entities/UserRootFolder.cs index c07fb40b3..e547db523 100644 --- a/MediaBrowser.Controller/Entities/UserRootFolder.cs +++ b/MediaBrowser.Controller/Entities/UserRootFolder.cs @@ -24,6 +24,14 @@ namespace MediaBrowser.Controller.Entities private readonly object _childIdsLock = new object(); private List<Guid> _childrenIds = null; + /// <summary> + /// Initializes a new instance of the <see cref="UserRootFolder"/> class. + /// </summary> + public UserRootFolder() + { + IsRoot = true; + } + [JsonIgnore] public override bool SupportsInheritedParentImages => false; @@ -44,14 +52,6 @@ namespace MediaBrowser.Controller.Entities } } - /// <summary> - /// Initializes a new instance of the <see cref="UserRootFolder"/> class. - /// </summary> - public UserRootFolder() - { - IsRoot = true; - } - protected override List<BaseItem> LoadChildren() { lock (_childIdsLock) diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index ec44150a2..bdb379332 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -37,7 +37,7 @@ namespace MediaBrowser.Controller.MediaEncoding "ConstrainedHigh" }; - private static readonly Version minVersionForCudaOverlay = new Version(4, 4); + private static readonly Version _minVersionForCudaOverlay = new Version(4, 4); public EncodingHelper( IMediaEncoder mediaEncoder, @@ -647,8 +647,8 @@ namespace MediaBrowser.Controller.MediaEncoding } if (state.IsVideoRequest - && ((string.Equals(options.HardwareAccelerationType, "nvenc", StringComparison.OrdinalIgnoreCase) - && (isNvdecDecoder || isCuvidHevcDecoder || isCuvidVp9Decoder || isSwDecoder)))) + && string.Equals(options.HardwareAccelerationType, "nvenc", StringComparison.OrdinalIgnoreCase) + && (isNvdecDecoder || isCuvidHevcDecoder || isCuvidVp9Decoder || isSwDecoder)) { if (!isCudaTonemappingSupported && isOpenclTonemappingSupported) { @@ -2099,7 +2099,7 @@ namespace MediaBrowser.Controller.MediaEncoding var isVppTonemappingSupported = IsVppTonemappingSupported(state, options); var mediaEncoderVersion = _mediaEncoder.GetMediaEncoderVersion(); - var isCudaOverlaySupported = _mediaEncoder.SupportsFilter("overlay_cuda") && mediaEncoderVersion != null && mediaEncoderVersion >= minVersionForCudaOverlay; + var isCudaOverlaySupported = _mediaEncoder.SupportsFilter("overlay_cuda") && mediaEncoderVersion != null && mediaEncoderVersion >= _minVersionForCudaOverlay; var isCudaFormatConversionSupported = _mediaEncoder.SupportsFilterWithOption(FilterOptionType.ScaleCudaFormat); // Tonemapping and burn-in graphical subtitles requires overlay_vaapi. @@ -2380,7 +2380,7 @@ namespace MediaBrowser.Controller.MediaEncoding var isCudaTonemappingSupported = IsCudaTonemappingSupported(state, options); var isTonemappingSupportedOnNvenc = string.Equals(options.HardwareAccelerationType, "nvenc", StringComparison.OrdinalIgnoreCase); var mediaEncoderVersion = _mediaEncoder.GetMediaEncoderVersion(); - var isCudaOverlaySupported = _mediaEncoder.SupportsFilter("overlay_cuda") && mediaEncoderVersion != null && mediaEncoderVersion >= minVersionForCudaOverlay; + var isCudaOverlaySupported = _mediaEncoder.SupportsFilter("overlay_cuda") && mediaEncoderVersion != null && mediaEncoderVersion >= _minVersionForCudaOverlay; var isCudaFormatConversionSupported = _mediaEncoder.SupportsFilterWithOption(FilterOptionType.ScaleCudaFormat); var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode; @@ -2683,7 +2683,7 @@ namespace MediaBrowser.Controller.MediaEncoding var isVppTonemappingSupported = IsVppTonemappingSupported(state, options); var isCudaTonemappingSupported = IsCudaTonemappingSupported(state, options); var mediaEncoderVersion = _mediaEncoder.GetMediaEncoderVersion(); - var isCudaOverlaySupported = _mediaEncoder.SupportsFilter("overlay_cuda") && mediaEncoderVersion != null && mediaEncoderVersion >= minVersionForCudaOverlay; + var isCudaOverlaySupported = _mediaEncoder.SupportsFilter("overlay_cuda") && mediaEncoderVersion != null && mediaEncoderVersion >= _minVersionForCudaOverlay; var hasSubs = state.SubtitleStream != null && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode; var hasTextSubs = state.SubtitleStream != null && state.SubtitleStream.IsTextSubtitleStream && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode; diff --git a/MediaBrowser.Controller/SyncPlay/PlaybackRequests/RemoveFromPlaylistGroupRequest.cs b/MediaBrowser.Controller/SyncPlay/PlaybackRequests/RemoveFromPlaylistGroupRequest.cs index 856f175df..2f38d6adc 100644 --- a/MediaBrowser.Controller/SyncPlay/PlaybackRequests/RemoveFromPlaylistGroupRequest.cs +++ b/MediaBrowser.Controller/SyncPlay/PlaybackRequests/RemoveFromPlaylistGroupRequest.cs @@ -19,7 +19,6 @@ namespace MediaBrowser.Controller.SyncPlay.PlaybackRequests /// <param name="items">The playlist ids of the items to remove.</param> /// <param name="clearPlaylist">Whether to clear the entire playlist. The items list will be ignored.</param> /// <param name="clearPlayingItem">Whether to remove the playing item as well. Used only when clearing the playlist.</param> - public RemoveFromPlaylistGroupRequest(IReadOnlyList<Guid> items, bool clearPlaylist = false, bool clearPlayingItem = false) { PlaylistItemIds = items ?? Array.Empty<Guid>(); diff --git a/MediaBrowser.Model/Configuration/MetadataOptions.cs b/MediaBrowser.Model/Configuration/MetadataOptions.cs index 76b72bd08..384a7997f 100644 --- a/MediaBrowser.Model/Configuration/MetadataOptions.cs +++ b/MediaBrowser.Model/Configuration/MetadataOptions.cs @@ -1,5 +1,5 @@ #nullable disable -#pragma warning disable CS1591 +#pragma warning disable CS1591, CA1819 using System; diff --git a/MediaBrowser.Model/Dlna/ResolutionNormalizer.cs b/MediaBrowser.Model/Dlna/ResolutionNormalizer.cs index 806877ff0..94071b419 100644 --- a/MediaBrowser.Model/Dlna/ResolutionNormalizer.cs +++ b/MediaBrowser.Model/Dlna/ResolutionNormalizer.cs @@ -5,7 +5,7 @@ using System; namespace MediaBrowser.Model.Dlna { - public class ResolutionNormalizer + public static class ResolutionNormalizer { private static readonly ResolutionConfiguration[] Configurations = new[] diff --git a/MediaBrowser.Model/Users/UserPolicy.cs b/MediaBrowser.Model/Users/UserPolicy.cs index 111070d81..3634d0705 100644 --- a/MediaBrowser.Model/Users/UserPolicy.cs +++ b/MediaBrowser.Model/Users/UserPolicy.cs @@ -1,5 +1,5 @@ #nullable disable -#pragma warning disable CS1591 +#pragma warning disable CS1591, CA1819 using System; using System.Xml.Serialization; diff --git a/MediaBrowser.Providers/MediaBrowser.Providers.csproj b/MediaBrowser.Providers/MediaBrowser.Providers.csproj index 3d866cdc2..52611c427 100644 --- a/MediaBrowser.Providers/MediaBrowser.Providers.csproj +++ b/MediaBrowser.Providers/MediaBrowser.Providers.csproj @@ -29,8 +29,6 @@ <TargetFramework>net5.0</TargetFramework> <GenerateAssemblyInfo>false</GenerateAssemblyInfo> <GenerateDocumentationFile>true</GenerateDocumentationFile> - <TreatWarningsAsErrors>true</TreatWarningsAsErrors> - <AnalysisMode Condition=" '$(Configuration)' == 'Debug'">AllEnabledByDefault</AnalysisMode> <CodeAnalysisRuleSet>../jellyfin.ruleset</CodeAnalysisRuleSet> <Nullable>disable</Nullable> </PropertyGroup> diff --git a/jellyfin.ruleset b/jellyfin.ruleset index 68fb9064e..dfb991170 100644 --- a/jellyfin.ruleset +++ b/jellyfin.ruleset @@ -1,9 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> <RuleSet Name="Rules for Jellyfin.Server" Description="Code analysis rules for Jellyfin.Server.csproj" ToolsVersion="14.0"> <Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.Analyzers"> - <!-- disable warning CA1040: Avoid empty interfaces --> - <Rule Id="CA1040" Action="Info" /> - <!-- disable warning SA1009: Closing parenthesis should be followed by a space. --> <Rule Id="SA1009" Action="None" /> <!-- disable warning SA1011: Closing square bracket should be followed by a space. --> @@ -57,12 +54,19 @@ <Rule Id="CA1031" Action="Info" /> <!-- disable warning CA1032: Implement standard exception constructors --> <Rule Id="CA1032" Action="Info" /> + <!-- disable warning CA1040: Avoid empty interfaces --> + <Rule Id="CA1040" Action="Info" /> <!-- disable warning CA1062: Validate arguments of public methods --> <Rule Id="CA1062" Action="Info" /> + <!-- TODO: enable when false positives are fixed --> + <!-- disable warning CA1508: Avoid dead conditional code --> + <Rule Id="CA1508" Action="Info" /> <!-- disable warning CA1716: Identifiers should not match keywords --> <Rule Id="CA1716" Action="Info" /> <!-- disable warning CA1720: Identifiers should not contain type names --> <Rule Id="CA1720" Action="Info" /> + <!-- disable warning CA1724: Type names should not match namespaces --> + <Rule Id="CA1724" Action="Info" /> <!-- disable warning CA1805: Do not initialize unnecessarily --> <Rule Id="CA1805" Action="Info" /> <!-- disable warning CA1812: internal class that is apparently never instantiated. -- cgit v1.2.3 From 9234e5bf80194e45acac25c60cb76f401bffaf96 Mon Sep 17 00:00:00 2001 From: Cody Robibero <cody@robibe.ro> Date: Sun, 26 Sep 2021 08:14:36 -0600 Subject: Remove all instances of en-US culture --- Emby.Dlna/Didl/DidlBuilder.cs | 28 +++++++-------- Emby.Dlna/Eventing/DlnaEventManager.cs | 8 ++--- Emby.Dlna/PlayTo/Device.cs | 12 +++---- Emby.Dlna/PlayTo/PlayToController.cs | 8 ++--- Emby.Dlna/PlayTo/SsdpHttpClient.cs | 8 ++--- Emby.Dlna/Server/DescriptionXmlBuilder.cs | 5 ++- .../MediaEncoder/EncodingManager.cs | 3 +- Jellyfin.Api/Controllers/ImageController.cs | 2 +- Jellyfin.Api/Controllers/SubtitleController.cs | 2 +- MediaBrowser.Controller/Entities/Year.cs | 4 +-- .../MediaEncoding/EncodingHelper.cs | 42 +++++++++++----------- MediaBrowser.Controller/MediaEncoding/JobLogger.cs | 11 +++--- .../Images/LocalImageProvider.cs | 4 +-- .../Parsers/BaseItemXmlParser.cs | 8 ++--- MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs | 12 +++---- MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 11 ++---- .../Probing/ProbeResultNormalizer.cs | 27 +++++++------- .../Globalization/ILocalizationManager.cs | 4 +-- MediaBrowser.Providers/Manager/ImageSaver.cs | 18 +++++----- .../Plugins/Omdb/OmdbProvider.cs | 13 ++++--- MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs | 10 +++--- .../Parsers/EpisodeNfoParser.cs | 10 +++--- .../Savers/EpisodeNfoSaver.cs | 18 +++++----- 23 files changed, 116 insertions(+), 152 deletions(-) (limited to 'MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs') diff --git a/Emby.Dlna/Didl/DidlBuilder.cs b/Emby.Dlna/Didl/DidlBuilder.cs index c00078499..0a84f30c4 100644 --- a/Emby.Dlna/Didl/DidlBuilder.cs +++ b/Emby.Dlna/Didl/DidlBuilder.cs @@ -41,8 +41,6 @@ namespace Emby.Dlna.Didl private const string NsUpnp = "urn:schemas-upnp-org:metadata-1-0/upnp/"; private const string NsDlna = "urn:schemas-dlna-org:metadata-1-0/"; - private readonly CultureInfo _usCulture = new CultureInfo("en-US"); - private readonly DeviceProfile _profile; private readonly IImageProcessor _imageProcessor; private readonly string _serverAddress; @@ -317,7 +315,7 @@ namespace Emby.Dlna.Didl if (mediaSource.RunTimeTicks.HasValue) { - writer.WriteAttributeString("duration", TimeSpan.FromTicks(mediaSource.RunTimeTicks.Value).ToString("c", _usCulture)); + writer.WriteAttributeString("duration", TimeSpan.FromTicks(mediaSource.RunTimeTicks.Value).ToString("c", CultureInfo.InvariantCulture)); } if (filter.Contains("res@size")) @@ -328,7 +326,7 @@ namespace Emby.Dlna.Didl if (size.HasValue) { - writer.WriteAttributeString("size", size.Value.ToString(_usCulture)); + writer.WriteAttributeString("size", size.Value.ToString(CultureInfo.InvariantCulture)); } } } @@ -342,7 +340,7 @@ namespace Emby.Dlna.Didl if (targetChannels.HasValue) { - writer.WriteAttributeString("nrAudioChannels", targetChannels.Value.ToString(_usCulture)); + writer.WriteAttributeString("nrAudioChannels", targetChannels.Value.ToString(CultureInfo.InvariantCulture)); } if (filter.Contains("res@resolution")) @@ -361,12 +359,12 @@ namespace Emby.Dlna.Didl if (targetSampleRate.HasValue) { - writer.WriteAttributeString("sampleFrequency", targetSampleRate.Value.ToString(_usCulture)); + writer.WriteAttributeString("sampleFrequency", targetSampleRate.Value.ToString(CultureInfo.InvariantCulture)); } if (totalBitrate.HasValue) { - writer.WriteAttributeString("bitrate", totalBitrate.Value.ToString(_usCulture)); + writer.WriteAttributeString("bitrate", totalBitrate.Value.ToString(CultureInfo.InvariantCulture)); } var mediaProfile = _profile.GetVideoMediaProfile( @@ -552,7 +550,7 @@ namespace Emby.Dlna.Didl if (mediaSource.RunTimeTicks.HasValue) { - writer.WriteAttributeString("duration", TimeSpan.FromTicks(mediaSource.RunTimeTicks.Value).ToString("c", _usCulture)); + writer.WriteAttributeString("duration", TimeSpan.FromTicks(mediaSource.RunTimeTicks.Value).ToString("c", CultureInfo.InvariantCulture)); } if (filter.Contains("res@size")) @@ -563,7 +561,7 @@ namespace Emby.Dlna.Didl if (size.HasValue) { - writer.WriteAttributeString("size", size.Value.ToString(_usCulture)); + writer.WriteAttributeString("size", size.Value.ToString(CultureInfo.InvariantCulture)); } } } @@ -575,17 +573,17 @@ namespace Emby.Dlna.Didl if (targetChannels.HasValue) { - writer.WriteAttributeString("nrAudioChannels", targetChannels.Value.ToString(_usCulture)); + writer.WriteAttributeString("nrAudioChannels", targetChannels.Value.ToString(CultureInfo.InvariantCulture)); } if (targetSampleRate.HasValue) { - writer.WriteAttributeString("sampleFrequency", targetSampleRate.Value.ToString(_usCulture)); + writer.WriteAttributeString("sampleFrequency", targetSampleRate.Value.ToString(CultureInfo.InvariantCulture)); } if (targetAudioBitrate.HasValue) { - writer.WriteAttributeString("bitrate", targetAudioBitrate.Value.ToString(_usCulture)); + writer.WriteAttributeString("bitrate", targetAudioBitrate.Value.ToString(CultureInfo.InvariantCulture)); } var mediaProfile = _profile.GetAudioMediaProfile( @@ -639,7 +637,7 @@ namespace Emby.Dlna.Didl writer.WriteAttributeString("restricted", "1"); writer.WriteAttributeString("searchable", "1"); - writer.WriteAttributeString("childCount", childCount.ToString(_usCulture)); + writer.WriteAttributeString("childCount", childCount.ToString(CultureInfo.InvariantCulture)); var clientId = GetClientId(folder, stubType); @@ -931,11 +929,11 @@ namespace Emby.Dlna.Didl if (item.IndexNumber.HasValue) { - AddValue(writer, "upnp", "originalTrackNumber", item.IndexNumber.Value.ToString(_usCulture), NsUpnp); + AddValue(writer, "upnp", "originalTrackNumber", item.IndexNumber.Value.ToString(CultureInfo.InvariantCulture), NsUpnp); if (item is Episode) { - AddValue(writer, "upnp", "episodeNumber", item.IndexNumber.Value.ToString(_usCulture), NsUpnp); + AddValue(writer, "upnp", "episodeNumber", item.IndexNumber.Value.ToString(CultureInfo.InvariantCulture), NsUpnp); } } } diff --git a/Emby.Dlna/Eventing/DlnaEventManager.cs b/Emby.Dlna/Eventing/DlnaEventManager.cs index b39bd5ce9..d17e23871 100644 --- a/Emby.Dlna/Eventing/DlnaEventManager.cs +++ b/Emby.Dlna/Eventing/DlnaEventManager.cs @@ -26,8 +26,6 @@ namespace Emby.Dlna.Eventing private readonly ILogger _logger; private readonly IHttpClientFactory _httpClientFactory; - private readonly CultureInfo _usCulture = new CultureInfo("en-US"); - public DlnaEventManager(ILogger logger, IHttpClientFactory httpClientFactory) { _httpClientFactory = httpClientFactory; @@ -83,7 +81,7 @@ namespace Emby.Dlna.Eventing if (!string.IsNullOrEmpty(header)) { // Starts with SECOND- - if (int.TryParse(header.AsSpan().RightPart('-'), NumberStyles.Integer, _usCulture, out var val)) + if (int.TryParse(header.AsSpan().RightPart('-'), NumberStyles.Integer, CultureInfo.InvariantCulture, out var val)) { return val; } @@ -106,7 +104,7 @@ namespace Emby.Dlna.Eventing var response = new EventSubscriptionResponse(string.Empty, "text/plain"); response.Headers["SID"] = subscriptionId; - response.Headers["TIMEOUT"] = string.IsNullOrEmpty(requestedTimeoutString) ? ("SECOND-" + timeoutSeconds.ToString(_usCulture)) : requestedTimeoutString; + response.Headers["TIMEOUT"] = string.IsNullOrEmpty(requestedTimeoutString) ? ("SECOND-" + timeoutSeconds.ToString(CultureInfo.InvariantCulture)) : requestedTimeoutString; return response; } @@ -163,7 +161,7 @@ namespace Emby.Dlna.Eventing options.Headers.TryAddWithoutValidation("NT", subscription.NotificationType); options.Headers.TryAddWithoutValidation("NTS", "upnp:propchange"); options.Headers.TryAddWithoutValidation("SID", subscription.Id); - options.Headers.TryAddWithoutValidation("SEQ", subscription.TriggerCount.ToString(_usCulture)); + options.Headers.TryAddWithoutValidation("SEQ", subscription.TriggerCount.ToString(CultureInfo.InvariantCulture)); try { diff --git a/Emby.Dlna/PlayTo/Device.cs b/Emby.Dlna/PlayTo/Device.cs index 11fcd81cf..0b2288000 100644 --- a/Emby.Dlna/PlayTo/Device.cs +++ b/Emby.Dlna/PlayTo/Device.cs @@ -20,8 +20,6 @@ namespace Emby.Dlna.PlayTo { public class Device : IDisposable { - private static readonly CultureInfo UsCulture = new CultureInfo("en-US"); - private readonly IHttpClientFactory _httpClientFactory; private readonly ILogger _logger; @@ -640,7 +638,7 @@ namespace Emby.Dlna.PlayTo return; } - Volume = int.Parse(volumeValue, UsCulture); + Volume = int.Parse(volumeValue, CultureInfo.InvariantCulture); if (Volume > 0) { @@ -842,7 +840,7 @@ namespace Emby.Dlna.PlayTo if (!string.IsNullOrWhiteSpace(duration) && !string.Equals(duration, "NOT_IMPLEMENTED", StringComparison.OrdinalIgnoreCase)) { - Duration = TimeSpan.Parse(duration, UsCulture); + Duration = TimeSpan.Parse(duration, CultureInfo.InvariantCulture); } else { @@ -854,7 +852,7 @@ namespace Emby.Dlna.PlayTo if (!string.IsNullOrWhiteSpace(position) && !string.Equals(position, "NOT_IMPLEMENTED", StringComparison.OrdinalIgnoreCase)) { - Position = TimeSpan.Parse(position, UsCulture); + Position = TimeSpan.Parse(position, CultureInfo.InvariantCulture); } var track = result.Document.Descendants("TrackMetaData").FirstOrDefault(); @@ -1194,8 +1192,8 @@ namespace Emby.Dlna.PlayTo var depth = element.GetDescendantValue(UPnpNamespaces.Ud.GetName("depth")); var url = element.GetDescendantValue(UPnpNamespaces.Ud.GetName("url")); - var widthValue = int.Parse(width, NumberStyles.Integer, UsCulture); - var heightValue = int.Parse(height, NumberStyles.Integer, UsCulture); + var widthValue = int.Parse(width, NumberStyles.Integer, CultureInfo.InvariantCulture); + var heightValue = int.Parse(height, NumberStyles.Integer, CultureInfo.InvariantCulture); return new DeviceIcon { diff --git a/Emby.Dlna/PlayTo/PlayToController.cs b/Emby.Dlna/PlayTo/PlayToController.cs index 0e49fd2c0..f25d8017e 100644 --- a/Emby.Dlna/PlayTo/PlayToController.cs +++ b/Emby.Dlna/PlayTo/PlayToController.cs @@ -30,8 +30,6 @@ namespace Emby.Dlna.PlayTo { public class PlayToController : ISessionController, IDisposable { - private static readonly CultureInfo _usCulture = CultureInfo.ReadOnly(new CultureInfo("en-US")); - private readonly SessionInfo _session; private readonly ISessionManager _sessionManager; private readonly ILibraryManager _libraryManager; @@ -716,7 +714,7 @@ namespace Emby.Dlna.PlayTo case GeneralCommandType.SetAudioStreamIndex: if (command.Arguments.TryGetValue("Index", out string index)) { - if (int.TryParse(index, NumberStyles.Integer, _usCulture, out var val)) + if (int.TryParse(index, NumberStyles.Integer, CultureInfo.InvariantCulture, out var val)) { return SetAudioStreamIndex(val); } @@ -728,7 +726,7 @@ namespace Emby.Dlna.PlayTo case GeneralCommandType.SetSubtitleStreamIndex: if (command.Arguments.TryGetValue("Index", out index)) { - if (int.TryParse(index, NumberStyles.Integer, _usCulture, out var val)) + if (int.TryParse(index, NumberStyles.Integer, CultureInfo.InvariantCulture, out var val)) { return SetSubtitleStreamIndex(val); } @@ -740,7 +738,7 @@ namespace Emby.Dlna.PlayTo case GeneralCommandType.SetVolume: if (command.Arguments.TryGetValue("Volume", out string vol)) { - if (int.TryParse(vol, NumberStyles.Integer, _usCulture, out var volume)) + if (int.TryParse(vol, NumberStyles.Integer, CultureInfo.InvariantCulture, out var volume)) { return _device.SetVolume(volume, cancellationToken); } diff --git a/Emby.Dlna/PlayTo/SsdpHttpClient.cs b/Emby.Dlna/PlayTo/SsdpHttpClient.cs index 4b92fbff4..cade7b4c2 100644 --- a/Emby.Dlna/PlayTo/SsdpHttpClient.cs +++ b/Emby.Dlna/PlayTo/SsdpHttpClient.cs @@ -20,8 +20,6 @@ namespace Emby.Dlna.PlayTo private const string USERAGENT = "Microsoft-Windows/6.2 UPnP/1.0 Microsoft-DLNA DLNADOC/1.50"; private const string FriendlyName = "Jellyfin"; - private readonly CultureInfo _usCulture = new CultureInfo("en-US"); - private readonly IHttpClientFactory _httpClientFactory; public SsdpHttpClient(IHttpClientFactory httpClientFactory) @@ -80,10 +78,10 @@ namespace Emby.Dlna.PlayTo { using var options = new HttpRequestMessage(new HttpMethod("SUBSCRIBE"), url); options.Headers.UserAgent.ParseAdd(USERAGENT); - options.Headers.TryAddWithoutValidation("HOST", ip + ":" + port.ToString(_usCulture)); - options.Headers.TryAddWithoutValidation("CALLBACK", "<" + localIp + ":" + eventport.ToString(_usCulture) + ">"); + options.Headers.TryAddWithoutValidation("HOST", ip + ":" + port.ToString(CultureInfo.InvariantCulture)); + options.Headers.TryAddWithoutValidation("CALLBACK", "<" + localIp + ":" + eventport.ToString(CultureInfo.InvariantCulture) + ">"); options.Headers.TryAddWithoutValidation("NT", "upnp:event"); - options.Headers.TryAddWithoutValidation("TIMEOUT", "Second-" + timeOut.ToString(_usCulture)); + options.Headers.TryAddWithoutValidation("TIMEOUT", "Second-" + timeOut.ToString(CultureInfo.InvariantCulture)); using var response = await _httpClientFactory.CreateClient(NamedClient.Default) .SendAsync(options, HttpCompletionOption.ResponseHeadersRead) diff --git a/Emby.Dlna/Server/DescriptionXmlBuilder.cs b/Emby.Dlna/Server/DescriptionXmlBuilder.cs index 09525aae4..80a45f2b2 100644 --- a/Emby.Dlna/Server/DescriptionXmlBuilder.cs +++ b/Emby.Dlna/Server/DescriptionXmlBuilder.cs @@ -15,7 +15,6 @@ namespace Emby.Dlna.Server { private readonly DeviceProfile _profile; - private readonly CultureInfo _usCulture = new CultureInfo("en-US"); private readonly string _serverUdn; private readonly string _serverAddress; private readonly string _serverName; @@ -193,10 +192,10 @@ namespace Emby.Dlna.Server .Append(SecurityElement.Escape(icon.MimeType ?? string.Empty)) .Append("</mimetype>"); builder.Append("<width>") - .Append(SecurityElement.Escape(icon.Width.ToString(_usCulture))) + .Append(SecurityElement.Escape(icon.Width.ToString(CultureInfo.InvariantCulture))) .Append("</width>"); builder.Append("<height>") - .Append(SecurityElement.Escape(icon.Height.ToString(_usCulture))) + .Append(SecurityElement.Escape(icon.Height.ToString(CultureInfo.InvariantCulture))) .Append("</height>"); builder.Append("<depth>") .Append(SecurityElement.Escape(icon.Depth ?? string.Empty)) diff --git a/Emby.Server.Implementations/MediaEncoder/EncodingManager.cs b/Emby.Server.Implementations/MediaEncoder/EncodingManager.cs index 8aaa1f7bb..ac6606d39 100644 --- a/Emby.Server.Implementations/MediaEncoder/EncodingManager.cs +++ b/Emby.Server.Implementations/MediaEncoder/EncodingManager.cs @@ -23,7 +23,6 @@ namespace Emby.Server.Implementations.MediaEncoder { public class EncodingManager : IEncodingManager { - private readonly CultureInfo _usCulture = new CultureInfo("en-US"); private readonly IFileSystem _fileSystem; private readonly ILogger<EncodingManager> _logger; private readonly IMediaEncoder _encoder; @@ -193,7 +192,7 @@ namespace Emby.Server.Implementations.MediaEncoder private string GetChapterImagePath(Video video, long chapterPositionTicks) { - var filename = video.DateModified.Ticks.ToString(_usCulture) + "_" + chapterPositionTicks.ToString(_usCulture) + ".jpg"; + var filename = video.DateModified.Ticks.ToString(CultureInfo.InvariantCulture) + "_" + chapterPositionTicks.ToString(CultureInfo.InvariantCulture) + ".jpg"; return Path.Combine(GetChapterImagesPath(video), filename); } diff --git a/Jellyfin.Api/Controllers/ImageController.cs b/Jellyfin.Api/Controllers/ImageController.cs index b1c860d61..86933074d 100644 --- a/Jellyfin.Api/Controllers/ImageController.cs +++ b/Jellyfin.Api/Controllers/ImageController.cs @@ -2007,7 +2007,7 @@ namespace Jellyfin.Api.Controllers Response.Headers.Add(HeaderNames.CacheControl, "public"); } - Response.Headers.Add(HeaderNames.LastModified, dateImageModified.ToUniversalTime().ToString("ddd, dd MMM yyyy HH:mm:ss \"GMT\"", new CultureInfo("en-US", false))); + Response.Headers.Add(HeaderNames.LastModified, dateImageModified.ToUniversalTime().ToString("ddd, dd MMM yyyy HH:mm:ss \"GMT\"", CultureInfo.InvariantCulture)); // if the image was not modified since "ifModifiedSinceHeader"-header, return a HTTP status code 304 not modified if (!(dateImageModified > ifModifiedSinceHeader) && cacheDuration.HasValue) diff --git a/Jellyfin.Api/Controllers/SubtitleController.cs b/Jellyfin.Api/Controllers/SubtitleController.cs index 11f67ee89..1849dd047 100644 --- a/Jellyfin.Api/Controllers/SubtitleController.cs +++ b/Jellyfin.Api/Controllers/SubtitleController.cs @@ -376,7 +376,7 @@ namespace Jellyfin.Api.Controllers var endPositionTicks = Math.Min(runtime, positionTicks + segmentLengthTicks); var url = string.Format( - CultureInfo.CurrentCulture, + CultureInfo.InvariantCulture, "stream.vtt?CopyTimestamps=true&AddVttTimeMap=true&StartPositionTicks={0}&EndPositionTicks={1}&api_key={2}", positionTicks.ToString(CultureInfo.InvariantCulture), endPositionTicks.ToString(CultureInfo.InvariantCulture), diff --git a/MediaBrowser.Controller/Entities/Year.cs b/MediaBrowser.Controller/Entities/Year.cs index 0853200dd..afdaf448b 100644 --- a/MediaBrowser.Controller/Entities/Year.cs +++ b/MediaBrowser.Controller/Entities/Year.cs @@ -57,9 +57,7 @@ namespace MediaBrowser.Controller.Entities public IList<BaseItem> GetTaggedItems(InternalItemsQuery query) { - var usCulture = new CultureInfo("en-US"); - - if (!int.TryParse(Name, NumberStyles.Integer, usCulture, out var year)) + if (!int.TryParse(Name, NumberStyles.Integer, CultureInfo.InvariantCulture, out var year)) { return new List<BaseItem>(); } diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index bdb379332..5715194b8 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -21,8 +21,6 @@ namespace MediaBrowser.Controller.MediaEncoding { public class EncodingHelper { - private static readonly CultureInfo _usCulture = new CultureInfo("en-US"); - private readonly IMediaEncoder _mediaEncoder; private readonly ISubtitleEncoder _subtitleEncoder; @@ -816,7 +814,7 @@ namespace MediaBrowser.Controller.MediaEncoding public static string NormalizeTranscodingLevel(EncodingJobInfo state, string level) { - if (double.TryParse(level, NumberStyles.Any, _usCulture, out double requestLevel)) + if (double.TryParse(level, NumberStyles.Any, CultureInfo.InvariantCulture, out double requestLevel)) { if (string.Equals(state.ActualOutputVideoCodec, "hevc", StringComparison.OrdinalIgnoreCase) || string.Equals(state.ActualOutputVideoCodec, "h265", StringComparison.OrdinalIgnoreCase)) @@ -911,7 +909,7 @@ namespace MediaBrowser.Controller.MediaEncoding CultureInfo.InvariantCulture, "subtitles='{0}:si={1}'{2}", _mediaEncoder.EscapeSubtitleFilterPath(mediaPath), - state.InternalSubtitleStreamOffset.ToString(_usCulture), + state.InternalSubtitleStreamOffset.ToString(CultureInfo.InvariantCulture), // fallbackFontParam, setPtsParam); } @@ -1217,7 +1215,7 @@ namespace MediaBrowser.Controller.MediaEncoding param += string.Format( CultureInfo.InvariantCulture, " -speed 16 -quality good -profile:v {0} -slices 8 -crf {1} -qmin {2} -qmax {3}", - profileScore.ToString(_usCulture), + profileScore.ToString(CultureInfo.InvariantCulture), crf, qmin, qmax); @@ -1289,7 +1287,7 @@ namespace MediaBrowser.Controller.MediaEncoding var framerate = GetFramerateParam(state); if (framerate.HasValue) { - param += string.Format(CultureInfo.InvariantCulture, " -r {0}", framerate.Value.ToString(_usCulture)); + param += string.Format(CultureInfo.InvariantCulture, " -r {0}", framerate.Value.ToString(CultureInfo.InvariantCulture)); } var targetVideoCodec = state.ActualOutputVideoCodec; @@ -1393,7 +1391,7 @@ namespace MediaBrowser.Controller.MediaEncoding else if (string.Equals(videoEncoder, "hevc_qsv", StringComparison.OrdinalIgnoreCase)) { // hevc_qsv use -level 51 instead of -level 153. - if (double.TryParse(level, NumberStyles.Any, _usCulture, out double hevcLevel)) + if (double.TryParse(level, NumberStyles.Any, CultureInfo.InvariantCulture, out double hevcLevel)) { param += " -level " + (hevcLevel / 3); } @@ -1555,7 +1553,7 @@ namespace MediaBrowser.Controller.MediaEncoding // If a specific level was requested, the source must match or be less than var level = state.GetRequestedLevel(videoStream.Codec); if (!string.IsNullOrEmpty(level) - && double.TryParse(level, NumberStyles.Any, _usCulture, out var requestLevel)) + && double.TryParse(level, NumberStyles.Any, CultureInfo.InvariantCulture, out var requestLevel)) { if (!videoStream.Level.HasValue) { @@ -1803,7 +1801,7 @@ namespace MediaBrowser.Controller.MediaEncoding && state.AudioStream.Channels.Value > 5 && !encodingOptions.DownMixAudioBoost.Equals(1)) { - filters.Add("volume=" + encodingOptions.DownMixAudioBoost.ToString(_usCulture)); + filters.Add("volume=" + encodingOptions.DownMixAudioBoost.ToString(CultureInfo.InvariantCulture)); } var isCopyingTimestamps = state.CopyTimestamps || state.TranscodingType != TranscodingJobType.Progressive; @@ -2434,8 +2432,8 @@ namespace MediaBrowser.Controller.MediaEncoding { if (isExynosV4L2) { - var widthParam = requestedWidth.Value.ToString(_usCulture); - var heightParam = requestedHeight.Value.ToString(_usCulture); + var widthParam = requestedWidth.Value.ToString(CultureInfo.InvariantCulture); + var heightParam = requestedHeight.Value.ToString(CultureInfo.InvariantCulture); filters.Add( string.Format( @@ -2453,8 +2451,8 @@ namespace MediaBrowser.Controller.MediaEncoding // If Max dimensions were supplied, for width selects lowest even number between input width and width req size and selects lowest even number from in width*display aspect and requested size else if (requestedMaxWidth.HasValue && requestedMaxHeight.HasValue) { - var maxWidthParam = requestedMaxWidth.Value.ToString(_usCulture); - var maxHeightParam = requestedMaxHeight.Value.ToString(_usCulture); + var maxWidthParam = requestedMaxWidth.Value.ToString(CultureInfo.InvariantCulture); + var maxHeightParam = requestedMaxHeight.Value.ToString(CultureInfo.InvariantCulture); if (isExynosV4L2) { @@ -2486,7 +2484,7 @@ namespace MediaBrowser.Controller.MediaEncoding } else { - var widthParam = requestedWidth.Value.ToString(_usCulture); + var widthParam = requestedWidth.Value.ToString(CultureInfo.InvariantCulture); filters.Add( string.Format( @@ -2499,7 +2497,7 @@ namespace MediaBrowser.Controller.MediaEncoding // If a fixed height was requested else if (requestedHeight.HasValue) { - var heightParam = requestedHeight.Value.ToString(_usCulture); + var heightParam = requestedHeight.Value.ToString(CultureInfo.InvariantCulture); if (isExynosV4L2) { @@ -2522,7 +2520,7 @@ namespace MediaBrowser.Controller.MediaEncoding // If a max width was requested else if (requestedMaxWidth.HasValue) { - var maxWidthParam = requestedMaxWidth.Value.ToString(_usCulture); + var maxWidthParam = requestedMaxWidth.Value.ToString(CultureInfo.InvariantCulture); if (isExynosV4L2) { @@ -2545,7 +2543,7 @@ namespace MediaBrowser.Controller.MediaEncoding // If a max height was requested else if (requestedMaxHeight.HasValue) { - var maxHeightParam = requestedMaxHeight.Value.ToString(_usCulture); + var maxHeightParam = requestedMaxHeight.Value.ToString(CultureInfo.InvariantCulture); if (isExynosV4L2) { @@ -4122,12 +4120,12 @@ namespace MediaBrowser.Controller.MediaEncoding if (bitrate.HasValue) { - args += " -ab " + bitrate.Value.ToString(_usCulture); + args += " -ab " + bitrate.Value.ToString(CultureInfo.InvariantCulture); } if (state.OutputAudioSampleRate.HasValue) { - args += " -ar " + state.OutputAudioSampleRate.Value.ToString(_usCulture); + args += " -ar " + state.OutputAudioSampleRate.Value.ToString(CultureInfo.InvariantCulture); } args += GetAudioFilterParam(state, encodingOptions); @@ -4143,12 +4141,12 @@ namespace MediaBrowser.Controller.MediaEncoding if (bitrate.HasValue) { - audioTranscodeParams.Add("-ab " + bitrate.Value.ToString(_usCulture)); + audioTranscodeParams.Add("-ab " + bitrate.Value.ToString(CultureInfo.InvariantCulture)); } if (state.OutputAudioChannels.HasValue) { - audioTranscodeParams.Add("-ac " + state.OutputAudioChannels.Value.ToString(_usCulture)); + audioTranscodeParams.Add("-ac " + state.OutputAudioChannels.Value.ToString(CultureInfo.InvariantCulture)); } // opus will fail on 44100 @@ -4156,7 +4154,7 @@ namespace MediaBrowser.Controller.MediaEncoding { if (state.OutputAudioSampleRate.HasValue) { - audioTranscodeParams.Add("-ar " + state.OutputAudioSampleRate.Value.ToString(_usCulture)); + audioTranscodeParams.Add("-ar " + state.OutputAudioSampleRate.Value.ToString(CultureInfo.InvariantCulture)); } } diff --git a/MediaBrowser.Controller/MediaEncoding/JobLogger.cs b/MediaBrowser.Controller/MediaEncoding/JobLogger.cs index c4ddc5618..933f440ac 100644 --- a/MediaBrowser.Controller/MediaEncoding/JobLogger.cs +++ b/MediaBrowser.Controller/MediaEncoding/JobLogger.cs @@ -13,7 +13,6 @@ namespace MediaBrowser.Controller.MediaEncoding { public class JobLogger { - private static readonly CultureInfo _usCulture = CultureInfo.ReadOnly(new CultureInfo("en-US")); private readonly ILogger _logger; public JobLogger(ILogger logger) @@ -87,7 +86,7 @@ namespace MediaBrowser.Controller.MediaEncoding { var rate = parts[i + 1]; - if (float.TryParse(rate, NumberStyles.Any, _usCulture, out var val)) + if (float.TryParse(rate, NumberStyles.Any, CultureInfo.InvariantCulture, out var val)) { framerate = val; } @@ -96,7 +95,7 @@ namespace MediaBrowser.Controller.MediaEncoding { var rate = part.Split('=', 2)[^1]; - if (float.TryParse(rate, NumberStyles.Any, _usCulture, out var val)) + if (float.TryParse(rate, NumberStyles.Any, CultureInfo.InvariantCulture, out var val)) { framerate = val; } @@ -106,7 +105,7 @@ namespace MediaBrowser.Controller.MediaEncoding { var time = part.Split('=', 2)[^1]; - if (TimeSpan.TryParse(time, _usCulture, out var val)) + if (TimeSpan.TryParse(time, CultureInfo.InvariantCulture, out var val)) { var currentMs = startMs + val.TotalMilliseconds; @@ -128,7 +127,7 @@ namespace MediaBrowser.Controller.MediaEncoding if (scale.HasValue) { - if (long.TryParse(size, NumberStyles.Any, _usCulture, out var val)) + if (long.TryParse(size, NumberStyles.Any, CultureInfo.InvariantCulture, out var val)) { bytesTranscoded = val * scale.Value; } @@ -147,7 +146,7 @@ namespace MediaBrowser.Controller.MediaEncoding if (scale.HasValue) { - if (float.TryParse(rate, NumberStyles.Any, _usCulture, out var val)) + if (float.TryParse(rate, NumberStyles.Any, CultureInfo.InvariantCulture, out var val)) { bitRate = (int)Math.Ceiling(val * scale.Value); } diff --git a/MediaBrowser.LocalMetadata/Images/LocalImageProvider.cs b/MediaBrowser.LocalMetadata/Images/LocalImageProvider.cs index b7398880e..988581df9 100644 --- a/MediaBrowser.LocalMetadata/Images/LocalImageProvider.cs +++ b/MediaBrowser.LocalMetadata/Images/LocalImageProvider.cs @@ -60,8 +60,6 @@ namespace MediaBrowser.LocalMetadata.Images private readonly IFileSystem _fileSystem; - private readonly CultureInfo _usCulture = new CultureInfo("en-US"); - /// <summary> /// Initializes a new instance of the <see cref="LocalImageProvider"/> class. /// </summary> @@ -434,7 +432,7 @@ namespace MediaBrowser.LocalMetadata.Images var seasonMarker = seasonNumber.Value == 0 ? "-specials" - : seasonNumber.Value.ToString("00", _usCulture); + : seasonNumber.Value.ToString("00", CultureInfo.InvariantCulture); // Get this one directly from the file system since we have to go up a level if (!string.Equals(prefix, seasonMarker, StringComparison.OrdinalIgnoreCase)) diff --git a/MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs b/MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs index 7c9e681d6..5a36c1663 100644 --- a/MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs +++ b/MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs @@ -21,8 +21,6 @@ namespace MediaBrowser.LocalMetadata.Parsers public class BaseItemXmlParser<T> where T : BaseItem { - private readonly CultureInfo _usCulture = new CultureInfo("en-US"); - private Dictionary<string, string>? _validProviderIds; /// <summary> @@ -180,7 +178,7 @@ namespace MediaBrowser.LocalMetadata.Parsers if (!string.IsNullOrEmpty(text)) { - if (float.TryParse(text, NumberStyles.Any, _usCulture, out var value)) + if (float.TryParse(text, NumberStyles.Any, CultureInfo.InvariantCulture, out var value)) { item.CriticRating = value; } @@ -332,7 +330,7 @@ namespace MediaBrowser.LocalMetadata.Parsers if (!string.IsNullOrWhiteSpace(text)) { - if (int.TryParse(text.AsSpan().LeftPart(' '), NumberStyles.Integer, _usCulture, out var runtime)) + if (int.TryParse(text.AsSpan().LeftPart(' '), NumberStyles.Integer, CultureInfo.InvariantCulture, out var runtime)) { item.RunTimeTicks = TimeSpan.FromMinutes(runtime).Ticks; } @@ -1095,7 +1093,7 @@ namespace MediaBrowser.LocalMetadata.Parsers if (!string.IsNullOrWhiteSpace(val)) { - if (int.TryParse(val, NumberStyles.Integer, _usCulture, out var intVal)) + if (int.TryParse(val, NumberStyles.Integer, CultureInfo.InvariantCulture, out var intVal)) { sortOrder = intVal; } diff --git a/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs b/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs index 6a3896eb6..6f66fd61b 100644 --- a/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs +++ b/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs @@ -25,8 +25,6 @@ namespace MediaBrowser.LocalMetadata.Savers /// </summary> public const string DateAddedFormat = "yyyy-MM-dd HH:mm:ss"; - private static readonly CultureInfo _usCulture = new CultureInfo("en-US"); - /// <summary> /// Initializes a new instance of the <see cref="BaseXmlSaver"/> class. /// </summary> @@ -205,7 +203,7 @@ namespace MediaBrowser.LocalMetadata.Savers if (item.CriticRating.HasValue) { - writer.WriteElementString("CriticRating", item.CriticRating.Value.ToString(_usCulture)); + writer.WriteElementString("CriticRating", item.CriticRating.Value.ToString(CultureInfo.InvariantCulture)); } if (!string.IsNullOrEmpty(item.Overview)) @@ -289,12 +287,12 @@ namespace MediaBrowser.LocalMetadata.Savers if (item.CommunityRating.HasValue) { - writer.WriteElementString("Rating", item.CommunityRating.Value.ToString(_usCulture)); + writer.WriteElementString("Rating", item.CommunityRating.Value.ToString(CultureInfo.InvariantCulture)); } if (item.ProductionYear.HasValue && item is not Person) { - writer.WriteElementString("ProductionYear", item.ProductionYear.Value.ToString(_usCulture)); + writer.WriteElementString("ProductionYear", item.ProductionYear.Value.ToString(CultureInfo.InvariantCulture)); } if (item is IHasAspectRatio hasAspectRatio) @@ -322,7 +320,7 @@ namespace MediaBrowser.LocalMetadata.Savers { var timespan = TimeSpan.FromTicks(runTimeTicks.Value); - writer.WriteElementString("RunningTime", Math.Floor(timespan.TotalMinutes).ToString(_usCulture)); + writer.WriteElementString("RunningTime", Math.Floor(timespan.TotalMinutes).ToString(CultureInfo.InvariantCulture)); } if (item.ProviderIds != null) @@ -395,7 +393,7 @@ namespace MediaBrowser.LocalMetadata.Savers if (person.SortOrder.HasValue) { - writer.WriteElementString("SortOrder", person.SortOrder.Value.ToString(_usCulture)); + writer.WriteElementString("SortOrder", person.SortOrder.Value.ToString(CultureInfo.InvariantCulture)); } writer.WriteEndElement(); diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index 4cbd1bbc8..06fe95ce8 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -43,11 +43,6 @@ namespace MediaBrowser.MediaEncoding.Encoder /// </summary> internal const int DefaultHdrImageExtractionTimeout = 20000; - /// <summary> - /// The us culture. - /// </summary> - private readonly CultureInfo _usCulture = new CultureInfo("en-US"); - private readonly ILogger<MediaEncoder> _logger; private readonly IServerConfigurationManager _configurationManager; private readonly IFileSystem _fileSystem; @@ -687,7 +682,7 @@ namespace MediaBrowser.MediaEncoding.Encoder public string GetTimeParameter(TimeSpan time) { - return time.ToString(@"hh\:mm\:ss\.fff", _usCulture); + return time.ToString(@"hh\:mm\:ss\.fff", CultureInfo.InvariantCulture); } public async Task ExtractVideoImagesOnInterval( @@ -704,11 +699,11 @@ namespace MediaBrowser.MediaEncoding.Encoder { var inputArgument = GetInputArgument(inputFile, mediaSource); - var vf = "fps=fps=1/" + interval.TotalSeconds.ToString(_usCulture); + var vf = "fps=fps=1/" + interval.TotalSeconds.ToString(CultureInfo.InvariantCulture); if (maxWidth.HasValue) { - var maxWidthParam = maxWidth.Value.ToString(_usCulture); + var maxWidthParam = maxWidth.Value.ToString(CultureInfo.InvariantCulture); vf += string.Format(CultureInfo.InvariantCulture, ",scale=min(iw\\,{0}):trunc(ow/dar/2)*2", maxWidthParam); } diff --git a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs index 26f629a31..9ed6c264e 100644 --- a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs +++ b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs @@ -30,7 +30,6 @@ namespace MediaBrowser.MediaEncoding.Probing private static readonly Regex _performerPattern = new (@"(?<name>.*) \((?<instrument>.*)\)"); - private readonly CultureInfo _usCulture = new ("en-US"); private readonly ILogger _logger; private readonly ILocalizationManager _localization; @@ -83,7 +82,7 @@ namespace MediaBrowser.MediaEncoding.Probing if (!string.IsNullOrEmpty(data.Format.BitRate)) { - if (int.TryParse(data.Format.BitRate, NumberStyles.Any, _usCulture, out var value)) + if (int.TryParse(data.Format.BitRate, NumberStyles.Any, CultureInfo.InvariantCulture, out var value)) { info.Bitrate = value; } @@ -191,7 +190,7 @@ namespace MediaBrowser.MediaEncoding.Probing if (data.Format != null && !string.IsNullOrEmpty(data.Format.Duration)) { - info.RunTimeTicks = TimeSpan.FromSeconds(double.Parse(data.Format.Duration, _usCulture)).Ticks; + info.RunTimeTicks = TimeSpan.FromSeconds(double.Parse(data.Format.Duration, CultureInfo.InvariantCulture)).Ticks; } FetchWtvInfo(info, data); @@ -673,7 +672,7 @@ namespace MediaBrowser.MediaEncoding.Probing if (!string.IsNullOrEmpty(streamInfo.SampleRate)) { - if (int.TryParse(streamInfo.SampleRate, NumberStyles.Any, _usCulture, out var value)) + if (int.TryParse(streamInfo.SampleRate, NumberStyles.Any, CultureInfo.InvariantCulture, out var value)) { stream.SampleRate = value; } @@ -802,7 +801,7 @@ namespace MediaBrowser.MediaEncoding.Probing if (!string.IsNullOrEmpty(streamInfo.BitRate)) { - if (int.TryParse(streamInfo.BitRate, NumberStyles.Any, _usCulture, out var value)) + if (int.TryParse(streamInfo.BitRate, NumberStyles.Any, CultureInfo.InvariantCulture, out var value)) { bitrate = value; } @@ -815,7 +814,7 @@ namespace MediaBrowser.MediaEncoding.Probing && (stream.Type == MediaStreamType.Video || (isAudio && stream.Type == MediaStreamType.Audio))) { // If the stream info doesn't have a bitrate get the value from the media format info - if (int.TryParse(formatInfo.BitRate, NumberStyles.Any, _usCulture, out var value)) + if (int.TryParse(formatInfo.BitRate, NumberStyles.Any, CultureInfo.InvariantCulture, out var value)) { bitrate = value; } @@ -921,8 +920,8 @@ namespace MediaBrowser.MediaEncoding.Probing var parts = (original ?? string.Empty).Split(':'); if (!(parts.Length == 2 && - int.TryParse(parts[0], NumberStyles.Any, _usCulture, out var width) && - int.TryParse(parts[1], NumberStyles.Any, _usCulture, out var height) && + int.TryParse(parts[0], NumberStyles.Any, CultureInfo.InvariantCulture, out var width) && + int.TryParse(parts[1], NumberStyles.Any, CultureInfo.InvariantCulture, out var height) && width > 0 && height > 0)) { @@ -1008,11 +1007,11 @@ namespace MediaBrowser.MediaEncoding.Probing if (parts.Length == 2) { - result = float.Parse(parts[0], _usCulture) / float.Parse(parts[1], _usCulture); + result = float.Parse(parts[0], CultureInfo.InvariantCulture) / float.Parse(parts[1], CultureInfo.InvariantCulture); } else { - result = float.Parse(parts[0], _usCulture); + result = float.Parse(parts[0], CultureInfo.InvariantCulture); } return float.IsNaN(result) ? null : result; @@ -1039,7 +1038,7 @@ namespace MediaBrowser.MediaEncoding.Probing // If we got something, parse it if (!string.IsNullOrEmpty(duration)) { - data.RunTimeTicks = TimeSpan.FromSeconds(double.Parse(duration, _usCulture)).Ticks; + data.RunTimeTicks = TimeSpan.FromSeconds(double.Parse(duration, CultureInfo.InvariantCulture)).Ticks; } } @@ -1101,7 +1100,7 @@ namespace MediaBrowser.MediaEncoding.Probing return; } - info.Size = string.IsNullOrEmpty(data.Format.Size) ? null : long.Parse(data.Format.Size, _usCulture); + info.Size = string.IsNullOrEmpty(data.Format.Size) ? null : long.Parse(data.Format.Size, CultureInfo.InvariantCulture); } private void SetAudioInfoFromTags(MediaInfo audio, IReadOnlyDictionary<string, string> tags) @@ -1144,7 +1143,7 @@ namespace MediaBrowser.MediaEncoding.Probing { Name = match.Groups["name"].Value, Type = PersonType.Actor, - Role = CultureInfo.CurrentCulture.TextInfo.ToTitleCase(match.Groups["instrument"].Value) + Role = CultureInfo.InvariantCulture.TextInfo.ToTitleCase(match.Groups["instrument"].Value) }); } } @@ -1443,7 +1442,7 @@ namespace MediaBrowser.MediaEncoding.Probing .ToArray(); } - if (tags.TryGetValue("WM/OriginalReleaseTime", out var year) && int.TryParse(year, NumberStyles.Integer, _usCulture, out var parsedYear)) + if (tags.TryGetValue("WM/OriginalReleaseTime", out var year) && int.TryParse(year, NumberStyles.Integer, CultureInfo.InvariantCulture, out var parsedYear)) { video.ProductionYear = parsedYear; } diff --git a/MediaBrowser.Model/Globalization/ILocalizationManager.cs b/MediaBrowser.Model/Globalization/ILocalizationManager.cs index b213e7aa0..406d32cde 100644 --- a/MediaBrowser.Model/Globalization/ILocalizationManager.cs +++ b/MediaBrowser.Model/Globalization/ILocalizationManager.cs @@ -56,10 +56,10 @@ namespace MediaBrowser.Model.Globalization IEnumerable<LocalizationOption> GetLocalizationOptions(); /// <summary> - /// Returns the correct <see cref="CultureInfo" /> for the given language. + /// Returns the correct <see cref="CultureDto" /> for the given language. /// </summary> /// <param name="language">The language.</param> - /// <returns>The correct <see cref="CultureInfo" /> for the given language.</returns> + /// <returns>The correct <see cref="CultureDto" /> for the given language.</returns> CultureDto? FindLanguageInfo(string language); } } diff --git a/MediaBrowser.Providers/Manager/ImageSaver.cs b/MediaBrowser.Providers/Manager/ImageSaver.cs index 7d259a9d3..4b05edd67 100644 --- a/MediaBrowser.Providers/Manager/ImageSaver.cs +++ b/MediaBrowser.Providers/Manager/ImageSaver.cs @@ -29,8 +29,6 @@ namespace MediaBrowser.Providers.Manager /// </summary> public class ImageSaver { - private static readonly CultureInfo UsCulture = new CultureInfo("en-US"); - /// <summary> /// The _config. /// </summary> @@ -377,7 +375,7 @@ namespace MediaBrowser.Providers.Manager var seasonMarker = season.IndexNumber.Value == 0 ? "-specials" - : season.IndexNumber.Value.ToString("00", UsCulture); + : season.IndexNumber.Value.ToString("00", CultureInfo.InvariantCulture); var imageFilename = "season" + seasonMarker + "-landscape" + extension; @@ -400,7 +398,7 @@ namespace MediaBrowser.Providers.Manager var seasonMarker = season.IndexNumber.Value == 0 ? "-specials" - : season.IndexNumber.Value.ToString("00", UsCulture); + : season.IndexNumber.Value.ToString("00", CultureInfo.InvariantCulture); var imageFilename = "season" + seasonMarker + "-banner" + extension; @@ -495,12 +493,12 @@ namespace MediaBrowser.Providers.Manager var filenames = images.Select(i => Path.GetFileNameWithoutExtension(i.Path)).ToList(); var current = 1; - while (filenames.Contains(numberedIndexPrefix + current.ToString(UsCulture), StringComparer.OrdinalIgnoreCase)) + while (filenames.Contains(numberedIndexPrefix + current.ToString(CultureInfo.InvariantCulture), StringComparer.OrdinalIgnoreCase)) { current++; } - return numberedIndexPrefix + current.ToString(UsCulture); + return numberedIndexPrefix + current.ToString(CultureInfo.InvariantCulture); } /// <summary> @@ -539,7 +537,7 @@ namespace MediaBrowser.Providers.Manager var seasonMarker = season.IndexNumber.Value == 0 ? "-specials" - : season.IndexNumber.Value.ToString("00", UsCulture); + : season.IndexNumber.Value.ToString("00", CultureInfo.InvariantCulture); var imageFilename = "season" + seasonMarker + "-fanart" + extension; @@ -556,7 +554,7 @@ namespace MediaBrowser.Providers.Manager if (item.IsInMixedFolder) { - return new[] { GetSavePathForItemInMixedFolder(item, type, "fanart" + outputIndex.ToString(UsCulture), extension) }; + return new[] { GetSavePathForItemInMixedFolder(item, type, "fanart" + outputIndex.ToString(CultureInfo.InvariantCulture), extension) }; } var extraFanartFilename = GetBackdropSaveFilename(item.GetImages(ImageType.Backdrop), "fanart", "fanart", outputIndex); @@ -568,7 +566,7 @@ namespace MediaBrowser.Providers.Manager if (EnableExtraThumbsDuplication) { - list.Add(Path.Combine(item.ContainingFolderPath, "extrathumbs", "thumb" + outputIndex.ToString(UsCulture) + extension)); + list.Add(Path.Combine(item.ContainingFolderPath, "extrathumbs", "thumb" + outputIndex.ToString(CultureInfo.InvariantCulture) + extension)); } return list.ToArray(); @@ -582,7 +580,7 @@ namespace MediaBrowser.Providers.Manager var seasonMarker = season.IndexNumber.Value == 0 ? "-specials" - : season.IndexNumber.Value.ToString("00", UsCulture); + : season.IndexNumber.Value.ToString("00", CultureInfo.InvariantCulture); var imageFilename = "season" + seasonMarker + "-poster" + extension; diff --git a/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs b/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs index 479ae0f39..b2bc58eea 100644 --- a/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs +++ b/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs @@ -26,7 +26,6 @@ namespace MediaBrowser.Providers.Plugins.Omdb private readonly IFileSystem _fileSystem; private readonly IServerConfigurationManager _configurationManager; private readonly IHttpClientFactory _httpClientFactory; - private readonly CultureInfo _usCulture = new CultureInfo("en-US"); private readonly IApplicationHost _appHost; private readonly JsonSerializerOptions _jsonOptions; @@ -79,7 +78,7 @@ namespace MediaBrowser.Providers.Plugins.Omdb } if (!string.IsNullOrEmpty(result.Year) && result.Year.Length >= 4 - && int.TryParse(result.Year.AsSpan().Slice(0, 4), NumberStyles.Number, _usCulture, out var year) + && int.TryParse(result.Year.AsSpan().Slice(0, 4), NumberStyles.Number, CultureInfo.InvariantCulture, out var year) && year >= 0) { item.ProductionYear = year; @@ -93,14 +92,14 @@ namespace MediaBrowser.Providers.Plugins.Omdb } if (!string.IsNullOrEmpty(result.imdbVotes) - && int.TryParse(result.imdbVotes, NumberStyles.Number, _usCulture, out var voteCount) + && int.TryParse(result.imdbVotes, NumberStyles.Number, CultureInfo.InvariantCulture, out var voteCount) && voteCount >= 0) { // item.VoteCount = voteCount; } if (!string.IsNullOrEmpty(result.imdbRating) - && float.TryParse(result.imdbRating, NumberStyles.Any, _usCulture, out var imdbRating) + && float.TryParse(result.imdbRating, NumberStyles.Any, CultureInfo.InvariantCulture, out var imdbRating) && imdbRating >= 0) { item.CommunityRating = imdbRating; @@ -191,7 +190,7 @@ namespace MediaBrowser.Providers.Plugins.Omdb } if (!string.IsNullOrEmpty(result.Year) && result.Year.Length >= 4 - && int.TryParse(result.Year.AsSpan().Slice(0, 4), NumberStyles.Number, _usCulture, out var year) + && int.TryParse(result.Year.AsSpan().Slice(0, 4), NumberStyles.Number, CultureInfo.InvariantCulture, out var year) && year >= 0) { item.ProductionYear = year; @@ -205,14 +204,14 @@ namespace MediaBrowser.Providers.Plugins.Omdb } if (!string.IsNullOrEmpty(result.imdbVotes) - && int.TryParse(result.imdbVotes, NumberStyles.Number, _usCulture, out var voteCount) + && int.TryParse(result.imdbVotes, NumberStyles.Number, CultureInfo.InvariantCulture, out var voteCount) && voteCount >= 0) { // item.VoteCount = voteCount; } if (!string.IsNullOrEmpty(result.imdbRating) - && float.TryParse(result.imdbRating, NumberStyles.Any, _usCulture, out var imdbRating) + && float.TryParse(result.imdbRating, NumberStyles.Any, CultureInfo.InvariantCulture, out var imdbRating) && imdbRating >= 0) { item.CommunityRating = imdbRating; diff --git a/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs b/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs index f7f4ea065..9d558b6ce 100644 --- a/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs +++ b/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs @@ -58,8 +58,6 @@ namespace MediaBrowser.XbmcMetadata.Parsers _directoryService = directoryService; } - protected CultureInfo UsCulture { get; } = new CultureInfo("en-US"); - /// <summary> /// Gets the logger. /// </summary> @@ -309,7 +307,7 @@ namespace MediaBrowser.XbmcMetadata.Parsers if (!string.IsNullOrEmpty(text)) { - if (float.TryParse(text, NumberStyles.Any, UsCulture, out var value)) + if (float.TryParse(text, NumberStyles.Any, CultureInfo.InvariantCulture, out var value)) { item.CriticRating = value; } @@ -370,7 +368,7 @@ namespace MediaBrowser.XbmcMetadata.Parsers var val = reader.ReadElementContentAsString(); if (!string.IsNullOrWhiteSpace(val) && userData != null) { - if (int.TryParse(val, NumberStyles.Integer, UsCulture, out var count)) + if (int.TryParse(val, NumberStyles.Integer, CultureInfo.InvariantCulture, out var count)) { userData.PlayCount = count; } @@ -475,7 +473,7 @@ namespace MediaBrowser.XbmcMetadata.Parsers if (!string.IsNullOrWhiteSpace(text)) { - if (int.TryParse(text.AsSpan().LeftPart(' '), NumberStyles.Integer, UsCulture, out var runtime)) + if (int.TryParse(text.AsSpan().LeftPart(' '), NumberStyles.Integer, CultureInfo.InvariantCulture, out var runtime)) { item.RunTimeTicks = TimeSpan.FromMinutes(runtime).Ticks; } @@ -1265,7 +1263,7 @@ namespace MediaBrowser.XbmcMetadata.Parsers if (!string.IsNullOrWhiteSpace(val)) { - if (int.TryParse(val, NumberStyles.Integer, UsCulture, out var intVal)) + if (int.TryParse(val, NumberStyles.Integer, CultureInfo.InvariantCulture, out var intVal)) { sortOrder = intVal; } diff --git a/MediaBrowser.XbmcMetadata/Parsers/EpisodeNfoParser.cs b/MediaBrowser.XbmcMetadata/Parsers/EpisodeNfoParser.cs index 3a305024e..d2f349ad7 100644 --- a/MediaBrowser.XbmcMetadata/Parsers/EpisodeNfoParser.cs +++ b/MediaBrowser.XbmcMetadata/Parsers/EpisodeNfoParser.cs @@ -163,7 +163,7 @@ namespace MediaBrowser.XbmcMetadata.Parsers if (!string.IsNullOrWhiteSpace(val)) { // int.TryParse is local aware, so it can be problematic, force us culture - if (int.TryParse(val, NumberStyles.Integer, UsCulture, out var rval)) + if (int.TryParse(val, NumberStyles.Integer, CultureInfo.InvariantCulture, out var rval)) { item.AirsBeforeEpisodeNumber = rval; } @@ -179,7 +179,7 @@ namespace MediaBrowser.XbmcMetadata.Parsers if (!string.IsNullOrWhiteSpace(val)) { // int.TryParse is local aware, so it can be problematic, force us culture - if (int.TryParse(val, NumberStyles.Integer, UsCulture, out var rval)) + if (int.TryParse(val, NumberStyles.Integer, CultureInfo.InvariantCulture, out var rval)) { item.AirsAfterSeasonNumber = rval; } @@ -195,7 +195,7 @@ namespace MediaBrowser.XbmcMetadata.Parsers if (!string.IsNullOrWhiteSpace(val)) { // int.TryParse is local aware, so it can be problematic, force us culture - if (int.TryParse(val, NumberStyles.Integer, UsCulture, out var rval)) + if (int.TryParse(val, NumberStyles.Integer, CultureInfo.InvariantCulture, out var rval)) { item.AirsBeforeSeasonNumber = rval; } @@ -211,7 +211,7 @@ namespace MediaBrowser.XbmcMetadata.Parsers if (!string.IsNullOrWhiteSpace(val)) { // int.TryParse is local aware, so it can be problematic, force us culture - if (int.TryParse(val, NumberStyles.Integer, UsCulture, out var rval)) + if (int.TryParse(val, NumberStyles.Integer, CultureInfo.InvariantCulture, out var rval)) { item.AirsBeforeSeasonNumber = rval; } @@ -227,7 +227,7 @@ namespace MediaBrowser.XbmcMetadata.Parsers if (!string.IsNullOrWhiteSpace(val)) { // int.TryParse is local aware, so it can be problematic, force us culture - if (int.TryParse(val, NumberStyles.Integer, UsCulture, out var rval)) + if (int.TryParse(val, NumberStyles.Integer, CultureInfo.InvariantCulture, out var rval)) { item.AirsBeforeEpisodeNumber = rval; } diff --git a/MediaBrowser.XbmcMetadata/Savers/EpisodeNfoSaver.cs b/MediaBrowser.XbmcMetadata/Savers/EpisodeNfoSaver.cs index 62f80e81b..2cd3fdf02 100644 --- a/MediaBrowser.XbmcMetadata/Savers/EpisodeNfoSaver.cs +++ b/MediaBrowser.XbmcMetadata/Savers/EpisodeNfoSaver.cs @@ -17,8 +17,6 @@ namespace MediaBrowser.XbmcMetadata.Savers /// </summary> public class EpisodeNfoSaver : BaseNfoSaver { - private readonly CultureInfo _usCulture = new CultureInfo("en-US"); - /// <summary> /// Initializes a new instance of the <see cref="EpisodeNfoSaver"/> class. /// </summary> @@ -60,17 +58,17 @@ namespace MediaBrowser.XbmcMetadata.Savers if (episode.IndexNumber.HasValue) { - writer.WriteElementString("episode", episode.IndexNumber.Value.ToString(_usCulture)); + writer.WriteElementString("episode", episode.IndexNumber.Value.ToString(CultureInfo.InvariantCulture)); } if (episode.IndexNumberEnd.HasValue) { - writer.WriteElementString("episodenumberend", episode.IndexNumberEnd.Value.ToString(_usCulture)); + writer.WriteElementString("episodenumberend", episode.IndexNumberEnd.Value.ToString(CultureInfo.InvariantCulture)); } if (episode.ParentIndexNumber.HasValue) { - writer.WriteElementString("season", episode.ParentIndexNumber.Value.ToString(_usCulture)); + writer.WriteElementString("season", episode.ParentIndexNumber.Value.ToString(CultureInfo.InvariantCulture)); } if (episode.PremiereDate.HasValue) @@ -84,28 +82,28 @@ namespace MediaBrowser.XbmcMetadata.Savers { if (episode.AirsAfterSeasonNumber.HasValue && episode.AirsAfterSeasonNumber.Value != -1) { - writer.WriteElementString("airsafter_season", episode.AirsAfterSeasonNumber.Value.ToString(_usCulture)); + writer.WriteElementString("airsafter_season", episode.AirsAfterSeasonNumber.Value.ToString(CultureInfo.InvariantCulture)); } if (episode.AirsBeforeEpisodeNumber.HasValue && episode.AirsBeforeEpisodeNumber.Value != -1) { - writer.WriteElementString("airsbefore_episode", episode.AirsBeforeEpisodeNumber.Value.ToString(_usCulture)); + writer.WriteElementString("airsbefore_episode", episode.AirsBeforeEpisodeNumber.Value.ToString(CultureInfo.InvariantCulture)); } if (episode.AirsBeforeSeasonNumber.HasValue && episode.AirsBeforeSeasonNumber.Value != -1) { - writer.WriteElementString("airsbefore_season", episode.AirsBeforeSeasonNumber.Value.ToString(_usCulture)); + writer.WriteElementString("airsbefore_season", episode.AirsBeforeSeasonNumber.Value.ToString(CultureInfo.InvariantCulture)); } if (episode.AirsBeforeEpisodeNumber.HasValue && episode.AirsBeforeEpisodeNumber.Value != -1) { - writer.WriteElementString("displayepisode", episode.AirsBeforeEpisodeNumber.Value.ToString(_usCulture)); + writer.WriteElementString("displayepisode", episode.AirsBeforeEpisodeNumber.Value.ToString(CultureInfo.InvariantCulture)); } var specialSeason = episode.AiredSeasonNumber; if (specialSeason.HasValue && specialSeason.Value != -1) { - writer.WriteElementString("displayseason", specialSeason.Value.ToString(_usCulture)); + writer.WriteElementString("displayseason", specialSeason.Value.ToString(CultureInfo.InvariantCulture)); } } } -- cgit v1.2.3