aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.ci/azure-pipelines-api-client.yml59
-rw-r--r--.ci/azure-pipelines.yml3
-rw-r--r--.github/label-commenter-config.yml43
-rw-r--r--.github/workflows/automation.yml12
-rw-r--r--.github/workflows/label-commenter.yml22
-rw-r--r--Dockerfile6
-rw-r--r--Dockerfile.arm6
-rw-r--r--Dockerfile.arm646
-rw-r--r--Emby.Dlna/Configuration/DlnaOptions.cs2
-rw-r--r--Emby.Dlna/ConfigurationExtension.cs1
-rw-r--r--Emby.Dlna/ContentDirectory/ContentDirectoryService.cs2
-rw-r--r--Emby.Dlna/ContentDirectory/ControlHandler.cs2
-rw-r--r--Emby.Dlna/ControlRequest.cs2
-rw-r--r--Emby.Dlna/ControlResponse.cs2
-rw-r--r--Emby.Dlna/Didl/DidlBuilder.cs28
-rw-r--r--Emby.Dlna/Didl/StringWriterWithEncoding.cs2
-rw-r--r--Emby.Dlna/DlnaConfigurationFactory.cs1
-rw-r--r--Emby.Dlna/DlnaManager.cs2
-rw-r--r--Emby.Dlna/Emby.Dlna.csproj1
-rw-r--r--Emby.Dlna/EventSubscriptionResponse.cs2
-rw-r--r--Emby.Dlna/Eventing/DlnaEventManager.cs2
-rw-r--r--Emby.Dlna/Eventing/EventSubscription.cs2
-rw-r--r--Emby.Dlna/Main/DlnaEntryPoint.cs2
-rw-r--r--Emby.Dlna/PlayTo/Device.cs2
-rw-r--r--Emby.Dlna/PlayTo/DeviceInfo.cs2
-rw-r--r--Emby.Dlna/PlayTo/MediaChangedEventArgs.cs2
-rw-r--r--Emby.Dlna/PlayTo/PlayToController.cs2
-rw-r--r--Emby.Dlna/PlayTo/PlayToManager.cs2
-rw-r--r--Emby.Dlna/PlayTo/PlaybackProgressEventArgs.cs2
-rw-r--r--Emby.Dlna/PlayTo/PlaybackStartEventArgs.cs2
-rw-r--r--Emby.Dlna/PlayTo/PlaybackStoppedEventArgs.cs2
-rw-r--r--Emby.Dlna/PlayTo/PlaylistItem.cs2
-rw-r--r--Emby.Dlna/PlayTo/PlaylistItemFactory.cs2
-rw-r--r--Emby.Dlna/PlayTo/SsdpHttpClient.cs2
-rw-r--r--Emby.Dlna/PlayTo/TransportCommands.cs14
-rw-r--r--Emby.Dlna/PlayTo/uBaseObject.cs2
-rw-r--r--Emby.Dlna/Server/DescriptionXmlBuilder.cs3
-rw-r--r--Emby.Dlna/Service/BaseControlHandler.cs4
-rw-r--r--Emby.Dlna/Ssdp/DeviceDiscovery.cs2
-rw-r--r--Emby.Dlna/Ssdp/SsdpExtensions.cs6
-rw-r--r--Emby.Naming/TV/EpisodeResolver.cs5
-rw-r--r--Emby.Server.Implementations/ApplicationHost.cs10
-rw-r--r--Emby.Server.Implementations/Collections/CollectionManager.cs14
-rw-r--r--Emby.Server.Implementations/Data/SqliteItemRepository.cs395
-rw-r--r--Emby.Server.Implementations/Dto/DtoService.cs15
-rw-r--r--Emby.Server.Implementations/Emby.Server.Implementations.csproj4
-rw-r--r--Emby.Server.Implementations/IO/ManagedFileSystem.cs61
-rw-r--r--Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs2
-rw-r--r--Emby.Server.Implementations/Images/PlaylistImageProvider.cs4
-rw-r--r--Emby.Server.Implementations/Library/LibraryManager.cs33
-rw-r--r--Emby.Server.Implementations/Library/MediaSourceManager.cs13
-rw-r--r--Emby.Server.Implementations/Library/MusicManager.cs3
-rw-r--r--Emby.Server.Implementations/Library/PathExtensions.cs10
-rw-r--r--Emby.Server.Implementations/Library/ResolverHelper.cs64
-rw-r--r--Emby.Server.Implementations/Library/Resolvers/ItemResolver.cs12
-rw-r--r--Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs2
-rw-r--r--Emby.Server.Implementations/Library/Resolvers/PhotoAlbumResolver.cs12
-rw-r--r--Emby.Server.Implementations/Library/Resolvers/PhotoResolver.cs2
-rw-r--r--Emby.Server.Implementations/Library/Resolvers/TV/EpisodeResolver.cs14
-rw-r--r--Emby.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs2
-rw-r--r--Emby.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs18
-rw-r--r--Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs24
-rw-r--r--Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs7
-rw-r--r--Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs7
-rw-r--r--Emby.Server.Implementations/LiveTv/LiveTvManager.cs15
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs23
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs3
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs34
-rw-r--r--Emby.Server.Implementations/Localization/Core/af.json4
-rw-r--r--Emby.Server.Implementations/Localization/Core/ar.json5
-rw-r--r--Emby.Server.Implementations/Localization/Core/bn.json2
-rw-r--r--Emby.Server.Implementations/Localization/Core/cs.json2
-rw-r--r--Emby.Server.Implementations/Localization/Core/da.json2
-rw-r--r--Emby.Server.Implementations/Localization/Core/fa.json2
-rw-r--r--Emby.Server.Implementations/Localization/Core/fi.json2
-rw-r--r--Emby.Server.Implementations/Localization/Core/fr.json8
-rw-r--r--Emby.Server.Implementations/Localization/Core/gl.json11
-rw-r--r--Emby.Server.Implementations/Localization/Core/hi.json11
-rw-r--r--Emby.Server.Implementations/Localization/Core/hu.json10
-rw-r--r--Emby.Server.Implementations/Localization/Core/is.json5
-rw-r--r--Emby.Server.Implementations/Localization/Core/it.json4
-rw-r--r--Emby.Server.Implementations/Localization/Core/kk.json58
-rw-r--r--Emby.Server.Implementations/Localization/Core/lt-LT.json5
-rw-r--r--Emby.Server.Implementations/Localization/Core/ms.json46
-rw-r--r--Emby.Server.Implementations/Localization/Core/nb.json56
-rw-r--r--Emby.Server.Implementations/Localization/Core/nl.json4
-rw-r--r--Emby.Server.Implementations/Localization/Core/nn.json63
-rw-r--r--Emby.Server.Implementations/Localization/Core/pa.json2
-rw-r--r--Emby.Server.Implementations/Localization/Core/ru.json4
-rw-r--r--Emby.Server.Implementations/Localization/Core/sv.json2
-rw-r--r--Emby.Server.Implementations/Localization/Core/ta.json2
-rw-r--r--Emby.Server.Implementations/Localization/Core/th.json6
-rw-r--r--Emby.Server.Implementations/Localization/Core/uk.json4
-rw-r--r--Emby.Server.Implementations/Localization/Core/zh-TW.json2
-rw-r--r--Emby.Server.Implementations/Localization/LocalizationManager.cs13
-rw-r--r--Emby.Server.Implementations/Playlists/PlaylistManager.cs2
-rw-r--r--Emby.Server.Implementations/Plugins/PluginManager.cs17
-rw-r--r--Emby.Server.Implementations/QuickConnect/QuickConnectManager.cs15
-rw-r--r--Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs11
-rw-r--r--Emby.Server.Implementations/Session/SessionManager.cs5
-rw-r--r--Emby.Server.Implementations/SyncPlay/SyncPlayManager.cs23
-rw-r--r--Emby.Server.Implementations/TV/TVSeriesManager.cs8
-rw-r--r--Jellyfin.Api/Auth/BaseAuthorizationHandler.cs5
-rw-r--r--Jellyfin.Api/Controllers/ConfigurationController.cs6
-rw-r--r--Jellyfin.Api/Controllers/ItemLookupController.cs91
-rw-r--r--Jellyfin.Api/Controllers/LibraryController.cs2
-rw-r--r--Jellyfin.Api/Controllers/MoviesController.cs11
-rw-r--r--Jellyfin.Api/Controllers/PersonsController.cs6
-rw-r--r--Jellyfin.Api/Controllers/PluginsController.cs7
-rw-r--r--Jellyfin.Api/Controllers/RemoteImageController.cs52
-rw-r--r--Jellyfin.Api/Controllers/SearchController.cs5
-rw-r--r--Jellyfin.Api/Controllers/UniversalAudioController.cs6
-rw-r--r--Jellyfin.Api/Controllers/VideosController.cs8
-rw-r--r--Jellyfin.Api/Helpers/HlsHelpers.cs5
-rw-r--r--Jellyfin.Api/Helpers/ProgressiveFileCopier.cs3
-rw-r--r--Jellyfin.Api/Helpers/StreamingHelpers.cs9
-rw-r--r--Jellyfin.Api/Jellyfin.Api.csproj4
-rw-r--r--Jellyfin.Data/Entities/AccessSchedule.cs8
-rw-r--r--Jellyfin.Data/Entities/ActivityLog.cs7
-rw-r--r--Jellyfin.Data/Entities/CustomItemDisplayPreferences.cs4
-rw-r--r--Jellyfin.Data/Entities/DisplayPreferences.cs12
-rw-r--r--Jellyfin.Data/Entities/Group.cs16
-rw-r--r--Jellyfin.Data/Entities/HomeSection.cs4
-rw-r--r--Jellyfin.Data/Entities/ImageInfo.cs8
-rw-r--r--Jellyfin.Data/Entities/ItemDisplayPreferences.cs4
-rw-r--r--Jellyfin.Data/Entities/Libraries/Artwork.cs8
-rw-r--r--Jellyfin.Data/Entities/Libraries/Book.cs8
-rw-r--r--Jellyfin.Data/Entities/Libraries/BookMetadata.cs6
-rw-r--r--Jellyfin.Data/Entities/Libraries/Chapter.cs8
-rw-r--r--Jellyfin.Data/Entities/Libraries/Collection.cs11
-rw-r--r--Jellyfin.Data/Entities/Libraries/CollectionItem.cs2
-rw-r--r--Jellyfin.Data/Entities/Libraries/Company.cs16
-rw-r--r--Jellyfin.Data/Entities/Libraries/CustomItem.cs8
-rw-r--r--Jellyfin.Data/Entities/Libraries/Episode.cs8
-rw-r--r--Jellyfin.Data/Entities/Libraries/Genre.cs6
-rw-r--r--Jellyfin.Data/Entities/Libraries/ItemMetadata.cs37
-rw-r--r--Jellyfin.Data/Entities/Libraries/Library.cs6
-rw-r--r--Jellyfin.Data/Entities/Libraries/LibraryItem.cs10
-rw-r--r--Jellyfin.Data/Entities/Libraries/MediaFile.cs12
-rw-r--r--Jellyfin.Data/Entities/Libraries/MediaFileStream.cs6
-rw-r--r--Jellyfin.Data/Entities/Libraries/MetadataProvider.cs6
-rw-r--r--Jellyfin.Data/Entities/Libraries/MetadataProviderId.cs6
-rw-r--r--Jellyfin.Data/Entities/Libraries/Movie.cs8
-rw-r--r--Jellyfin.Data/Entities/Libraries/MovieMetadata.cs6
-rw-r--r--Jellyfin.Data/Entities/Libraries/MusicAlbum.cs10
-rw-r--r--Jellyfin.Data/Entities/Libraries/MusicAlbumMetadata.cs6
-rw-r--r--Jellyfin.Data/Entities/Libraries/Person.cs16
-rw-r--r--Jellyfin.Data/Entities/Libraries/PersonRole.cs14
-rw-r--r--Jellyfin.Data/Entities/Libraries/Photo.cs8
-rw-r--r--Jellyfin.Data/Entities/Libraries/Rating.cs6
-rw-r--r--Jellyfin.Data/Entities/Libraries/RatingSource.cs6
-rw-r--r--Jellyfin.Data/Entities/Libraries/Release.cs16
-rw-r--r--Jellyfin.Data/Entities/Libraries/Season.cs10
-rw-r--r--Jellyfin.Data/Entities/Libraries/Series.cs11
-rw-r--r--Jellyfin.Data/Entities/Libraries/SeriesMetadata.cs6
-rw-r--r--Jellyfin.Data/Entities/Libraries/Track.cs8
-rw-r--r--Jellyfin.Data/Entities/Permission.cs16
-rw-r--r--Jellyfin.Data/Entities/Preference.cs15
-rw-r--r--Jellyfin.Data/Entities/User.cs44
-rw-r--r--Jellyfin.Data/Enums/HomeSectionType.cs7
-rw-r--r--Jellyfin.Drawing.Skia/StripCollageBuilder.cs14
-rw-r--r--Jellyfin.Networking/Manager/NetworkManager.cs2
-rw-r--r--Jellyfin.Server.Implementations/JellyfinDb.cs68
-rw-r--r--Jellyfin.Server.Implementations/Migrations/20210320181425_AddIndexesAndCollations.Designer.cs535
-rw-r--r--Jellyfin.Server.Implementations/Migrations/20210320181425_AddIndexesAndCollations.cs240
-rw-r--r--Jellyfin.Server.Implementations/Migrations/JellyfinDbModelSnapshot.cs33
-rw-r--r--Jellyfin.Server.Implementations/Users/UserManager.cs18
-rw-r--r--Jellyfin.Server/Migrations/Routines/CreateUserLoggingConfigFile.cs2
-rw-r--r--MediaBrowser.Common/Configuration/ConfigurationStore.cs2
-rw-r--r--MediaBrowser.Common/Configuration/ConfigurationUpdateEventArgs.cs1
-rw-r--r--MediaBrowser.Common/Configuration/IApplicationPaths.cs2
-rw-r--r--MediaBrowser.Common/Cryptography/PasswordHash.cs1
-rw-r--r--MediaBrowser.Common/Events/EventHelper.cs4
-rw-r--r--MediaBrowser.Common/Extensions/BaseExtensions.cs2
-rw-r--r--MediaBrowser.Common/Extensions/CopyToExtensions.cs2
-rw-r--r--MediaBrowser.Common/Extensions/HttpContextExtensions.cs2
-rw-r--r--MediaBrowser.Common/Extensions/MethodNotAllowedException.cs2
-rw-r--r--MediaBrowser.Common/Extensions/ProcessExtensions.cs2
-rw-r--r--MediaBrowser.Common/Extensions/RateLimitExceededException.cs1
-rw-r--r--MediaBrowser.Common/Extensions/ResourceNotFoundException.cs2
-rw-r--r--MediaBrowser.Common/Extensions/ShuffleExtensions.cs2
-rw-r--r--MediaBrowser.Common/Extensions/SplitStringExtensions.cs95
-rw-r--r--MediaBrowser.Common/Extensions/StreamExtensions.cs22
-rw-r--r--MediaBrowser.Common/IApplicationHost.cs2
-rw-r--r--MediaBrowser.Common/Json/Converters/JsonCommaDelimitedArrayConverter.cs57
-rw-r--r--MediaBrowser.Common/Json/Converters/JsonCommaDelimitedArrayConverterFactory.cs4
-rw-r--r--MediaBrowser.Common/Json/Converters/JsonDelimitedArrayConverter.cs81
-rw-r--r--MediaBrowser.Common/Json/Converters/JsonNullableStructConverterFactory.cs6
-rw-r--r--MediaBrowser.Common/Json/Converters/JsonOmdbNotAvailableStringConverter.cs18
-rw-r--r--MediaBrowser.Common/Json/Converters/JsonPipeDelimitedArrayConverter.cs57
-rw-r--r--MediaBrowser.Common/Json/Converters/JsonPipeDelimitedArrayConverterFactory.cs4
-rw-r--r--MediaBrowser.Common/Json/Converters/JsonStringConverter.cs8
-rw-r--r--MediaBrowser.Common/Json/Converters/JsonVersionConverter.cs2
-rw-r--r--MediaBrowser.Common/MediaBrowser.Common.csproj1
-rw-r--r--MediaBrowser.Common/Net/INetworkManager.cs1
-rw-r--r--MediaBrowser.Common/Net/IPHost.cs6
-rw-r--r--MediaBrowser.Common/Net/IPNetAddress.cs1
-rw-r--r--MediaBrowser.Common/Net/IPObject.cs1
-rw-r--r--MediaBrowser.Common/Plugins/BasePlugin.cs2
-rw-r--r--MediaBrowser.Common/Plugins/BasePluginOfT.cs7
-rw-r--r--MediaBrowser.Common/Plugins/IPlugin.cs2
-rw-r--r--MediaBrowser.Common/Plugins/IPluginManager.cs2
-rw-r--r--MediaBrowser.Common/Plugins/LocalPlugin.cs1
-rw-r--r--MediaBrowser.Common/Plugins/PluginManifest.cs2
-rw-r--r--MediaBrowser.Common/Progress/ActionableProgress.cs4
-rw-r--r--MediaBrowser.Common/Progress/SimpleProgress.cs2
-rw-r--r--MediaBrowser.Common/Providers/ProviderIdParsers.cs4
-rw-r--r--MediaBrowser.Common/Updates/IInstallationManager.cs2
-rw-r--r--MediaBrowser.Common/Updates/InstallationEventArgs.cs2
-rw-r--r--MediaBrowser.Common/Updates/InstallationFailedEventArgs.cs1
-rw-r--r--MediaBrowser.Controller/Authentication/AuthenticationResult.cs2
-rw-r--r--MediaBrowser.Controller/Authentication/IAuthenticationProvider.cs2
-rw-r--r--MediaBrowser.Controller/Authentication/IPasswordResetProvider.cs2
-rw-r--r--MediaBrowser.Controller/BaseItemManager/BaseItemManager.cs2
-rw-r--r--MediaBrowser.Controller/BaseItemManager/IBaseItemManager.cs2
-rw-r--r--MediaBrowser.Controller/Channels/Channel.cs2
-rw-r--r--MediaBrowser.Controller/Channels/ChannelItemInfo.cs28
-rw-r--r--MediaBrowser.Controller/Channels/ChannelItemResult.cs10
-rw-r--r--MediaBrowser.Controller/Channels/ChannelLatestMediaSearch.cs11
-rw-r--r--MediaBrowser.Controller/Channels/ChannelSearchInfo.cs7
-rw-r--r--MediaBrowser.Controller/Channels/IChannel.cs2
-rw-r--r--MediaBrowser.Controller/Channels/IChannelManager.cs2
-rw-r--r--MediaBrowser.Controller/Channels/IHasCacheKey.cs2
-rw-r--r--MediaBrowser.Controller/Channels/ISearchableChannel.cs2
-rw-r--r--MediaBrowser.Controller/Channels/InternalChannelFeatures.cs2
-rw-r--r--MediaBrowser.Controller/Channels/InternalChannelItemQuery.cs2
-rw-r--r--MediaBrowser.Controller/Collections/CollectionCreatedEventArgs.cs24
-rw-r--r--MediaBrowser.Controller/Collections/CollectionCreationOptions.cs6
-rw-r--r--MediaBrowser.Controller/Collections/CollectionModifiedEventArgs.cs (renamed from MediaBrowser.Controller/Collections/CollectionEvents.cs)25
-rw-r--r--MediaBrowser.Controller/Collections/ICollectionManager.cs2
-rw-r--r--MediaBrowser.Controller/Configuration/IServerConfigurationManager.cs2
-rw-r--r--MediaBrowser.Controller/Devices/IDeviceManager.cs2
-rw-r--r--MediaBrowser.Controller/Dlna/IDlnaManager.cs2
-rw-r--r--MediaBrowser.Controller/Drawing/IImageEncoder.cs2
-rw-r--r--MediaBrowser.Controller/Drawing/IImageProcessor.cs2
-rw-r--r--MediaBrowser.Controller/Drawing/ImageCollageOptions.cs6
-rw-r--r--MediaBrowser.Controller/Drawing/ImageHelper.cs2
-rw-r--r--MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs2
-rw-r--r--MediaBrowser.Controller/Drawing/ImageProcessorExtensions.cs2
-rw-r--r--MediaBrowser.Controller/Drawing/ImageStream.cs12
-rw-r--r--MediaBrowser.Controller/Dto/DtoOptions.cs47
-rw-r--r--MediaBrowser.Controller/Dto/IDtoService.cs2
-rw-r--r--MediaBrowser.Controller/Entities/AggregateFolder.cs6
-rw-r--r--MediaBrowser.Controller/Entities/Audio/Audio.cs2
-rw-r--r--MediaBrowser.Controller/Entities/Audio/IHasAlbumArtist.cs2
-rw-r--r--MediaBrowser.Controller/Entities/Audio/IHasMusicGenres.cs2
-rw-r--r--MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs2
-rw-r--r--MediaBrowser.Controller/Entities/Audio/MusicArtist.cs4
-rw-r--r--MediaBrowser.Controller/Entities/Audio/MusicGenre.cs2
-rw-r--r--MediaBrowser.Controller/Entities/AudioBook.cs2
-rw-r--r--MediaBrowser.Controller/Entities/BaseItem.cs38
-rw-r--r--MediaBrowser.Controller/Entities/BaseItemExtensions.cs2
-rw-r--r--MediaBrowser.Controller/Entities/BasePluginFolder.cs2
-rw-r--r--MediaBrowser.Controller/Entities/Book.cs12
-rw-r--r--MediaBrowser.Controller/Entities/CollectionFolder.cs8
-rw-r--r--MediaBrowser.Controller/Entities/Extensions.cs2
-rw-r--r--MediaBrowser.Controller/Entities/Folder.cs19
-rw-r--r--MediaBrowser.Controller/Entities/Genre.cs4
-rw-r--r--MediaBrowser.Controller/Entities/ICollectionFolder.cs2
-rw-r--r--MediaBrowser.Controller/Entities/IHasAspectRatio.cs2
-rw-r--r--MediaBrowser.Controller/Entities/IHasDisplayOrder.cs2
-rw-r--r--MediaBrowser.Controller/Entities/IHasMediaSources.cs2
-rw-r--r--MediaBrowser.Controller/Entities/IHasProgramAttributes.cs2
-rw-r--r--MediaBrowser.Controller/Entities/IHasSeries.cs2
-rw-r--r--MediaBrowser.Controller/Entities/IHasSpecialFeatures.cs2
-rw-r--r--MediaBrowser.Controller/Entities/IHasTrailers.cs2
-rw-r--r--MediaBrowser.Controller/Entities/InternalItemsQuery.cs2
-rw-r--r--MediaBrowser.Controller/Entities/InternalPeopleQuery.cs24
-rw-r--r--MediaBrowser.Controller/Entities/ItemImageInfo.cs2
-rw-r--r--MediaBrowser.Controller/Entities/LinkedChild.cs47
-rw-r--r--MediaBrowser.Controller/Entities/LinkedChildComparer.cs34
-rw-r--r--MediaBrowser.Controller/Entities/LinkedChildType.cs18
-rw-r--r--MediaBrowser.Controller/Entities/Movies/BoxSet.cs5
-rw-r--r--MediaBrowser.Controller/Entities/Movies/Movie.cs2
-rw-r--r--MediaBrowser.Controller/Entities/MusicVideo.cs10
-rw-r--r--MediaBrowser.Controller/Entities/PeopleHelper.cs18
-rw-r--r--MediaBrowser.Controller/Entities/Person.cs2
-rw-r--r--MediaBrowser.Controller/Entities/PersonInfo.cs2
-rw-r--r--MediaBrowser.Controller/Entities/Photo.cs5
-rw-r--r--MediaBrowser.Controller/Entities/Share.cs2
-rw-r--r--MediaBrowser.Controller/Entities/Studio.cs2
-rw-r--r--MediaBrowser.Controller/Entities/TV/Episode.cs2
-rw-r--r--MediaBrowser.Controller/Entities/TV/Season.cs2
-rw-r--r--MediaBrowser.Controller/Entities/TV/Series.cs13
-rw-r--r--MediaBrowser.Controller/Entities/Trailer.cs2
-rw-r--r--MediaBrowser.Controller/Entities/UserItemData.cs2
-rw-r--r--MediaBrowser.Controller/Entities/UserRootFolder.cs2
-rw-r--r--MediaBrowser.Controller/Entities/UserView.cs7
-rw-r--r--MediaBrowser.Controller/Entities/UserViewBuilder.cs2
-rw-r--r--MediaBrowser.Controller/Entities/Video.cs2
-rw-r--r--MediaBrowser.Controller/Entities/Year.cs2
-rw-r--r--MediaBrowser.Controller/Events/IEventConsumer.cs2
-rw-r--r--MediaBrowser.Controller/Events/IEventManager.cs2
-rw-r--r--MediaBrowser.Controller/Events/Session/SessionEndedEventArgs.cs2
-rw-r--r--MediaBrowser.Controller/Events/Session/SessionStartedEventArgs.cs2
-rw-r--r--MediaBrowser.Controller/Events/Updates/PluginInstallationCancelledEventArgs.cs2
-rw-r--r--MediaBrowser.Controller/Events/Updates/PluginInstalledEventArgs.cs2
-rw-r--r--MediaBrowser.Controller/Events/Updates/PluginInstallingEventArgs.cs2
-rw-r--r--MediaBrowser.Controller/Events/Updates/PluginUpdatedEventArgs.cs2
-rw-r--r--MediaBrowser.Controller/Extensions/StringExtensions.cs1
-rw-r--r--MediaBrowser.Controller/IDisplayPreferencesManager.cs2
-rw-r--r--MediaBrowser.Controller/IServerApplicationHost.cs2
-rw-r--r--MediaBrowser.Controller/IServerApplicationPaths.cs2
-rw-r--r--MediaBrowser.Controller/Library/DeleteOptions.cs8
-rw-r--r--MediaBrowser.Controller/Library/IIntroProvider.cs14
-rw-r--r--MediaBrowser.Controller/Library/ILibraryManager.cs2
-rw-r--r--MediaBrowser.Controller/Library/ILiveStream.cs2
-rw-r--r--MediaBrowser.Controller/Library/IMediaSourceManager.cs2
-rw-r--r--MediaBrowser.Controller/Library/IMetadataSaver.cs2
-rw-r--r--MediaBrowser.Controller/Library/IMusicManager.cs2
-rw-r--r--MediaBrowser.Controller/Library/IUserDataManager.cs2
-rw-r--r--MediaBrowser.Controller/Library/IUserManager.cs2
-rw-r--r--MediaBrowser.Controller/Library/IUserViewManager.cs2
-rw-r--r--MediaBrowser.Controller/Library/IntroInfo.cs2
-rw-r--r--MediaBrowser.Controller/Library/ItemChangeEventArgs.cs2
-rw-r--r--MediaBrowser.Controller/Library/ItemResolveArgs.cs29
-rw-r--r--MediaBrowser.Controller/Library/LibraryManagerExtensions.cs2
-rw-r--r--MediaBrowser.Controller/Library/MetadataConfigurationExtensions.cs2
-rw-r--r--MediaBrowser.Controller/Library/NameExtensions.cs1
-rw-r--r--MediaBrowser.Controller/Library/PlaybackProgressEventArgs.cs2
-rw-r--r--MediaBrowser.Controller/Library/PlaybackStartEventArgs.cs2
-rw-r--r--MediaBrowser.Controller/Library/Profiler.cs6
-rw-r--r--MediaBrowser.Controller/Library/SearchHintInfo.cs2
-rw-r--r--MediaBrowser.Controller/Library/TVUtils.cs4
-rw-r--r--MediaBrowser.Controller/Library/UserDataSaveEventArgs.cs2
-rw-r--r--MediaBrowser.Controller/LiveTv/ActiveRecordingInfo.cs19
-rw-r--r--MediaBrowser.Controller/LiveTv/ChannelInfo.cs8
-rw-r--r--MediaBrowser.Controller/LiveTv/IListingsProvider.cs2
-rw-r--r--MediaBrowser.Controller/LiveTv/ILiveTvManager.cs18
-rw-r--r--MediaBrowser.Controller/LiveTv/ILiveTvService.cs2
-rw-r--r--MediaBrowser.Controller/LiveTv/ITunerHost.cs2
-rw-r--r--MediaBrowser.Controller/LiveTv/LiveTvChannel.cs2
-rw-r--r--MediaBrowser.Controller/LiveTv/LiveTvProgram.cs14
-rw-r--r--MediaBrowser.Controller/LiveTv/LiveTvServiceStatusInfo.cs2
-rw-r--r--MediaBrowser.Controller/LiveTv/LiveTvTunerInfo.cs2
-rw-r--r--MediaBrowser.Controller/LiveTv/ProgramInfo.cs35
-rw-r--r--MediaBrowser.Controller/LiveTv/RecordingInfo.cs28
-rw-r--r--MediaBrowser.Controller/LiveTv/RecordingStatusChangedEventArgs.cs2
-rw-r--r--MediaBrowser.Controller/LiveTv/SeriesTimerInfo.cs31
-rw-r--r--MediaBrowser.Controller/LiveTv/TimerEventInfo.cs2
-rw-r--r--MediaBrowser.Controller/LiveTv/TimerInfo.cs2
-rw-r--r--MediaBrowser.Controller/LiveTv/TunerChannelMapping.cs2
-rw-r--r--MediaBrowser.Controller/MediaBrowser.Controller.csproj3
-rw-r--r--MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs2
-rw-r--r--MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs2
-rw-r--r--MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs2
-rw-r--r--MediaBrowser.Controller/MediaEncoding/IAttachmentExtractor.cs2
-rw-r--r--MediaBrowser.Controller/MediaEncoding/IEncodingManager.cs2
-rw-r--r--MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs2
-rw-r--r--MediaBrowser.Controller/MediaEncoding/ISubtitleEncoder.cs2
-rw-r--r--MediaBrowser.Controller/MediaEncoding/ImageEncodingOptions.cs2
-rw-r--r--MediaBrowser.Controller/MediaEncoding/JobLogger.cs2
-rw-r--r--MediaBrowser.Controller/MediaEncoding/MediaEncoderHelpers.cs1
-rw-r--r--MediaBrowser.Controller/MediaEncoding/MediaInfoRequest.cs2
-rw-r--r--MediaBrowser.Controller/Net/AuthorizationInfo.cs2
-rw-r--r--MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs2
-rw-r--r--MediaBrowser.Controller/Net/IAuthService.cs2
-rw-r--r--MediaBrowser.Controller/Net/IWebSocketConnection.cs4
-rw-r--r--MediaBrowser.Controller/Net/SecurityException.cs2
-rw-r--r--MediaBrowser.Controller/Net/WebSocketMessageInfo.cs2
-rw-r--r--MediaBrowser.Controller/Notifications/INotificationManager.cs2
-rw-r--r--MediaBrowser.Controller/Notifications/INotificationService.cs2
-rw-r--r--MediaBrowser.Controller/Notifications/UserNotification.cs2
-rw-r--r--MediaBrowser.Controller/Persistence/IItemRepository.cs5
-rw-r--r--MediaBrowser.Controller/Persistence/IUserDataRepository.cs2
-rw-r--r--MediaBrowser.Controller/Playlists/Playlist.cs7
-rw-r--r--MediaBrowser.Controller/Plugins/ILocalizablePlugin.cs22
-rw-r--r--MediaBrowser.Controller/Providers/AlbumInfo.cs14
-rw-r--r--MediaBrowser.Controller/Providers/ArtistInfo.cs4
-rw-r--r--MediaBrowser.Controller/Providers/BookInfo.cs2
-rw-r--r--MediaBrowser.Controller/Providers/DirectoryService.cs19
-rw-r--r--MediaBrowser.Controller/Providers/DynamicImageResponse.cs2
-rw-r--r--MediaBrowser.Controller/Providers/EpisodeInfo.cs12
-rw-r--r--MediaBrowser.Controller/Providers/IDirectoryService.cs2
-rw-r--r--MediaBrowser.Controller/Providers/IExternalId.cs2
-rw-r--r--MediaBrowser.Controller/Providers/IMetadataService.cs12
-rw-r--r--MediaBrowser.Controller/Providers/IProviderManager.cs9
-rw-r--r--MediaBrowser.Controller/Providers/ImageRefreshOptions.cs2
-rw-r--r--MediaBrowser.Controller/Providers/ItemInfo.cs5
-rw-r--r--MediaBrowser.Controller/Providers/ItemLookupInfo.cs14
-rw-r--r--MediaBrowser.Controller/Providers/LocalImageInfo.cs2
-rw-r--r--MediaBrowser.Controller/Providers/MetadataRefreshOptions.cs38
-rw-r--r--MediaBrowser.Controller/Providers/MetadataResult.cs18
-rw-r--r--MediaBrowser.Controller/Providers/MusicVideoInfo.cs2
-rw-r--r--MediaBrowser.Controller/Providers/RefreshPriority.cs23
-rw-r--r--MediaBrowser.Controller/Providers/RemoteSearchQuery.cs4
-rw-r--r--MediaBrowser.Controller/Providers/SeasonInfo.cs4
-rw-r--r--MediaBrowser.Controller/Providers/SongInfo.cs2
-rw-r--r--MediaBrowser.Controller/QuickConnect/IQuickConnect.cs2
-rw-r--r--MediaBrowser.Controller/Resolvers/BaseItemResolver.cs14
-rw-r--r--MediaBrowser.Controller/Resolvers/IResolverIgnoreRule.cs2
-rw-r--r--MediaBrowser.Controller/Security/AuthenticationInfo.cs2
-rw-r--r--MediaBrowser.Controller/Security/AuthenticationInfoQuery.cs2
-rw-r--r--MediaBrowser.Controller/Security/IAuthenticationRepository.cs2
-rw-r--r--MediaBrowser.Controller/Session/AuthenticationRequest.cs2
-rw-r--r--MediaBrowser.Controller/Session/ISessionController.cs2
-rw-r--r--MediaBrowser.Controller/Session/ISessionManager.cs6
-rw-r--r--MediaBrowser.Controller/Session/SessionEventArgs.cs2
-rw-r--r--MediaBrowser.Controller/Session/SessionInfo.cs6
-rw-r--r--MediaBrowser.Controller/Sorting/AlphanumComparator.cs2
-rw-r--r--MediaBrowser.Controller/Sorting/IUserBaseItemComparer.cs2
-rw-r--r--MediaBrowser.Controller/Sorting/SortExtensions.cs2
-rw-r--r--MediaBrowser.Controller/Subtitles/ISubtitleManager.cs2
-rw-r--r--MediaBrowser.Controller/Subtitles/ISubtitleProvider.cs2
-rw-r--r--MediaBrowser.Controller/Subtitles/SubtitleDownloadFailureEventArgs.cs2
-rw-r--r--MediaBrowser.Controller/Subtitles/SubtitleResponse.cs2
-rw-r--r--MediaBrowser.Controller/Subtitles/SubtitleSearchRequest.cs2
-rw-r--r--MediaBrowser.Controller/Sync/IHasDynamicAccess.cs2
-rw-r--r--MediaBrowser.Controller/Sync/IServerSyncProvider.cs2
-rw-r--r--MediaBrowser.Controller/Sync/ISyncProvider.cs2
-rw-r--r--MediaBrowser.Controller/Sync/SyncedFileInfo.cs2
-rw-r--r--MediaBrowser.Controller/SyncPlay/GroupMember.cs2
-rw-r--r--MediaBrowser.Controller/SyncPlay/GroupStates/AbstractGroupState.cs2
-rw-r--r--MediaBrowser.Controller/SyncPlay/GroupStates/IdleGroupState.cs2
-rw-r--r--MediaBrowser.Controller/SyncPlay/GroupStates/PausedGroupState.cs2
-rw-r--r--MediaBrowser.Controller/SyncPlay/GroupStates/PlayingGroupState.cs2
-rw-r--r--MediaBrowser.Controller/SyncPlay/GroupStates/WaitingGroupState.cs2
-rw-r--r--MediaBrowser.Controller/SyncPlay/IGroupPlaybackRequest.cs2
-rw-r--r--MediaBrowser.Controller/SyncPlay/IGroupState.cs2
-rw-r--r--MediaBrowser.Controller/SyncPlay/IGroupStateContext.cs2
-rw-r--r--MediaBrowser.Controller/SyncPlay/ISyncPlayManager.cs2
-rw-r--r--MediaBrowser.Controller/SyncPlay/PlaybackRequests/AbstractPlaybackRequest.cs2
-rw-r--r--MediaBrowser.Controller/SyncPlay/PlaybackRequests/BufferGroupRequest.cs2
-rw-r--r--MediaBrowser.Controller/SyncPlay/PlaybackRequests/IgnoreWaitGroupRequest.cs2
-rw-r--r--MediaBrowser.Controller/SyncPlay/PlaybackRequests/MovePlaylistItemGroupRequest.cs2
-rw-r--r--MediaBrowser.Controller/SyncPlay/PlaybackRequests/NextItemGroupRequest.cs2
-rw-r--r--MediaBrowser.Controller/SyncPlay/PlaybackRequests/PauseGroupRequest.cs2
-rw-r--r--MediaBrowser.Controller/SyncPlay/PlaybackRequests/PingGroupRequest.cs2
-rw-r--r--MediaBrowser.Controller/SyncPlay/PlaybackRequests/PlayGroupRequest.cs2
-rw-r--r--MediaBrowser.Controller/SyncPlay/PlaybackRequests/PreviousItemGroupRequest.cs2
-rw-r--r--MediaBrowser.Controller/SyncPlay/PlaybackRequests/QueueGroupRequest.cs2
-rw-r--r--MediaBrowser.Controller/SyncPlay/PlaybackRequests/ReadyGroupRequest.cs2
-rw-r--r--MediaBrowser.Controller/SyncPlay/PlaybackRequests/RemoveFromPlaylistGroupRequest.cs2
-rw-r--r--MediaBrowser.Controller/SyncPlay/PlaybackRequests/SeekGroupRequest.cs2
-rw-r--r--MediaBrowser.Controller/SyncPlay/PlaybackRequests/SetPlaylistItemGroupRequest.cs2
-rw-r--r--MediaBrowser.Controller/SyncPlay/PlaybackRequests/SetRepeatModeGroupRequest.cs2
-rw-r--r--MediaBrowser.Controller/SyncPlay/PlaybackRequests/SetShuffleModeGroupRequest.cs2
-rw-r--r--MediaBrowser.Controller/SyncPlay/Queue/PlayQueueManager.cs2
-rw-r--r--MediaBrowser.LocalMetadata/BaseXmlProvider.cs2
-rw-r--r--MediaBrowser.LocalMetadata/Images/EpisodeLocalImageProvider.cs4
-rw-r--r--MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs3
-rw-r--r--MediaBrowser.LocalMetadata/Providers/BoxSetXmlProvider.cs2
-rw-r--r--MediaBrowser.LocalMetadata/Providers/PlaylistXmlProvider.cs2
-rw-r--r--MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs6
-rw-r--r--MediaBrowser.MediaEncoding/BdInfo/BdInfoExaminer.cs16
-rw-r--r--MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs56
-rw-r--r--MediaBrowser.Model/Dlna/ContainerProfile.cs59
-rw-r--r--MediaBrowser.Model/Dlna/DeviceProfile.cs149
-rw-r--r--MediaBrowser.Model/Dlna/DirectPlayProfile.cs8
-rw-r--r--MediaBrowser.Model/Dlna/StreamBuilder.cs2
-rw-r--r--MediaBrowser.Model/Dlna/TranscodingProfile.cs22
-rw-r--r--MediaBrowser.Model/Entities/MediaStream.cs10
-rw-r--r--MediaBrowser.Model/Entities/ProviderIdsExtensions.cs5
-rw-r--r--MediaBrowser.Model/IO/FileSystemMetadata.cs6
-rw-r--r--MediaBrowser.Providers/Manager/MetadataService.cs6
-rw-r--r--MediaBrowser.Providers/Manager/ProviderManager.cs2
-rw-r--r--MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs4
-rw-r--r--MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs5
-rw-r--r--MediaBrowser.Providers/MediaInfo/SubtitleDownloader.cs4
-rw-r--r--MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs4
-rw-r--r--MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieProvider.cs7
-rw-r--r--MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeriesProvider.cs2
-rw-r--r--MediaBrowser.Providers/Plugins/Tmdb/TmdbUtils.cs25
-rw-r--r--MediaBrowser.Providers/Studios/StudiosImageProvider.cs9
-rw-r--r--MediaBrowser.Providers/Subtitles/SubtitleManager.cs15
-rw-r--r--MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs102
-rw-r--r--MediaBrowser.XbmcMetadata/Providers/AlbumNfoProvider.cs2
-rw-r--r--MediaBrowser.XbmcMetadata/Providers/ArtistNfoProvider.cs2
-rw-r--r--MediaBrowser.XbmcMetadata/Providers/EpisodeNfoProvider.cs2
-rw-r--r--MediaBrowser.XbmcMetadata/Providers/SeasonNfoProvider.cs2
-rw-r--r--MediaBrowser.XbmcMetadata/Providers/SeriesNfoProvider.cs2
-rw-r--r--RSSDP/SsdpCommunicationsServer.cs5
-rw-r--r--apiclient/.openapi-generator-ignore2
-rw-r--r--apiclient/templates/typescript/axios/generate.sh11
-rw-r--r--apiclient/templates/typescript/axios/package.mustache30
-rw-r--r--tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj4
-rw-r--r--tests/Jellyfin.Model.Tests/Dlna/ContainerProfileTests.cs19
-rw-r--r--tests/Jellyfin.Networking.Tests/NetworkParseTests.cs10
-rw-r--r--tests/Jellyfin.Server.Implementations.Tests/Data/SqliteItemRepositoryTests.cs250
-rw-r--r--tests/Jellyfin.Server.Implementations.Tests/IO/ManagedFileSystemTests.cs10
-rw-r--r--tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj2
-rw-r--r--tests/Jellyfin.Server.Implementations.Tests/Library/EpisodeResolverTest.cs11
-rw-r--r--tests/Jellyfin.Server.Implementations.Tests/Library/PathExtensionsTests.cs1
-rw-r--r--tests/Jellyfin.Server.Integration.Tests/Jellyfin.Server.Integration.Tests.csproj11
-rw-r--r--tests/Jellyfin.Server.Integration.Tests/xunit.runner.json4
-rw-r--r--tests/Jellyfin.Server.Tests/Jellyfin.Server.Tests.csproj4
-rw-r--r--tests/Jellyfin.XbmcMetadata.Tests/Parsers/MovieNfoParserTests.cs6
-rw-r--r--tests/Jellyfin.XbmcMetadata.Tests/Test Data/Justice League.nfo2
488 files changed, 3512 insertions, 2136 deletions
diff --git a/.ci/azure-pipelines-api-client.yml b/.ci/azure-pipelines-api-client.yml
deleted file mode 100644
index 0e944e6f4..000000000
--- a/.ci/azure-pipelines-api-client.yml
+++ /dev/null
@@ -1,59 +0,0 @@
-parameters:
- - name: LinuxImage
- type: string
- default: "ubuntu-latest"
- - name: GeneratorVersion
- type: string
- default: "5.0.1"
-
-jobs:
-- job: GenerateApiClients
- displayName: 'Generate Api Clients'
- condition: startsWith(variables['Build.SourceBranch'], 'refs/tags/v')
- dependsOn: Test
-
- pool:
- vmImage: "${{ parameters.LinuxImage }}"
-
- steps:
- - task: DownloadPipelineArtifact@2
- displayName: 'Download OpenAPI Spec Artifact'
- inputs:
- source: 'current'
- artifact: "OpenAPI Spec"
- path: "$(System.ArtifactsDirectory)/openapispec"
- runVersion: "latest"
-
- - task: CmdLine@2
- displayName: 'Download OpenApi Generator'
- inputs:
- script: "wget https://repo1.maven.org/maven2/org/openapitools/openapi-generator-cli/${{ parameters.GeneratorVersion }}/openapi-generator-cli-${{ parameters.GeneratorVersion }}.jar -O openapi-generator-cli.jar"
-
-## Authenticate with npm registry
- - task: npmAuthenticate@0
- inputs:
- workingFile: ./.npmrc
- customEndpoint: 'jellyfin-bot for NPM'
-
-## Generate npm api client
- - task: CmdLine@2
- displayName: 'Build stable typescript axios client'
- inputs:
- script: "bash ./apiclient/templates/typescript/axios/generate.sh $(System.ArtifactsDirectory)"
-
-## Run npm install
- - task: Npm@1
- displayName: 'Install npm dependencies'
- inputs:
- command: install
- workingDir: ./apiclient/generated/typescript/axios
-
-## Publish npm packages
- - task: Npm@1
- displayName: 'Publish stable typescript axios client'
- inputs:
- command: custom
- customCommand: publish --access public
- publishRegistry: useExternalRegistry
- publishEndpoint: 'jellyfin-bot for NPM'
- workingDir: ./apiclient/generated/typescript/axios
diff --git a/.ci/azure-pipelines.yml b/.ci/azure-pipelines.yml
index 6430503f9..c028b6e3e 100644
--- a/.ci/azure-pipelines.yml
+++ b/.ci/azure-pipelines.yml
@@ -61,6 +61,3 @@ jobs:
- ${{ if or(startsWith(variables['Build.SourceBranch'], 'refs/tags/v'), startsWith(variables['Build.SourceBranch'], 'refs/heads/master')) }}:
- template: azure-pipelines-package.yml
-
-- ${{ if or(startsWith(variables['Build.SourceBranch'], 'refs/tags/v'), startsWith(variables['Build.SourceBranch'], 'refs/heads/master')) }}:
- - template: azure-pipelines-api-client.yml
diff --git a/.github/label-commenter-config.yml b/.github/label-commenter-config.yml
new file mode 100644
index 000000000..78b75be43
--- /dev/null
+++ b/.github/label-commenter-config.yml
@@ -0,0 +1,43 @@
+comment:
+ header: Hello @{{ issue.user.login }}
+ footer: "\
+ ---\n\n
+ > This is an automated comment created by the [peaceiris/actions-label-commenter]. \
+ Responding to the bot or mentioning it won't have any effect.\n\n
+ [peaceiris/actions-label-commenter]: https://github.com/peaceiris/actions-label-commenter
+ "
+
+labels:
+ - name: stable backport
+ labeled:
+ pr:
+ body: |
+ This pull request has been tagged as a stable backport. It will be cherry-picked into the next stable point release.
+
+ Please observe the following:
+
+ * Any dependent PRs that this PR requires **must** be tagged for stable backporting as well.
+
+ * Any issue(s) this PR fixes or closes **should** target the current stable release or a previous stable release to which a fix has not yet entered the current stable release.
+
+ * This PR **must** be test cherry-picked against the current release branch (`release-X.Y.z` where X and Y are numbers). It must apply cleanly, or a diff of the expected change must be provided.
+
+ To do this, run the following commands from your local copy of the Jellyfin repository:
+
+ 1. `git checkout master`
+
+ 1. `git merge --no-ff <myPullRequestBranch>`
+
+ 1. `git log` -> `commit xxxxxxxxx`, grab hash
+
+ 1. `git checkout release-X.Y.z` replacing X and Y with the *current* stable version (e.g. `release-10.7.z`)
+
+ 1. `git cherry-pick -sx -m1 <hash>`
+
+ Ensure the `cherry-pick` applies cleanly. If it does not, fix any merge conflicts *preserving as much of the original code as possible*, and make note of the resulting diff.
+
+ Test your changes with a build to ensure they are successful. If not, adjust the diff accordingly.
+
+ **Do not** push your merges to either branch. Use `git reset --hard HEAD~1` to revert both branches to their original state.
+
+ Reply to this PR with a comment beginning "Cherry-pick test completed." and including the merge-conflict-fixing diff(s) if applicable.
diff --git a/.github/workflows/automation.yml b/.github/workflows/automation.yml
index d5d308185..2529d8099 100644
--- a/.github/workflows/automation.yml
+++ b/.github/workflows/automation.yml
@@ -2,8 +2,6 @@ name: Automation
on:
pull_request:
- issues:
- issue_comment:
jobs:
main:
@@ -16,7 +14,7 @@ jobs:
label: stable backport
- name: Remove from 'Current Release' project
- uses: alex-page/github-project-automation-plus@v0.6.0
+ uses: alex-page/github-project-automation-plus@v0.7.1
if: (github.event.pull_request || github.event.issue.pull_request) && !steps.checkLabel.outputs.hasLabel
continue-on-error: true
with:
@@ -25,7 +23,7 @@ jobs:
repo-token: ${{ secrets.GH_TOKEN }}
- name: Add to 'Release Next' project
- uses: alex-page/github-project-automation-plus@v0.6.0
+ uses: alex-page/github-project-automation-plus@v0.7.1
if: (github.event.pull_request || github.event.issue.pull_request) && github.event.action == 'opened'
continue-on-error: true
with:
@@ -34,7 +32,7 @@ jobs:
repo-token: ${{ secrets.GH_TOKEN }}
- name: Add to 'Current Release' project
- uses: alex-page/github-project-automation-plus@v0.6.0
+ uses: alex-page/github-project-automation-plus@v0.7.1
if: (github.event.pull_request || github.event.issue.pull_request) && steps.checkLabel.outputs.hasLabel
continue-on-error: true
with:
@@ -48,7 +46,7 @@ jobs:
run: echo "::set-output name=number::$(curl -s ${{ github.event.issue.comments_url }} | jq '.[] | select(.author_association == "MEMBER") | .author_association' | wc -l)"
- name: Move issue to needs triage
- uses: alex-page/github-project-automation-plus@v0.6.0
+ uses: alex-page/github-project-automation-plus@v0.7.1
if: github.event.issue.pull_request == '' && github.event.comment.author_association == 'MEMBER' && steps.member_comments.outputs.number <= 1
continue-on-error: true
with:
@@ -57,7 +55,7 @@ jobs:
repo-token: ${{ secrets.GH_TOKEN }}
- name: Add issue to triage project
- uses: alex-page/github-project-automation-plus@v0.6.0
+ uses: alex-page/github-project-automation-plus@v0.7.1
if: github.event.issue.pull_request == '' && github.event.action == 'opened'
continue-on-error: true
with:
diff --git a/.github/workflows/label-commenter.yml b/.github/workflows/label-commenter.yml
new file mode 100644
index 000000000..be9216cc1
--- /dev/null
+++ b/.github/workflows/label-commenter.yml
@@ -0,0 +1,22 @@
+name: Label Commenter
+
+on:
+ issues:
+ types:
+ - labeled
+ - unlabeled
+ pull_request_target:
+ types:
+ - labeled
+ - unlabeled
+
+jobs:
+ comment:
+ runs-on: ubuntu-20.04
+ steps:
+ - uses: actions/checkout@v2
+ with:
+ ref: master
+
+ - name: Label Commenter
+ uses: peaceiris/actions-label-commenter@v1
diff --git a/Dockerfile b/Dockerfile
index ebe5eb00c..4e2d06b82 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,11 +1,11 @@
ARG DOTNET_VERSION=5.0
-FROM node:alpine as web-builder
+FROM node:lts-alpine as web-builder
ARG JELLYFIN_WEB_VERSION=master
-RUN apk add curl git zlib zlib-dev autoconf g++ make libpng-dev gifsicle alpine-sdk automake libtool make gcc musl-dev nasm python \
+RUN apk add curl git zlib zlib-dev autoconf g++ make libpng-dev gifsicle alpine-sdk automake libtool make gcc musl-dev nasm python3 \
&& curl -L https://github.com/jellyfin/jellyfin-web/archive/${JELLYFIN_WEB_VERSION}.tar.gz | tar zxf - \
&& cd jellyfin-web-* \
- && npm ci --no-audit \
+ && npm ci --no-audit --unsafe-perm \
&& mv dist /dist
FROM mcr.microsoft.com/dotnet/sdk:${DOTNET_VERSION} as builder
diff --git a/Dockerfile.arm b/Dockerfile.arm
index d63dbee75..25a0de7db 100644
--- a/Dockerfile.arm
+++ b/Dockerfile.arm
@@ -5,12 +5,12 @@
ARG DOTNET_VERSION=5.0
-FROM node:alpine as web-builder
+FROM node:lts-alpine as web-builder
ARG JELLYFIN_WEB_VERSION=master
-RUN apk add curl git zlib zlib-dev autoconf g++ make libpng-dev gifsicle alpine-sdk automake libtool make gcc musl-dev nasm python \
+RUN apk add curl git zlib zlib-dev autoconf g++ make libpng-dev gifsicle alpine-sdk automake libtool make gcc musl-dev nasm python3 \
&& curl -L https://github.com/jellyfin/jellyfin-web/archive/${JELLYFIN_WEB_VERSION}.tar.gz | tar zxf - \
&& cd jellyfin-web-* \
- && npm ci --no-audit \
+ && npm ci --no-audit --unsafe-perm \
&& mv dist /dist
diff --git a/Dockerfile.arm64 b/Dockerfile.arm64
index e95999f2a..c9f19c5a3 100644
--- a/Dockerfile.arm64
+++ b/Dockerfile.arm64
@@ -5,12 +5,12 @@
ARG DOTNET_VERSION=5.0
-FROM node:alpine as web-builder
+FROM node:lts-alpine as web-builder
ARG JELLYFIN_WEB_VERSION=master
-RUN apk add curl git zlib zlib-dev autoconf g++ make libpng-dev gifsicle alpine-sdk automake libtool make gcc musl-dev nasm python \
+RUN apk add curl git zlib zlib-dev autoconf g++ make libpng-dev gifsicle alpine-sdk automake libtool make gcc musl-dev nasm python3 \
&& curl -L https://github.com/jellyfin/jellyfin-web/archive/${JELLYFIN_WEB_VERSION}.tar.gz | tar zxf - \
&& cd jellyfin-web-* \
- && npm ci --no-audit \
+ && npm ci --no-audit --unsafe-perm \
&& mv dist /dist
diff --git a/Emby.Dlna/Configuration/DlnaOptions.cs b/Emby.Dlna/Configuration/DlnaOptions.cs
index e63a85860..5ceeb5530 100644
--- a/Emby.Dlna/Configuration/DlnaOptions.cs
+++ b/Emby.Dlna/Configuration/DlnaOptions.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
namespace Emby.Dlna.Configuration
diff --git a/Emby.Dlna/ConfigurationExtension.cs b/Emby.Dlna/ConfigurationExtension.cs
index fc02e1751..3ca43052a 100644
--- a/Emby.Dlna/ConfigurationExtension.cs
+++ b/Emby.Dlna/ConfigurationExtension.cs
@@ -1,4 +1,3 @@
-#nullable enable
#pragma warning disable CS1591
using Emby.Dlna.Configuration;
diff --git a/Emby.Dlna/ContentDirectory/ContentDirectoryService.cs b/Emby.Dlna/ContentDirectory/ContentDirectoryService.cs
index 2f3107450..7b8c50440 100644
--- a/Emby.Dlna/ContentDirectory/ContentDirectoryService.cs
+++ b/Emby.Dlna/ContentDirectory/ContentDirectoryService.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/Emby.Dlna/ContentDirectory/ControlHandler.cs b/Emby.Dlna/ContentDirectory/ControlHandler.cs
index 90ba601b4..27c5b2268 100644
--- a/Emby.Dlna/ContentDirectory/ControlHandler.cs
+++ b/Emby.Dlna/ContentDirectory/ControlHandler.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections.Generic;
using System.Globalization;
diff --git a/Emby.Dlna/ControlRequest.cs b/Emby.Dlna/ControlRequest.cs
index 4ea4e4e48..8ee6325e9 100644
--- a/Emby.Dlna/ControlRequest.cs
+++ b/Emby.Dlna/ControlRequest.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System.IO;
diff --git a/Emby.Dlna/ControlResponse.cs b/Emby.Dlna/ControlResponse.cs
index d827eef26..a7f2d4a73 100644
--- a/Emby.Dlna/ControlResponse.cs
+++ b/Emby.Dlna/ControlResponse.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System.Collections.Generic;
diff --git a/Emby.Dlna/Didl/DidlBuilder.cs b/Emby.Dlna/Didl/DidlBuilder.cs
index 66ae07329..2982ce97e 100644
--- a/Emby.Dlna/Didl/DidlBuilder.cs
+++ b/Emby.Dlna/Didl/DidlBuilder.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
@@ -976,15 +978,28 @@ namespace Emby.Dlna.Didl
return;
}
- var albumartUrlInfo = GetImageUrl(imageInfo, _profile.MaxAlbumArtWidth, _profile.MaxAlbumArtHeight, "jpg");
+ // TODO: Remove these default values
+ var albumArtUrlInfo = GetImageUrl(
+ imageInfo,
+ _profile.MaxAlbumArtWidth ?? 10000,
+ _profile.MaxAlbumArtHeight ?? 10000,
+ "jpg");
writer.WriteStartElement("upnp", "albumArtURI", NsUpnp);
- writer.WriteAttributeString("dlna", "profileID", NsDlna, _profile.AlbumArtPn);
- writer.WriteString(albumartUrlInfo.url);
+ if (!string.IsNullOrEmpty(_profile.AlbumArtPn))
+ {
+ writer.WriteAttributeString("dlna", "profileID", NsDlna, _profile.AlbumArtPn);
+ }
+
+ writer.WriteString(albumArtUrlInfo.url);
writer.WriteFullEndElement();
- // TOOD: Remove these default values
- var iconUrlInfo = GetImageUrl(imageInfo, _profile.MaxIconWidth ?? 48, _profile.MaxIconHeight ?? 48, "jpg");
+ // TODO: Remove these default values
+ var iconUrlInfo = GetImageUrl(
+ imageInfo,
+ _profile.MaxIconWidth ?? 48,
+ _profile.MaxIconHeight ?? 48,
+ "jpg");
writer.WriteElementString("upnp", "icon", NsUpnp, iconUrlInfo.url);
if (!_profile.EnableAlbumArtInDidl)
@@ -1207,8 +1222,7 @@ namespace Emby.Dlna.Didl
if (width.HasValue && height.HasValue)
{
- var newSize = DrawingUtils.Resize(
- new ImageDimensions(width.Value, height.Value), 0, 0, maxWidth, maxHeight);
+ var newSize = DrawingUtils.Resize(new ImageDimensions(width.Value, height.Value), 0, 0, maxWidth, maxHeight);
width = newSize.Width;
height = newSize.Height;
diff --git a/Emby.Dlna/Didl/StringWriterWithEncoding.cs b/Emby.Dlna/Didl/StringWriterWithEncoding.cs
index 2b86ea333..b66f53ece 100644
--- a/Emby.Dlna/Didl/StringWriterWithEncoding.cs
+++ b/Emby.Dlna/Didl/StringWriterWithEncoding.cs
@@ -9,7 +9,7 @@ namespace Emby.Dlna.Didl
{
public class StringWriterWithEncoding : StringWriter
{
- private readonly Encoding _encoding;
+ private readonly Encoding? _encoding;
public StringWriterWithEncoding()
{
diff --git a/Emby.Dlna/DlnaConfigurationFactory.cs b/Emby.Dlna/DlnaConfigurationFactory.cs
index 4c6ca869a..6cc6b73a0 100644
--- a/Emby.Dlna/DlnaConfigurationFactory.cs
+++ b/Emby.Dlna/DlnaConfigurationFactory.cs
@@ -1,4 +1,3 @@
-#nullable enable
#pragma warning disable CS1591
using System.Collections.Generic;
diff --git a/Emby.Dlna/DlnaManager.cs b/Emby.Dlna/DlnaManager.cs
index 5f2be07cf..a1b106704 100644
--- a/Emby.Dlna/DlnaManager.cs
+++ b/Emby.Dlna/DlnaManager.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/Emby.Dlna/Emby.Dlna.csproj b/Emby.Dlna/Emby.Dlna.csproj
index 480621dd7..a40578e40 100644
--- a/Emby.Dlna/Emby.Dlna.csproj
+++ b/Emby.Dlna/Emby.Dlna.csproj
@@ -21,6 +21,7 @@
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
+ <Nullable>enable</Nullable>
</PropertyGroup>
<!-- Code Analyzers-->
diff --git a/Emby.Dlna/EventSubscriptionResponse.cs b/Emby.Dlna/EventSubscriptionResponse.cs
index 1b1bd426c..8c82dcbf6 100644
--- a/Emby.Dlna/EventSubscriptionResponse.cs
+++ b/Emby.Dlna/EventSubscriptionResponse.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System.Collections.Generic;
diff --git a/Emby.Dlna/Eventing/DlnaEventManager.cs b/Emby.Dlna/Eventing/DlnaEventManager.cs
index ff81e83b5..2e672b886 100644
--- a/Emby.Dlna/Eventing/DlnaEventManager.cs
+++ b/Emby.Dlna/Eventing/DlnaEventManager.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/Emby.Dlna/Eventing/EventSubscription.cs b/Emby.Dlna/Eventing/EventSubscription.cs
index 40d73ee0e..4fd7f8169 100644
--- a/Emby.Dlna/Eventing/EventSubscription.cs
+++ b/Emby.Dlna/Eventing/EventSubscription.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/Emby.Dlna/Main/DlnaEntryPoint.cs b/Emby.Dlna/Main/DlnaEntryPoint.cs
index bdfe430cf..0309926ab 100644
--- a/Emby.Dlna/Main/DlnaEntryPoint.cs
+++ b/Emby.Dlna/Main/DlnaEntryPoint.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/Emby.Dlna/PlayTo/Device.cs b/Emby.Dlna/PlayTo/Device.cs
index abd99bbc3..5fa1fd589 100644
--- a/Emby.Dlna/PlayTo/Device.cs
+++ b/Emby.Dlna/PlayTo/Device.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/Emby.Dlna/PlayTo/DeviceInfo.cs b/Emby.Dlna/PlayTo/DeviceInfo.cs
index d3daab9e0..2acfff4eb 100644
--- a/Emby.Dlna/PlayTo/DeviceInfo.cs
+++ b/Emby.Dlna/PlayTo/DeviceInfo.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System.Collections.Generic;
diff --git a/Emby.Dlna/PlayTo/MediaChangedEventArgs.cs b/Emby.Dlna/PlayTo/MediaChangedEventArgs.cs
index dabd079af..2bc4d8cc2 100644
--- a/Emby.Dlna/PlayTo/MediaChangedEventArgs.cs
+++ b/Emby.Dlna/PlayTo/MediaChangedEventArgs.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/Emby.Dlna/PlayTo/PlayToController.cs b/Emby.Dlna/PlayTo/PlayToController.cs
index ee09cc65a..1e6a5fadb 100644
--- a/Emby.Dlna/PlayTo/PlayToController.cs
+++ b/Emby.Dlna/PlayTo/PlayToController.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/Emby.Dlna/PlayTo/PlayToManager.cs b/Emby.Dlna/PlayTo/PlayToManager.cs
index f2f526221..35bf5927c 100644
--- a/Emby.Dlna/PlayTo/PlayToManager.cs
+++ b/Emby.Dlna/PlayTo/PlayToManager.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/Emby.Dlna/PlayTo/PlaybackProgressEventArgs.cs b/Emby.Dlna/PlayTo/PlaybackProgressEventArgs.cs
index d14617c8a..c7d2b28df 100644
--- a/Emby.Dlna/PlayTo/PlaybackProgressEventArgs.cs
+++ b/Emby.Dlna/PlayTo/PlaybackProgressEventArgs.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/Emby.Dlna/PlayTo/PlaybackStartEventArgs.cs b/Emby.Dlna/PlayTo/PlaybackStartEventArgs.cs
index 3f8d55263..f8a14f411 100644
--- a/Emby.Dlna/PlayTo/PlaybackStartEventArgs.cs
+++ b/Emby.Dlna/PlayTo/PlaybackStartEventArgs.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/Emby.Dlna/PlayTo/PlaybackStoppedEventArgs.cs b/Emby.Dlna/PlayTo/PlaybackStoppedEventArgs.cs
index deeb47918..6661f92ac 100644
--- a/Emby.Dlna/PlayTo/PlaybackStoppedEventArgs.cs
+++ b/Emby.Dlna/PlayTo/PlaybackStoppedEventArgs.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/Emby.Dlna/PlayTo/PlaylistItem.cs b/Emby.Dlna/PlayTo/PlaylistItem.cs
index 85846166c..5056e69ae 100644
--- a/Emby.Dlna/PlayTo/PlaylistItem.cs
+++ b/Emby.Dlna/PlayTo/PlaylistItem.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using MediaBrowser.Model.Dlna;
diff --git a/Emby.Dlna/PlayTo/PlaylistItemFactory.cs b/Emby.Dlna/PlayTo/PlaylistItemFactory.cs
index e28840a89..657491303 100644
--- a/Emby.Dlna/PlayTo/PlaylistItemFactory.cs
+++ b/Emby.Dlna/PlayTo/PlaylistItemFactory.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System.IO;
diff --git a/Emby.Dlna/PlayTo/SsdpHttpClient.cs b/Emby.Dlna/PlayTo/SsdpHttpClient.cs
index d9f1ce490..f14f73bb6 100644
--- a/Emby.Dlna/PlayTo/SsdpHttpClient.cs
+++ b/Emby.Dlna/PlayTo/SsdpHttpClient.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/Emby.Dlna/PlayTo/TransportCommands.cs b/Emby.Dlna/PlayTo/TransportCommands.cs
index cbcf66e45..b58669355 100644
--- a/Emby.Dlna/PlayTo/TransportCommands.cs
+++ b/Emby.Dlna/PlayTo/TransportCommands.cs
@@ -46,7 +46,7 @@ namespace Emby.Dlna.PlayTo
{
var serviceAction = new ServiceAction
{
- Name = container.GetValue(UPnpNamespaces.Svc + "name"),
+ Name = container.GetValue(UPnpNamespaces.Svc + "name") ?? string.Empty,
};
var argumentList = serviceAction.ArgumentList;
@@ -68,9 +68,9 @@ namespace Emby.Dlna.PlayTo
return new Argument
{
- Name = container.GetValue(UPnpNamespaces.Svc + "name"),
- Direction = container.GetValue(UPnpNamespaces.Svc + "direction"),
- RelatedStateVariable = container.GetValue(UPnpNamespaces.Svc + "relatedStateVariable")
+ Name = container.GetValue(UPnpNamespaces.Svc + "name") ?? string.Empty,
+ Direction = container.GetValue(UPnpNamespaces.Svc + "direction") ?? string.Empty,
+ RelatedStateVariable = container.GetValue(UPnpNamespaces.Svc + "relatedStateVariable") ?? string.Empty
};
}
@@ -89,8 +89,8 @@ namespace Emby.Dlna.PlayTo
return new StateVariable
{
- Name = container.GetValue(UPnpNamespaces.Svc + "name"),
- DataType = container.GetValue(UPnpNamespaces.Svc + "dataType"),
+ Name = container.GetValue(UPnpNamespaces.Svc + "name") ?? string.Empty,
+ DataType = container.GetValue(UPnpNamespaces.Svc + "dataType") ?? string.Empty,
AllowedValues = allowedValues
};
}
@@ -166,7 +166,7 @@ namespace Emby.Dlna.PlayTo
return string.Format(CultureInfo.InvariantCulture, CommandBase, action.Name, xmlNamesapce, stateString);
}
- private string BuildArgumentXml(Argument argument, string value, string commandParameter = "")
+ private string BuildArgumentXml(Argument argument, string? value, string commandParameter = "")
{
var state = StateVariables.FirstOrDefault(a => string.Equals(a.Name, argument.RelatedStateVariable, StringComparison.OrdinalIgnoreCase));
diff --git a/Emby.Dlna/PlayTo/uBaseObject.cs b/Emby.Dlna/PlayTo/uBaseObject.cs
index 0d9478e42..02d2da58d 100644
--- a/Emby.Dlna/PlayTo/uBaseObject.cs
+++ b/Emby.Dlna/PlayTo/uBaseObject.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/Emby.Dlna/Server/DescriptionXmlBuilder.cs b/Emby.Dlna/Server/DescriptionXmlBuilder.cs
index 09525aae4..3f3dfccd3 100644
--- a/Emby.Dlna/Server/DescriptionXmlBuilder.cs
+++ b/Emby.Dlna/Server/DescriptionXmlBuilder.cs
@@ -250,7 +250,8 @@ namespace Emby.Dlna.Server
url = _serverAddress.TrimEnd('/') + "/dlna/" + _serverUdn + "/" + url.TrimStart('/');
- return SecurityElement.Escape(url);
+ // TODO: @bond remove null-coalescing operator when https://github.com/dotnet/runtime/pull/52442 is merged/released
+ return SecurityElement.Escape(url) ?? string.Empty;
}
private IEnumerable<DeviceIcon> GetIcons()
diff --git a/Emby.Dlna/Service/BaseControlHandler.cs b/Emby.Dlna/Service/BaseControlHandler.cs
index fda8346f9..904c23d99 100644
--- a/Emby.Dlna/Service/BaseControlHandler.cs
+++ b/Emby.Dlna/Service/BaseControlHandler.cs
@@ -47,7 +47,7 @@ namespace Emby.Dlna.Service
private async Task<ControlResponse> ProcessControlRequestInternalAsync(ControlRequest request)
{
- ControlRequestInfo requestInfo = null;
+ ControlRequestInfo? requestInfo = null;
using (var streamReader = new StreamReader(request.InputXml, Encoding.UTF8))
{
@@ -151,7 +151,7 @@ namespace Emby.Dlna.Service
private async Task<ControlRequestInfo> ParseBodyTagAsync(XmlReader reader)
{
- string namespaceURI = null, localName = null;
+ string? namespaceURI = null, localName = null;
await reader.MoveToContentAsync().ConfigureAwait(false);
await reader.ReadAsync().ConfigureAwait(false);
diff --git a/Emby.Dlna/Ssdp/DeviceDiscovery.cs b/Emby.Dlna/Ssdp/DeviceDiscovery.cs
index d9c6a93c7..391dda147 100644
--- a/Emby.Dlna/Ssdp/DeviceDiscovery.cs
+++ b/Emby.Dlna/Ssdp/DeviceDiscovery.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/Emby.Dlna/Ssdp/SsdpExtensions.cs b/Emby.Dlna/Ssdp/SsdpExtensions.cs
index e7a52f168..d00eb02b4 100644
--- a/Emby.Dlna/Ssdp/SsdpExtensions.cs
+++ b/Emby.Dlna/Ssdp/SsdpExtensions.cs
@@ -7,21 +7,21 @@ namespace Emby.Dlna.Ssdp
{
public static class SsdpExtensions
{
- public static string GetValue(this XElement container, XName name)
+ public static string? GetValue(this XElement container, XName name)
{
var node = container.Element(name);
return node?.Value;
}
- public static string GetAttributeValue(this XElement container, XName name)
+ public static string? GetAttributeValue(this XElement container, XName name)
{
var node = container.Attribute(name);
return node?.Value;
}
- public static string GetDescendantValue(this XElement container, XName name)
+ public static string? GetDescendantValue(this XElement container, XName name)
=> container.Descendants(name).FirstOrDefault()?.Value;
}
}
diff --git a/Emby.Naming/TV/EpisodeResolver.cs b/Emby.Naming/TV/EpisodeResolver.cs
index f7df58786..c63aec64e 100644
--- a/Emby.Naming/TV/EpisodeResolver.cs
+++ b/Emby.Naming/TV/EpisodeResolver.cs
@@ -68,6 +68,11 @@ namespace Emby.Naming.TV
var parsingResult = new EpisodePathParser(_options)
.Parse(path, isDirectory, isNamed, isOptimistic, supportsAbsoluteNumbers, fillExtendedInfo);
+ if (!parsingResult.Success && !isStub)
+ {
+ return null;
+ }
+
return new EpisodeInfo(path)
{
Container = container,
diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs
index 703f8d20d..75d8fc113 100644
--- a/Emby.Server.Implementations/ApplicationHost.cs
+++ b/Emby.Server.Implementations/ApplicationHost.cs
@@ -335,10 +335,7 @@ namespace Emby.Server.Implementations
{
get
{
- if (_deviceId == null)
- {
- _deviceId = new DeviceId(ApplicationPaths, LoggerFactory);
- }
+ _deviceId ??= new DeviceId(ApplicationPaths, LoggerFactory);
return _deviceId.Value;
}
@@ -370,10 +367,7 @@ namespace Emby.Server.Implementations
/// <returns>System.Object.</returns>
protected object CreateInstanceSafe(Type type)
{
- if (_creatingInstances == null)
- {
- _creatingInstances = new List<Type>();
- }
+ _creatingInstances ??= new List<Type>();
if (_creatingInstances.IndexOf(type) != -1)
{
diff --git a/Emby.Server.Implementations/Collections/CollectionManager.cs b/Emby.Server.Implementations/Collections/CollectionManager.cs
index 1b85a9d4b..c56f33448 100644
--- a/Emby.Server.Implementations/Collections/CollectionManager.cs
+++ b/Emby.Server.Implementations/Collections/CollectionManager.cs
@@ -164,7 +164,7 @@ namespace Emby.Server.Implementations.Collections
parentFolder.AddChild(collection, CancellationToken.None);
- if (options.ItemIdList.Length > 0)
+ if (options.ItemIdList.Count > 0)
{
await AddToCollectionAsync(
collection.Id,
@@ -248,11 +248,7 @@ namespace Emby.Server.Implementations.Collections
if (fireEvent)
{
- ItemsAddedToCollection?.Invoke(this, new CollectionModifiedEventArgs
- {
- Collection = collection,
- ItemsChanged = itemList
- });
+ ItemsAddedToCollection?.Invoke(this, new CollectionModifiedEventArgs(collection, itemList));
}
}
}
@@ -304,11 +300,7 @@ namespace Emby.Server.Implementations.Collections
},
RefreshPriority.High);
- ItemsRemovedFromCollection?.Invoke(this, new CollectionModifiedEventArgs
- {
- Collection = collection,
- ItemsChanged = itemList
- });
+ ItemsRemovedFromCollection?.Invoke(this, new CollectionModifiedEventArgs(collection, itemList));
}
/// <inheritdoc />
diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs
index a9815ae36..835eb0692 100644
--- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs
+++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs
@@ -1,6 +1,7 @@
#pragma warning disable CS1591
using System;
+using System.Buffers.Text;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
@@ -502,7 +503,7 @@ namespace Emby.Server.Implementations.Data
using (var saveImagesStatement = base.PrepareStatement(db, "Update TypedBaseItems set Images=@Images where guid=@Id"))
{
saveImagesStatement.TryBind("@Id", item.Id.ToByteArray());
- saveImagesStatement.TryBind("@Images", SerializeImages(item));
+ saveImagesStatement.TryBind("@Images", SerializeImages(item.ImageInfos));
saveImagesStatement.MoveNext();
}
@@ -897,8 +898,8 @@ namespace Emby.Server.Implementations.Data
saveItemStatement.TryBind("@ExternalSeriesId", item.ExternalSeriesId);
saveItemStatement.TryBind("@Tagline", item.Tagline);
- saveItemStatement.TryBind("@ProviderIds", SerializeProviderIds(item));
- saveItemStatement.TryBind("@Images", SerializeImages(item));
+ saveItemStatement.TryBind("@ProviderIds", SerializeProviderIds(item.ProviderIds));
+ saveItemStatement.TryBind("@Images", SerializeImages(item.ImageInfos));
if (item.ProductionLocations.Length > 0)
{
@@ -968,10 +969,10 @@ namespace Emby.Server.Implementations.Data
saveItemStatement.MoveNext();
}
- private static string SerializeProviderIds(BaseItem item)
+ internal static string SerializeProviderIds(Dictionary<string, string> providerIds)
{
StringBuilder str = new StringBuilder();
- foreach (var i in item.ProviderIds)
+ foreach (var i in providerIds)
{
// Ideally we shouldn't need this IsNullOrWhiteSpace check,
// but we're seeing some cases of bad data slip through
@@ -995,35 +996,25 @@ namespace Emby.Server.Implementations.Data
return str.ToString();
}
- private static void DeserializeProviderIds(string value, BaseItem item)
+ internal static void DeserializeProviderIds(string value, IHasProviderIds item)
{
if (string.IsNullOrWhiteSpace(value))
{
return;
}
- if (item.ProviderIds.Count > 0)
+ foreach (var part in value.SpanSplit('|'))
{
- return;
- }
-
- var parts = value.Split('|', StringSplitOptions.RemoveEmptyEntries);
-
- foreach (var part in parts)
- {
- var idParts = part.Split('=');
-
- if (idParts.Length == 2)
+ var providerDelimiterIndex = part.IndexOf('=');
+ if (providerDelimiterIndex != -1 && providerDelimiterIndex == part.LastIndexOf('='))
{
- item.SetProviderId(idParts[0], idParts[1]);
+ item.SetProviderId(part.Slice(0, providerDelimiterIndex).ToString(), part.Slice(providerDelimiterIndex + 1).ToString());
}
}
}
- private string SerializeImages(BaseItem item)
+ internal string SerializeImages(ItemImageInfo[] images)
{
- var images = item.ImageInfos;
-
if (images.Length == 0)
{
return null;
@@ -1045,21 +1036,15 @@ namespace Emby.Server.Implementations.Data
return str.ToString();
}
- private void DeserializeImages(string value, BaseItem item)
+ internal ItemImageInfo[] DeserializeImages(string value)
{
if (string.IsNullOrWhiteSpace(value))
{
- return;
- }
-
- if (item.ImageInfos.Length > 0)
- {
- return;
+ return Array.Empty<ItemImageInfo>();
}
- var parts = value.Split('|' , StringSplitOptions.RemoveEmptyEntries);
var list = new List<ItemImageInfo>();
- foreach (var part in parts)
+ foreach (var part in value.SpanSplit('|'))
{
var image = ItemImageInfoFromValueString(part);
@@ -1069,15 +1054,14 @@ namespace Emby.Server.Implementations.Data
}
}
- item.ImageInfos = list.ToArray();
+ return list.ToArray();
}
- public void AppendItemImageInfo(StringBuilder bldr, ItemImageInfo image)
+ private void AppendItemImageInfo(StringBuilder bldr, ItemImageInfo image)
{
const char Delimiter = '*';
var path = image.Path ?? string.Empty;
- var hash = image.BlurHash ?? string.Empty;
bldr.Append(GetPathToSave(path))
.Append(Delimiter)
@@ -1087,48 +1071,105 @@ namespace Emby.Server.Implementations.Data
.Append(Delimiter)
.Append(image.Width)
.Append(Delimiter)
- .Append(image.Height)
- .Append(Delimiter)
- // Replace delimiters with other characters.
- // This can be removed when we migrate to a proper DB.
- .Append(hash.Replace('*', '/').Replace('|', '\\'));
+ .Append(image.Height);
+
+ var hash = image.BlurHash;
+ if (!string.IsNullOrEmpty(hash))
+ {
+ bldr.Append(Delimiter)
+ // Replace delimiters with other characters.
+ // This can be removed when we migrate to a proper DB.
+ .Append(hash.Replace('*', '/').Replace('|', '\\'));
+ }
}
- public ItemImageInfo ItemImageInfoFromValueString(string value)
+ internal ItemImageInfo ItemImageInfoFromValueString(ReadOnlySpan<char> value)
{
- var parts = value.Split('*', StringSplitOptions.None);
+ var nextSegment = value.IndexOf('*');
+ if (nextSegment == -1)
+ {
+ return null;
+ }
- if (parts.Length < 3)
+ ReadOnlySpan<char> path = value[..nextSegment];
+ value = value[(nextSegment + 1)..];
+ nextSegment = value.IndexOf('*');
+ if (nextSegment == -1)
{
return null;
}
- var image = new ItemImageInfo();
+ ReadOnlySpan<char> dateModified = value[..nextSegment];
+ value = value[(nextSegment + 1)..];
+ nextSegment = value.IndexOf('*');
+ if (nextSegment == -1)
+ {
+ nextSegment = value.Length;
+ }
+
+ ReadOnlySpan<char> imageType = value[..nextSegment];
- image.Path = RestorePath(parts[0]);
+ var image = new ItemImageInfo
+ {
+ Path = RestorePath(path.ToString())
+ };
- if (long.TryParse(parts[1], NumberStyles.Any, CultureInfo.InvariantCulture, out var ticks))
+ if (long.TryParse(dateModified, NumberStyles.Any, CultureInfo.InvariantCulture, out var ticks))
{
image.DateModified = new DateTime(ticks, DateTimeKind.Utc);
}
- if (Enum.TryParse(parts[2], true, out ImageType type))
+ if (Enum.TryParse(imageType.ToString(), true, out ImageType type))
{
image.Type = type;
}
- if (parts.Length >= 5)
+ // Optional parameters: width*height*blurhash
+ if (nextSegment + 1 < value.Length - 1)
{
- if (int.TryParse(parts[3], NumberStyles.Integer, CultureInfo.InvariantCulture, out var width)
- && int.TryParse(parts[4], NumberStyles.Integer, CultureInfo.InvariantCulture, out var height))
+ value = value[(nextSegment + 1)..];
+ nextSegment = value.IndexOf('*');
+ if (nextSegment == -1 || nextSegment == value.Length)
+ {
+ return image;
+ }
+
+ ReadOnlySpan<char> widthSpan = value[..nextSegment];
+
+ value = value[(nextSegment + 1)..];
+ nextSegment = value.IndexOf('*');
+ if (nextSegment == -1)
+ {
+ nextSegment = value.Length;
+ }
+
+ ReadOnlySpan<char> heightSpan = value[..nextSegment];
+
+ if (int.TryParse(widthSpan, NumberStyles.Integer, CultureInfo.InvariantCulture, out var width)
+ && int.TryParse(heightSpan, NumberStyles.Integer, CultureInfo.InvariantCulture, out var height))
{
image.Width = width;
image.Height = height;
}
- if (parts.Length >= 6)
+ if (nextSegment < value.Length - 1)
{
- image.BlurHash = parts[5].Replace('/', '*').Replace('\\', '|');
+ value = value[(nextSegment + 1)..];
+ var length = value.Length;
+
+ Span<char> blurHashSpan = stackalloc char[length];
+ for (int i = 0; i < length; i++)
+ {
+ var c = value[i];
+ blurHashSpan[i] = c switch
+ {
+ '/' => '*',
+ '\\' => '|',
+ _ => c
+ };
+ }
+
+ image.BlurHash = new string(blurHashSpan);
}
}
@@ -1311,7 +1352,14 @@ namespace Emby.Server.Implementations.Data
if (!reader.IsDBNull(index))
{
- item.ChannelId = new Guid(reader.GetString(index));
+ if (!Utf8Parser.TryParse(reader[index].ToBlob(), out Guid value, out _, standardFormat: 'N'))
+ {
+ var str = reader.GetString(index);
+ Logger.LogWarning("{ChannelId} isn't in the expected format", str);
+ value = new Guid(str);
+ }
+
+ item.ChannelId = value;
}
index++;
@@ -1790,7 +1838,7 @@ namespace Emby.Server.Implementations.Data
index++;
}
- if (!reader.IsDBNull(index))
+ if (item.ProviderIds.Count == 0 && !reader.IsDBNull(index))
{
DeserializeProviderIds(reader.GetString(index), item);
}
@@ -1799,9 +1847,9 @@ namespace Emby.Server.Implementations.Data
if (query.DtoOptions.EnableImages)
{
- if (!reader.IsDBNull(index))
+ if (item.ImageInfos.Length == 0 && !reader.IsDBNull(index))
{
- DeserializeImages(reader.GetString(index), item);
+ item.ImageInfos = DeserializeImages(reader.GetString(index));
}
index++;
@@ -2116,30 +2164,7 @@ namespace Emby.Server.Implementations.Data
|| query.IsLiked.HasValue;
}
- private readonly ItemFields[] _allFields = Enum.GetNames(typeof(ItemFields))
- .Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true))
- .ToArray();
-
- private string[] GetColumnNamesFromField(ItemFields field)
- {
- switch (field)
- {
- case ItemFields.Settings:
- return new[] { "IsLocked", "PreferredMetadataCountryCode", "PreferredMetadataLanguage", "LockedFields" };
- case ItemFields.ServiceName:
- return new[] { "ExternalServiceId" };
- case ItemFields.SortName:
- return new[] { "ForcedSortName" };
- case ItemFields.Taglines:
- return new[] { "Tagline" };
- case ItemFields.Tags:
- return new[] { "Tags" };
- case ItemFields.IsHD:
- return Array.Empty<string>();
- default:
- return new[] { field.ToString() };
- }
- }
+ private readonly ItemFields[] _allFields = Enum.GetValues<ItemFields>();
private bool HasField(InternalItemsQuery query, ItemFields name)
{
@@ -2329,9 +2354,32 @@ namespace Emby.Server.Implementations.Data
{
if (!HasField(query, field))
{
- foreach (var fieldToRemove in GetColumnNamesFromField(field))
+ switch (field)
{
- list.Remove(fieldToRemove);
+ case ItemFields.Settings:
+ list.Remove("IsLocked");
+ list.Remove("PreferredMetadataCountryCode");
+ list.Remove("PreferredMetadataLanguage");
+ list.Remove("LockedFields");
+ break;
+ case ItemFields.ServiceName:
+ list.Remove("ExternalServiceId");
+ break;
+ case ItemFields.SortName:
+ list.Remove("ForcedSortName");
+ break;
+ case ItemFields.Taglines:
+ list.Remove("Tagline");
+ break;
+ case ItemFields.Tags:
+ list.Remove("Tags");
+ break;
+ case ItemFields.IsHD:
+ // do nothing
+ break;
+ default:
+ list.Remove(field.ToString());
+ break;
}
}
}
@@ -2578,9 +2626,9 @@ namespace Emby.Server.Implementations.Data
}
var commandText = "select "
- + string.Join(',', GetFinalColumnsToSelect(query, new[] { "count(distinct PresentationUniqueKey)" }))
- + GetFromText()
- + GetJoinUserDataText(query);
+ + string.Join(',', GetFinalColumnsToSelect(query, new[] { "count(distinct PresentationUniqueKey)" }))
+ + GetFromText()
+ + GetJoinUserDataText(query);
var whereClauses = GetWhereClauses(query, null);
if (whereClauses.Count != 0)
@@ -2721,87 +2769,22 @@ namespace Emby.Server.Implementations.Data
private string FixUnicodeChars(string buffer)
{
- if (buffer.IndexOf('\u2013', StringComparison.Ordinal) > -1)
- {
- buffer = buffer.Replace('\u2013', '-'); // en dash
- }
-
- if (buffer.IndexOf('\u2014', StringComparison.Ordinal) > -1)
- {
- buffer = buffer.Replace('\u2014', '-'); // em dash
- }
-
- if (buffer.IndexOf('\u2015', StringComparison.Ordinal) > -1)
- {
- buffer = buffer.Replace('\u2015', '-'); // horizontal bar
- }
-
- if (buffer.IndexOf('\u2017', StringComparison.Ordinal) > -1)
- {
- buffer = buffer.Replace('\u2017', '_'); // double low line
- }
-
- if (buffer.IndexOf('\u2018', StringComparison.Ordinal) > -1)
- {
- buffer = buffer.Replace('\u2018', '\''); // left single quotation mark
- }
-
- if (buffer.IndexOf('\u2019', StringComparison.Ordinal) > -1)
- {
- buffer = buffer.Replace('\u2019', '\''); // right single quotation mark
- }
-
- if (buffer.IndexOf('\u201a', StringComparison.Ordinal) > -1)
- {
- buffer = buffer.Replace('\u201a', ','); // single low-9 quotation mark
- }
-
- if (buffer.IndexOf('\u201b', StringComparison.Ordinal) > -1)
- {
- buffer = buffer.Replace('\u201b', '\''); // single high-reversed-9 quotation mark
- }
-
- if (buffer.IndexOf('\u201c', StringComparison.Ordinal) > -1)
- {
- buffer = buffer.Replace('\u201c', '\"'); // left double quotation mark
- }
-
- if (buffer.IndexOf('\u201d', StringComparison.Ordinal) > -1)
- {
- buffer = buffer.Replace('\u201d', '\"'); // right double quotation mark
- }
-
- if (buffer.IndexOf('\u201e', StringComparison.Ordinal) > -1)
- {
- buffer = buffer.Replace('\u201e', '\"'); // double low-9 quotation mark
- }
-
- if (buffer.IndexOf('\u2026', StringComparison.Ordinal) > -1)
- {
- buffer = buffer.Replace("\u2026", "...", StringComparison.Ordinal); // horizontal ellipsis
- }
-
- if (buffer.IndexOf('\u2032', StringComparison.Ordinal) > -1)
- {
- buffer = buffer.Replace('\u2032', '\''); // prime
- }
-
- if (buffer.IndexOf('\u2033', StringComparison.Ordinal) > -1)
- {
- buffer = buffer.Replace('\u2033', '\"'); // double prime
- }
-
- if (buffer.IndexOf('\u0060', StringComparison.Ordinal) > -1)
- {
- buffer = buffer.Replace('\u0060', '\''); // grave accent
- }
-
- if (buffer.IndexOf('\u00B4', StringComparison.Ordinal) > -1)
- {
- buffer = buffer.Replace('\u00B4', '\''); // acute accent
- }
-
- return buffer;
+ buffer = buffer.Replace('\u2013', '-'); // en dash
+ buffer = buffer.Replace('\u2014', '-'); // em dash
+ buffer = buffer.Replace('\u2015', '-'); // horizontal bar
+ buffer = buffer.Replace('\u2017', '_'); // double low line
+ buffer = buffer.Replace('\u2018', '\''); // left single quotation mark
+ buffer = buffer.Replace('\u2019', '\''); // right single quotation mark
+ buffer = buffer.Replace('\u201a', ','); // single low-9 quotation mark
+ buffer = buffer.Replace('\u201b', '\''); // single high-reversed-9 quotation mark
+ buffer = buffer.Replace('\u201c', '\"'); // left double quotation mark
+ buffer = buffer.Replace('\u201d', '\"'); // right double quotation mark
+ buffer = buffer.Replace('\u201e', '\"'); // double low-9 quotation mark
+ buffer = buffer.Replace("\u2026", "...", StringComparison.Ordinal); // horizontal ellipsis
+ buffer = buffer.Replace('\u2032', '\''); // prime
+ buffer = buffer.Replace('\u2033', '\"'); // double prime
+ buffer = buffer.Replace('\u0060', '\''); // grave accent
+ return buffer.Replace('\u00B4', '\''); // acute accent
}
private void AddItem(List<BaseItem> items, BaseItem newItem)
@@ -3584,11 +3567,11 @@ namespace Emby.Server.Implementations.Data
statement?.TryBind("@IsFolder", query.IsFolder);
}
- var includeTypes = query.IncludeItemTypes.SelectMany(MapIncludeItemTypes).ToArray();
+ var includeTypes = query.IncludeItemTypes.Select(MapIncludeItemTypes).Where(x => x != null).ToArray();
// Only specify excluded types if no included types are specified
if (includeTypes.Length == 0)
{
- var excludeTypes = query.ExcludeItemTypes.SelectMany(MapIncludeItemTypes).ToArray();
+ var excludeTypes = query.ExcludeItemTypes.Select(MapIncludeItemTypes).Where(x => x != null).ToArray();
if (excludeTypes.Length == 1)
{
whereClauses.Add("type<>@type");
@@ -4532,7 +4515,7 @@ namespace Emby.Server.Implementations.Data
whereClauses.Add(GetProviderIdClause(query.HasTvdbId.Value, "tvdb"));
}
- var includedItemByNameTypes = GetItemByNameTypesInQuery(query).SelectMany(MapIncludeItemTypes).ToList();
+ var includedItemByNameTypes = GetItemByNameTypesInQuery(query);
var enableItemsByName = (query.IncludeItemsByName ?? false) && includedItemByNameTypes.Count > 0;
var queryTopParentIds = query.TopParentIds;
@@ -4790,27 +4773,27 @@ namespace Emby.Server.Implementations.Data
if (IsTypeInQuery(nameof(Person), query))
{
- list.Add(nameof(Person));
+ list.Add(typeof(Person).FullName);
}
if (IsTypeInQuery(nameof(Genre), query))
{
- list.Add(nameof(Genre));
+ list.Add(typeof(Genre).FullName);
}
if (IsTypeInQuery(nameof(MusicGenre), query))
{
- list.Add(nameof(MusicGenre));
+ list.Add(typeof(MusicGenre).FullName);
}
if (IsTypeInQuery(nameof(MusicArtist), query))
{
- list.Add(nameof(MusicArtist));
+ list.Add(typeof(MusicArtist).FullName);
}
if (IsTypeInQuery(nameof(Studio), query))
{
- list.Add(nameof(Studio));
+ list.Add(typeof(Studio).FullName);
}
return list;
@@ -4915,15 +4898,10 @@ namespace Emby.Server.Implementations.Data
typeof(AggregateFolder)
};
- public void UpdateInheritedValues(CancellationToken cancellationToken)
- {
- UpdateInheritedTags(cancellationToken);
- }
-
- private void UpdateInheritedTags(CancellationToken cancellationToken)
+ public void UpdateInheritedValues()
{
string sql = string.Join(
- ";",
+ ';',
new string[]
{
"delete from itemvalues where type = 6",
@@ -4946,37 +4924,38 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
}
}
- private static Dictionary<string, string[]> GetTypeMapDictionary()
+ private static Dictionary<string, string> GetTypeMapDictionary()
{
- var dict = new Dictionary<string, string[]>(StringComparer.OrdinalIgnoreCase);
+ var dict = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
foreach (var t in _knownTypes)
{
- dict[t.Name] = new[] { t.FullName };
+ dict[t.Name] = t.FullName ;
}
- dict["Program"] = new[] { typeof(LiveTvProgram).FullName };
- dict["TvChannel"] = new[] { typeof(LiveTvChannel).FullName };
+ dict["Program"] = typeof(LiveTvProgram).FullName;
+ dict["TvChannel"] = typeof(LiveTvChannel).FullName;
return dict;
}
// Not crazy about having this all the way down here, but at least it's in one place
- private readonly Dictionary<string, string[]> _types = GetTypeMapDictionary();
+ private readonly Dictionary<string, string> _types = GetTypeMapDictionary();
- private string[] MapIncludeItemTypes(string value)
+ private string MapIncludeItemTypes(string value)
{
- if (_types.TryGetValue(value, out string[] result))
+ if (_types.TryGetValue(value, out string result))
{
return result;
}
if (IsValidType(value))
{
- return new[] { value };
+ return value;
}
- return Array.Empty<string>();
+ Logger.LogWarning("Unknown item type: {ItemType}", value);
+ return null;
}
public void DeleteItem(Guid id)
@@ -5279,31 +5258,46 @@ AND Type = @InternalPersonType)");
public List<string> GetStudioNames()
{
- return GetItemValueNames(new[] { 3 }, new List<string>(), new List<string>());
+ return GetItemValueNames(new[] { 3 }, Array.Empty<string>(), Array.Empty<string>());
}
public List<string> GetAllArtistNames()
{
- return GetItemValueNames(new[] { 0, 1 }, new List<string>(), new List<string>());
+ return GetItemValueNames(new[] { 0, 1 }, Array.Empty<string>(), Array.Empty<string>());
}
public List<string> GetMusicGenreNames()
{
- return GetItemValueNames(new[] { 2 }, new List<string> { "Audio", "MusicVideo", "MusicAlbum", "MusicArtist" }, new List<string>());
+ return GetItemValueNames(
+ new[] { 2 },
+ new string[]
+ {
+ typeof(Audio).FullName,
+ typeof(MusicVideo).FullName,
+ typeof(MusicAlbum).FullName,
+ typeof(MusicArtist).FullName
+ },
+ Array.Empty<string>());
}
public List<string> GetGenreNames()
{
- return GetItemValueNames(new[] { 2 }, new List<string>(), new List<string> { "Audio", "MusicVideo", "MusicAlbum", "MusicArtist" });
+ return GetItemValueNames(
+ new[] { 2 },
+ Array.Empty<string>(),
+ new string[]
+ {
+ typeof(Audio).FullName,
+ typeof(MusicVideo).FullName,
+ typeof(MusicAlbum).FullName,
+ typeof(MusicArtist).FullName
+ });
}
- private List<string> GetItemValueNames(int[] itemValueTypes, List<string> withItemTypes, List<string> excludeItemTypes)
+ private List<string> GetItemValueNames(int[] itemValueTypes, IReadOnlyList<string> withItemTypes, IReadOnlyList<string> excludeItemTypes)
{
CheckDisposed();
- withItemTypes = withItemTypes.SelectMany(MapIncludeItemTypes).ToList();
- excludeItemTypes = excludeItemTypes.SelectMany(MapIncludeItemTypes).ToList();
-
var now = DateTime.UtcNow;
var typeClause = itemValueTypes.Length == 1 ?
@@ -5811,7 +5805,10 @@ AND Type = @InternalPersonType)");
var endIndex = Math.Min(people.Count, startIndex + Limit);
for (var i = startIndex; i < endIndex; i++)
{
- insertText.AppendFormat("(@ItemId, @Name{0}, @Role{0}, @PersonType{0}, @SortOrder{0}, @ListOrder{0}),", i.ToString(CultureInfo.InvariantCulture));
+ insertText.AppendFormat(
+ CultureInfo.InvariantCulture,
+ "(@ItemId, @Name{0}, @Role{0}, @PersonType{0}, @SortOrder{0}, @ListOrder{0}),",
+ i.ToString(CultureInfo.InvariantCulture));
}
// Remove last comma
@@ -6263,7 +6260,7 @@ AND Type = @InternalPersonType)");
CheckDisposed();
if (id == Guid.Empty)
{
- throw new ArgumentException(nameof(id));
+ throw new ArgumentException("Guid can't be empty.", nameof(id));
}
if (attachments == null)
diff --git a/Emby.Server.Implementations/Dto/DtoService.cs b/Emby.Server.Implementations/Dto/DtoService.cs
index 54b18a8c8..4ae35039a 100644
--- a/Emby.Server.Implementations/Dto/DtoService.cs
+++ b/Emby.Server.Implementations/Dto/DtoService.cs
@@ -665,10 +665,7 @@ namespace Emby.Server.Implementations.Dto
var tag = GetImageCacheTag(item, image);
if (!string.IsNullOrEmpty(image.BlurHash))
{
- if (dto.ImageBlurHashes == null)
- {
- dto.ImageBlurHashes = new Dictionary<ImageType, Dictionary<string, string>>();
- }
+ dto.ImageBlurHashes ??= new Dictionary<ImageType, Dictionary<string, string>>();
if (!dto.ImageBlurHashes.ContainsKey(image.Type))
{
@@ -702,10 +699,7 @@ namespace Emby.Server.Implementations.Dto
if (hashes.Count > 0)
{
- if (dto.ImageBlurHashes == null)
- {
- dto.ImageBlurHashes = new Dictionary<ImageType, Dictionary<string, string>>();
- }
+ dto.ImageBlurHashes ??= new Dictionary<ImageType, Dictionary<string, string>>();
dto.ImageBlurHashes[imageType] = hashes;
}
@@ -898,10 +892,7 @@ namespace Emby.Server.Implementations.Dto
dto.Taglines = new string[] { item.Tagline };
}
- if (dto.Taglines == null)
- {
- dto.Taglines = Array.Empty<string>();
- }
+ dto.Taglines ??= Array.Empty<string>();
}
dto.Type = item.GetBaseItemKind();
diff --git a/Emby.Server.Implementations/Emby.Server.Implementations.csproj b/Emby.Server.Implementations/Emby.Server.Implementations.csproj
index adbfe52c4..8ea98f454 100644
--- a/Emby.Server.Implementations/Emby.Server.Implementations.csproj
+++ b/Emby.Server.Implementations/Emby.Server.Implementations.csproj
@@ -29,9 +29,9 @@
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="5.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="5.0.3" />
<PackageReference Include="Mono.Nat" Version="3.0.1" />
- <PackageReference Include="prometheus-net.DotNetRuntime" Version="4.0.0" />
+ <PackageReference Include="prometheus-net.DotNetRuntime" Version="4.1.0" />
<PackageReference Include="sharpcompress" Version="0.28.2" />
- <PackageReference Include="SQLitePCL.pretty.netstandard" Version="2.1.0" />
+ <PackageReference Include="SQLitePCL.pretty.netstandard" Version="2.2.0" />
<PackageReference Include="DotNet.Glob" Version="3.1.2" />
</ItemGroup>
diff --git a/Emby.Server.Implementations/IO/ManagedFileSystem.cs b/Emby.Server.Implementations/IO/ManagedFileSystem.cs
index 3893a1577..27096ed33 100644
--- a/Emby.Server.Implementations/IO/ManagedFileSystem.cs
+++ b/Emby.Server.Implementations/IO/ManagedFileSystem.cs
@@ -2,11 +2,10 @@
using System;
using System.Collections.Generic;
-using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
-using System.Text;
+using System.Runtime.InteropServices;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.System;
@@ -24,7 +23,7 @@ namespace Emby.Server.Implementations.IO
private readonly List<IShortcutHandler> _shortcutHandlers = new List<IShortcutHandler>();
private readonly string _tempPath;
- private readonly bool _isEnvironmentCaseInsensitive;
+ private static readonly bool _isEnvironmentCaseInsensitive = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
public ManagedFileSystem(
ILogger<ManagedFileSystem> logger,
@@ -32,8 +31,6 @@ namespace Emby.Server.Implementations.IO
{
Logger = logger;
_tempPath = applicationPaths.TempDirectory;
-
- _isEnvironmentCaseInsensitive = OperatingSystem.Id == OperatingSystemId.Windows;
}
public virtual void AddShortcutHandler(IShortcutHandler handler)
@@ -55,7 +52,7 @@ namespace Emby.Server.Implementations.IO
}
var extension = Path.GetExtension(filename);
- return _shortcutHandlers.Any(i => string.Equals(extension, i.Extension, _isEnvironmentCaseInsensitive ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal));
+ return _shortcutHandlers.Any(i => string.Equals(extension, i.Extension, StringComparison.OrdinalIgnoreCase));
}
/// <summary>
@@ -72,7 +69,7 @@ namespace Emby.Server.Implementations.IO
}
var extension = Path.GetExtension(filename);
- var handler = _shortcutHandlers.FirstOrDefault(i => string.Equals(extension, i.Extension, StringComparison.OrdinalIgnoreCase));
+ var handler = _shortcutHandlers.Find(i => string.Equals(extension, i.Extension, StringComparison.OrdinalIgnoreCase));
return handler?.Resolve(filename);
}
@@ -263,8 +260,6 @@ namespace Emby.Server.Implementations.IO
result.Exists = false;
}
}
-
- result.DirectoryName = fileInfo.DirectoryName;
}
result.CreationTimeUtc = GetCreationTimeUtc(info);
@@ -303,16 +298,37 @@ namespace Emby.Server.Implementations.IO
/// <param name="filename">The filename.</param>
/// <returns>System.String.</returns>
/// <exception cref="ArgumentNullException">The filename is null.</exception>
- public virtual string GetValidFilename(string filename)
+ public string GetValidFilename(string filename)
{
- var builder = new StringBuilder(filename);
-
- foreach (var c in Path.GetInvalidFileNameChars())
+ var invalid = Path.GetInvalidFileNameChars();
+ var first = filename.IndexOfAny(invalid);
+ if (first == -1)
{
- builder = builder.Replace(c, ' ');
+ // Fast path for clean strings
+ return filename;
}
- return builder.ToString();
+ return string.Create(
+ filename.Length,
+ (filename, invalid, first),
+ (chars, state) =>
+ {
+ state.filename.AsSpan().CopyTo(chars);
+
+ chars[state.first++] = ' ';
+
+ var len = chars.Length;
+ foreach (var c in state.invalid)
+ {
+ for (int i = state.first; i < len; i++)
+ {
+ if (chars[i] == c)
+ {
+ chars[i] = ' ';
+ }
+ }
+ }
+ });
}
/// <summary>
@@ -684,20 +700,5 @@ namespace Emby.Server.Implementations.IO
AttributesToSkip = 0
};
}
-
- private static void RunProcess(string path, string args, string workingDirectory)
- {
- using (var process = Process.Start(new ProcessStartInfo
- {
- Arguments = args,
- FileName = path,
- CreateNoWindow = true,
- WorkingDirectory = workingDirectory,
- WindowStyle = ProcessWindowStyle.Normal
- }))
- {
- process.WaitForExit();
- }
- }
}
}
diff --git a/Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs b/Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs
index 5f7e51858..6fa3c1c61 100644
--- a/Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs
+++ b/Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs
@@ -191,7 +191,7 @@ namespace Emby.Server.Implementations.Images
InputPaths = GetStripCollageImagePaths(primaryItem, items).ToArray()
};
- if (options.InputPaths.Length == 0)
+ if (options.InputPaths.Count == 0)
{
return null;
}
diff --git a/Emby.Server.Implementations/Images/PlaylistImageProvider.cs b/Emby.Server.Implementations/Images/PlaylistImageProvider.cs
index 0ce1b91e8..a4c106e87 100644
--- a/Emby.Server.Implementations/Images/PlaylistImageProvider.cs
+++ b/Emby.Server.Implementations/Images/PlaylistImageProvider.cs
@@ -29,9 +29,7 @@ namespace Emby.Server.Implementations.Images
{
var subItem = i.Item2;
- var episode = subItem as Episode;
-
- if (episode != null)
+ if (subItem is Episode episode)
{
var series = episode.Series;
if (series != null && series.HasImage(ImageType.Primary))
diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs
index 7d030418a..4d207471a 100644
--- a/Emby.Server.Implementations/Library/LibraryManager.cs
+++ b/Emby.Server.Implementations/Library/LibraryManager.cs
@@ -48,6 +48,7 @@ using MediaBrowser.Providers.MediaInfo;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Logging;
using Episode = MediaBrowser.Controller.Entities.TV.Episode;
+using EpisodeInfo = Emby.Naming.TV.EpisodeInfo;
using Genre = MediaBrowser.Controller.Entities.Genre;
using Person = MediaBrowser.Controller.Entities.Person;
using VideoResolver = Emby.Naming.Video.VideoResolver;
@@ -175,10 +176,7 @@ namespace Emby.Server.Implementations.Library
{
lock (_rootFolderSyncLock)
{
- if (_rootFolder == null)
- {
- _rootFolder = CreateRootFolder();
- }
+ _rootFolder ??= CreateRootFolder();
}
}
@@ -558,7 +556,6 @@ namespace Emby.Server.Implementations.Library
var args = new ItemResolveArgs(_configurationManager.ApplicationPaths, directoryService)
{
Parent = parent,
- Path = fullPath,
FileInfo = fileInfo,
CollectionType = collectionType,
LibraryOptions = libraryOptions
@@ -684,7 +681,7 @@ namespace Emby.Server.Implementations.Library
foreach (var item in items)
{
- ResolverHelper.SetInitialItemValues(item, parent, _fileSystem, this, directoryService);
+ ResolverHelper.SetInitialItemValues(item, parent, this, directoryService);
}
items.AddRange(ResolveFileList(result.ExtraFiles, directoryService, parent, collectionType, resolvers, libraryOptions));
@@ -1163,7 +1160,7 @@ namespace Emby.Server.Implementations.Library
progress.Report(percent * 100);
}
- _itemRepository.UpdateInheritedValues(cancellationToken);
+ _itemRepository.UpdateInheritedValues();
progress.Report(100);
}
@@ -2517,7 +2514,7 @@ namespace Emby.Server.Implementations.Library
public bool FillMissingEpisodeNumbersFromPath(Episode episode, bool forceRefresh)
{
var series = episode.Series;
- bool? isAbsoluteNaming = series == null ? false : string.Equals(series.DisplayOrder, "absolute", StringComparison.OrdinalIgnoreCase);
+ bool? isAbsoluteNaming = series != null && string.Equals(series.DisplayOrder, "absolute", StringComparison.OrdinalIgnoreCase);
if (!isAbsoluteNaming.Value)
{
// In other words, no filter applied
@@ -2529,9 +2526,23 @@ namespace Emby.Server.Implementations.Library
var isFolder = episode.VideoType == VideoType.BluRay || episode.VideoType == VideoType.Dvd;
// TODO nullable - what are we trying to do there with empty episodeInfo?
- var episodeInfo = episode.IsFileProtocol
- ? resolver.Resolve(episode.Path, isFolder, null, null, isAbsoluteNaming) ?? new Naming.TV.EpisodeInfo(episode.Path)
- : new Naming.TV.EpisodeInfo(episode.Path);
+ EpisodeInfo episodeInfo = null;
+ if (episode.IsFileProtocol)
+ {
+ episodeInfo = resolver.Resolve(episode.Path, isFolder, null, null, isAbsoluteNaming);
+ // Resolve from parent folder if it's not the Season folder
+ if (episodeInfo == null && episode.Parent.GetType() == typeof(Folder))
+ {
+ episodeInfo = resolver.Resolve(episode.Parent.Path, true, null, null, isAbsoluteNaming);
+ if (episodeInfo != null)
+ {
+ // add the container
+ episodeInfo.Container = Path.GetExtension(episode.Path)?.TrimStart('.');
+ }
+ }
+ }
+
+ episodeInfo ??= new EpisodeInfo(episode.Path);
try
{
diff --git a/Emby.Server.Implementations/Library/MediaSourceManager.cs b/Emby.Server.Implementations/Library/MediaSourceManager.cs
index d0b85f07d..85d6d3043 100644
--- a/Emby.Server.Implementations/Library/MediaSourceManager.cs
+++ b/Emby.Server.Implementations/Library/MediaSourceManager.cs
@@ -590,18 +590,9 @@ namespace Emby.Server.Implementations.Library
public Task<IDirectStreamProvider> GetDirectStreamProviderByUniqueId(string uniqueId, CancellationToken cancellationToken)
{
- var info = _openStreams.Values.FirstOrDefault(i =>
- {
- var liveStream = i as ILiveStream;
- if (liveStream != null)
- {
- return string.Equals(liveStream.UniqueId, uniqueId, StringComparison.OrdinalIgnoreCase);
- }
-
- return false;
- });
+ var info = _openStreams.FirstOrDefault(i => i.Value != null && string.Equals(i.Value.UniqueId, uniqueId, StringComparison.OrdinalIgnoreCase));
- return Task.FromResult(info as IDirectStreamProvider);
+ return Task.FromResult(info.Value as IDirectStreamProvider);
}
public async Task<LiveStreamResponse> OpenLiveStream(LiveStreamRequest request, CancellationToken cancellationToken)
diff --git a/Emby.Server.Implementations/Library/MusicManager.cs b/Emby.Server.Implementations/Library/MusicManager.cs
index 658c53f28..f8bae4fd1 100644
--- a/Emby.Server.Implementations/Library/MusicManager.cs
+++ b/Emby.Server.Implementations/Library/MusicManager.cs
@@ -100,8 +100,7 @@ namespace Emby.Server.Implementations.Library
public List<BaseItem> GetInstantMixFromItem(BaseItem item, User user, DtoOptions dtoOptions)
{
- var genre = item as MusicGenre;
- if (genre != null)
+ if (item is MusicGenre genre)
{
return GetInstantMixFromGenreIds(new[] { item.Id }, user, dtoOptions);
}
diff --git a/Emby.Server.Implementations/Library/PathExtensions.cs b/Emby.Server.Implementations/Library/PathExtensions.cs
index 770cf6bb0..0de4edb7e 100644
--- a/Emby.Server.Implementations/Library/PathExtensions.cs
+++ b/Emby.Server.Implementations/Library/PathExtensions.cs
@@ -96,8 +96,14 @@ namespace Emby.Server.Implementations.Library
// We have to ensure that the sub path ends with a directory separator otherwise we'll get weird results
// when the sub path matches a similar but in-complete subpath
var oldSubPathEndsWithSeparator = subPath[^1] == newDirectorySeparatorChar;
- if (!path.StartsWith(subPath, StringComparison.OrdinalIgnoreCase)
- || (!oldSubPathEndsWithSeparator && path[subPath.Length] != newDirectorySeparatorChar))
+ if (!path.StartsWith(subPath, StringComparison.OrdinalIgnoreCase))
+ {
+ return false;
+ }
+
+ if (path.Length > subPath.Length
+ && !oldSubPathEndsWithSeparator
+ && path[subPath.Length] != newDirectorySeparatorChar)
{
return false;
}
diff --git a/Emby.Server.Implementations/Library/ResolverHelper.cs b/Emby.Server.Implementations/Library/ResolverHelper.cs
index 4e4cac75b..1d9b44874 100644
--- a/Emby.Server.Implementations/Library/ResolverHelper.cs
+++ b/Emby.Server.Implementations/Library/ResolverHelper.cs
@@ -1,3 +1,5 @@
+#nullable enable
+
using System;
using System.IO;
using System.Linq;
@@ -18,11 +20,10 @@ namespace Emby.Server.Implementations.Library
/// </summary>
/// <param name="item">The item.</param>
/// <param name="parent">The parent.</param>
- /// <param name="fileSystem">The file system.</param>
/// <param name="libraryManager">The library manager.</param>
/// <param name="directoryService">The directory service.</param>
- /// <exception cref="ArgumentException">Item must have a path</exception>
- public static void SetInitialItemValues(BaseItem item, Folder parent, IFileSystem fileSystem, ILibraryManager libraryManager, IDirectoryService directoryService)
+ /// <exception cref="ArgumentException">Item must have a path.</exception>
+ public static void SetInitialItemValues(BaseItem item, Folder? parent, ILibraryManager libraryManager, IDirectoryService directoryService)
{
// This version of the below method has no ItemResolveArgs, so we have to require the path already being set
if (string.IsNullOrEmpty(item.Path))
@@ -43,9 +44,14 @@ namespace Emby.Server.Implementations.Library
// Make sure DateCreated and DateModified have values
var fileInfo = directoryService.GetFile(item.Path);
- SetDateCreated(item, fileSystem, fileInfo);
+ if (fileInfo == null)
+ {
+ throw new FileNotFoundException("Can't find item path.", item.Path);
+ }
+
+ SetDateCreated(item, fileInfo);
- EnsureName(item, item.Path, fileInfo);
+ EnsureName(item, fileInfo);
}
/// <summary>
@@ -72,9 +78,9 @@ namespace Emby.Server.Implementations.Library
item.Id = libraryManager.GetNewItemId(item.Path, item.GetType());
// Make sure the item has a name
- EnsureName(item, item.Path, args.FileInfo);
+ EnsureName(item, args.FileInfo);
- item.IsLocked = item.Path.IndexOf("[dontfetchmeta]", StringComparison.OrdinalIgnoreCase) != -1 ||
+ item.IsLocked = item.Path.Contains("[dontfetchmeta]", StringComparison.OrdinalIgnoreCase) ||
item.GetParents().Any(i => i.IsLocked);
// Make sure DateCreated and DateModified have values
@@ -84,29 +90,16 @@ namespace Emby.Server.Implementations.Library
/// <summary>
/// Ensures the name.
/// </summary>
- private static void EnsureName(BaseItem item, string fullPath, FileSystemMetadata fileInfo)
+ private static void EnsureName(BaseItem item, FileSystemMetadata fileInfo)
{
// If the subclass didn't supply a name, add it here
- if (string.IsNullOrEmpty(item.Name) && !string.IsNullOrEmpty(fullPath))
+ if (string.IsNullOrEmpty(item.Name) && !string.IsNullOrEmpty(item.Path))
{
- var fileName = fileInfo == null ? Path.GetFileName(fullPath) : fileInfo.Name;
-
- item.Name = GetDisplayName(fileName, fileInfo != null && fileInfo.IsDirectory);
+ item.Name = fileInfo.IsDirectory ? fileInfo.Name : Path.GetFileNameWithoutExtension(fileInfo.Name);
}
}
/// <summary>
- /// Gets the display name.
- /// </summary>
- /// <param name="path">The path.</param>
- /// <param name="isDirectory">if set to <c>true</c> [is directory].</param>
- /// <returns>System.String.</returns>
- private static string GetDisplayName(string path, bool isDirectory)
- {
- return isDirectory ? Path.GetFileName(path) : Path.GetFileNameWithoutExtension(path);
- }
-
- /// <summary>
/// Ensures DateCreated and DateModified have values.
/// </summary>
/// <param name="fileSystem">The file system.</param>
@@ -114,21 +107,6 @@ namespace Emby.Server.Implementations.Library
/// <param name="args">The args.</param>
private static void EnsureDates(IFileSystem fileSystem, BaseItem item, ItemResolveArgs args)
{
- if (fileSystem == null)
- {
- throw new ArgumentNullException(nameof(fileSystem));
- }
-
- if (item == null)
- {
- throw new ArgumentNullException(nameof(item));
- }
-
- if (args == null)
- {
- throw new ArgumentNullException(nameof(args));
- }
-
// See if a different path came out of the resolver than what went in
if (!fileSystem.AreEqual(args.Path, item.Path))
{
@@ -136,7 +114,7 @@ namespace Emby.Server.Implementations.Library
if (childData != null)
{
- SetDateCreated(item, fileSystem, childData);
+ SetDateCreated(item, childData);
}
else
{
@@ -144,17 +122,17 @@ namespace Emby.Server.Implementations.Library
if (fileData.Exists)
{
- SetDateCreated(item, fileSystem, fileData);
+ SetDateCreated(item, fileData);
}
}
}
else
{
- SetDateCreated(item, fileSystem, args.FileInfo);
+ SetDateCreated(item, args.FileInfo);
}
}
- private static void SetDateCreated(BaseItem item, IFileSystem fileSystem, FileSystemMetadata info)
+ private static void SetDateCreated(BaseItem item, FileSystemMetadata? info)
{
var config = BaseItem.ConfigurationManager.GetMetadataConfiguration();
@@ -163,7 +141,7 @@ namespace Emby.Server.Implementations.Library
// directoryService.getFile may return null
if (info != null)
{
- var dateCreated = fileSystem.GetCreationTimeUtc(info);
+ var dateCreated = info.CreationTimeUtc;
if (dateCreated.Equals(DateTime.MinValue))
{
diff --git a/Emby.Server.Implementations/Library/Resolvers/ItemResolver.cs b/Emby.Server.Implementations/Library/Resolvers/ItemResolver.cs
index 9ca76095b..92fb2a753 100644
--- a/Emby.Server.Implementations/Library/Resolvers/ItemResolver.cs
+++ b/Emby.Server.Implementations/Library/Resolvers/ItemResolver.cs
@@ -12,6 +12,12 @@ namespace Emby.Server.Implementations.Library.Resolvers
where T : BaseItem, new()
{
/// <summary>
+ /// Gets the priority.
+ /// </summary>
+ /// <value>The priority.</value>
+ public virtual ResolverPriority Priority => ResolverPriority.First;
+
+ /// <summary>
/// Resolves the specified args.
/// </summary>
/// <param name="args">The args.</param>
@@ -22,12 +28,6 @@ namespace Emby.Server.Implementations.Library.Resolvers
}
/// <summary>
- /// Gets the priority.
- /// </summary>
- /// <value>The priority.</value>
- public virtual ResolverPriority Priority => ResolverPriority.First;
-
- /// <summary>
/// Sets initial values on the newly resolved item.
/// </summary>
/// <param name="item">The item.</param>
diff --git a/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs b/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs
index 714bc3a84..16bf4dc4a 100644
--- a/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs
+++ b/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs
@@ -376,7 +376,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
{
var multiDiscFolders = new List<FileSystemMetadata>();
- var libraryOptions = args.GetLibraryOptions();
+ var libraryOptions = args.LibraryOptions;
var supportPhotos = string.Equals(collectionType, CollectionType.HomeVideos, StringComparison.OrdinalIgnoreCase) && libraryOptions.EnablePhotos;
var photos = new List<FileSystemMetadata>();
diff --git a/Emby.Server.Implementations/Library/Resolvers/PhotoAlbumResolver.cs b/Emby.Server.Implementations/Library/Resolvers/PhotoAlbumResolver.cs
index 3ac837057..204c8a62e 100644
--- a/Emby.Server.Implementations/Library/Resolvers/PhotoAlbumResolver.cs
+++ b/Emby.Server.Implementations/Library/Resolvers/PhotoAlbumResolver.cs
@@ -13,7 +13,7 @@ namespace Emby.Server.Implementations.Library.Resolvers
public class PhotoAlbumResolver : FolderResolver<PhotoAlbum>
{
private readonly IImageProcessor _imageProcessor;
- private ILibraryManager _libraryManager;
+ private readonly ILibraryManager _libraryManager;
/// <summary>
/// Initializes a new instance of the <see cref="PhotoAlbumResolver"/> class.
@@ -26,6 +26,9 @@ namespace Emby.Server.Implementations.Library.Resolvers
_libraryManager = libraryManager;
}
+ /// <inheritdoc />
+ public override ResolverPriority Priority => ResolverPriority.Second;
+
/// <summary>
/// Resolves the specified args.
/// </summary>
@@ -39,8 +42,8 @@ namespace Emby.Server.Implementations.Library.Resolvers
// Must be an image file within a photo collection
var collectionType = args.GetCollectionType();
- if (string.Equals(collectionType, CollectionType.Photos, StringComparison.OrdinalIgnoreCase) ||
- (string.Equals(collectionType, CollectionType.HomeVideos, StringComparison.OrdinalIgnoreCase) && args.GetLibraryOptions().EnablePhotos))
+ if (string.Equals(collectionType, CollectionType.Photos, StringComparison.OrdinalIgnoreCase)
+ || (string.Equals(collectionType, CollectionType.HomeVideos, StringComparison.OrdinalIgnoreCase) && args.LibraryOptions.EnablePhotos))
{
if (HasPhotos(args))
{
@@ -84,8 +87,5 @@ namespace Emby.Server.Implementations.Library.Resolvers
return false;
}
-
- /// <inheritdoc />
- public override ResolverPriority Priority => ResolverPriority.Second;
}
}
diff --git a/Emby.Server.Implementations/Library/Resolvers/PhotoResolver.cs b/Emby.Server.Implementations/Library/Resolvers/PhotoResolver.cs
index bcfcee9c6..3cb6542cf 100644
--- a/Emby.Server.Implementations/Library/Resolvers/PhotoResolver.cs
+++ b/Emby.Server.Implementations/Library/Resolvers/PhotoResolver.cs
@@ -47,7 +47,7 @@ namespace Emby.Server.Implementations.Library.Resolvers
var collectionType = args.CollectionType;
if (string.Equals(collectionType, CollectionType.Photos, StringComparison.OrdinalIgnoreCase)
- || (string.Equals(collectionType, CollectionType.HomeVideos, StringComparison.OrdinalIgnoreCase) && args.GetLibraryOptions().EnablePhotos))
+ || (string.Equals(collectionType, CollectionType.HomeVideos, StringComparison.OrdinalIgnoreCase) && args.LibraryOptions.EnablePhotos))
{
if (IsImageFile(args.Path, _imageProcessor))
{
diff --git a/Emby.Server.Implementations/Library/Resolvers/TV/EpisodeResolver.cs b/Emby.Server.Implementations/Library/Resolvers/TV/EpisodeResolver.cs
index 9b4cd7a3d..6f29bc649 100644
--- a/Emby.Server.Implementations/Library/Resolvers/TV/EpisodeResolver.cs
+++ b/Emby.Server.Implementations/Library/Resolvers/TV/EpisodeResolver.cs
@@ -35,14 +35,10 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV
return null;
}
- var season = parent as Season;
-
// Just in case the user decided to nest episodes.
// Not officially supported but in some cases we can handle it.
- if (season == null)
- {
- season = parent.GetParents().OfType<Season>().FirstOrDefault();
- }
+
+ var season = parent as Season ?? parent.GetParents().OfType<Season>().FirstOrDefault();
// If the parent is a Season or Series and the parent is not an extras folder, then this is an Episode if the VideoResolver returns something
// Also handle flat tv folders
@@ -55,11 +51,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV
if (episode != null)
{
- var series = parent as Series;
- if (series == null)
- {
- series = parent.GetParents().OfType<Series>().FirstOrDefault();
- }
+ var series = parent as Series ?? parent.GetParents().OfType<Series>().FirstOrDefault();
if (series != null)
{
diff --git a/Emby.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs b/Emby.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs
index 3332e1806..768e2e4f5 100644
--- a/Emby.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs
+++ b/Emby.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs
@@ -88,7 +88,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV
CultureInfo.InvariantCulture,
_localization.GetLocalizedString("NameSeasonNumber"),
seasonNumber,
- args.GetLibraryOptions().PreferredMetadataLanguage);
+ args.LibraryOptions.PreferredMetadataLanguage);
}
return season;
diff --git a/Emby.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs b/Emby.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs
index 4a9d2cf8c..8fc3e3e75 100644
--- a/Emby.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs
+++ b/Emby.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs
@@ -19,19 +19,16 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV
/// </summary>
public class SeriesResolver : FolderResolver<Series>
{
- private readonly IFileSystem _fileSystem;
private readonly ILogger<SeriesResolver> _logger;
private readonly ILibraryManager _libraryManager;
/// <summary>
/// Initializes a new instance of the <see cref="SeriesResolver"/> class.
/// </summary>
- /// <param name="fileSystem">The file system.</param>
/// <param name="logger">The logger.</param>
/// <param name="libraryManager">The library manager.</param>
- public SeriesResolver(IFileSystem fileSystem, ILogger<SeriesResolver> logger, ILibraryManager libraryManager)
+ public SeriesResolver(ILogger<SeriesResolver> logger, ILibraryManager libraryManager)
{
- _fileSystem = fileSystem;
_logger = logger;
_libraryManager = libraryManager;
}
@@ -59,15 +56,6 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV
var collectionType = args.GetCollectionType();
if (string.Equals(collectionType, CollectionType.TvShows, StringComparison.OrdinalIgnoreCase))
{
- // if (args.ContainsFileSystemEntryByName("tvshow.nfo"))
- //{
- // return new Series
- // {
- // Path = args.Path,
- // Name = Path.GetFileName(args.Path)
- // };
- //}
-
var configuredContentType = _libraryManager.GetConfiguredContentType(args.Path);
if (!string.Equals(configuredContentType, CollectionType.TvShows, StringComparison.OrdinalIgnoreCase))
{
@@ -100,7 +88,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV
return null;
}
- if (IsSeriesFolder(args.Path, args.FileSystemChildren, args.DirectoryService, _fileSystem, _logger, _libraryManager, false))
+ if (IsSeriesFolder(args.Path, args.FileSystemChildren, _logger, _libraryManager, false))
{
return new Series
{
@@ -117,8 +105,6 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV
public static bool IsSeriesFolder(
string path,
IEnumerable<FileSystemMetadata> fileSystemChildren,
- IDirectoryService directoryService,
- IFileSystem fileSystem,
ILogger<SeriesResolver> logger,
ILibraryManager libraryManager,
bool isTvContentType)
diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
index c9d9cc49a..28a2095e1 100644
--- a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
+++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
@@ -801,22 +801,22 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
public ActiveRecordingInfo GetActiveRecordingInfo(string path)
{
- if (string.IsNullOrWhiteSpace(path))
+ if (string.IsNullOrWhiteSpace(path) || _activeRecordings.IsEmpty)
{
return null;
}
- foreach (var recording in _activeRecordings.Values)
+ foreach (var (_, recordingInfo) in _activeRecordings)
{
- if (string.Equals(recording.Path, path, StringComparison.Ordinal) && !recording.CancellationTokenSource.IsCancellationRequested)
+ if (string.Equals(recordingInfo.Path, path, StringComparison.Ordinal) && !recordingInfo.CancellationTokenSource.IsCancellationRequested)
{
- var timer = recording.Timer;
+ var timer = recordingInfo.Timer;
if (timer.Status != RecordingStatus.InProgress)
{
return null;
}
- return recording;
+ return recordingInfo;
}
}
@@ -1621,9 +1621,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
}
return _activeRecordings
- .Values
- .ToList()
- .Any(i => string.Equals(i.Path, path, StringComparison.OrdinalIgnoreCase) && !string.Equals(i.Timer.Id, timerId, StringComparison.OrdinalIgnoreCase));
+ .Any(i => string.Equals(i.Value.Path, path, StringComparison.OrdinalIgnoreCase) && !string.Equals(i.Value.Timer.Id, timerId, StringComparison.OrdinalIgnoreCase));
}
private IRecorder GetRecorder(MediaSourceInfo mediaSource)
@@ -2239,14 +2237,10 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
var enabledTimersForSeries = new List<TimerInfo>();
foreach (var timer in allTimers)
{
- var existingTimer = _timerProvider.GetTimer(timer.Id);
-
- if (existingTimer == null)
- {
- existingTimer = string.IsNullOrWhiteSpace(timer.ProgramId)
+ var existingTimer = _timerProvider.GetTimer(timer.Id)
+ ?? (string.IsNullOrWhiteSpace(timer.ProgramId)
? null
- : _timerProvider.GetTimerByProgramId(timer.ProgramId);
- }
+ : _timerProvider.GetTimerByProgramId(timer.ProgramId));
if (existingTimer == null)
{
diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs
index 44a8cdee4..9372b0f6c 100644
--- a/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs
+++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs
@@ -10,6 +10,7 @@ using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Common.Configuration;
+using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.Json;
using MediaBrowser.Controller;
using MediaBrowser.Controller.Configuration;
@@ -307,13 +308,11 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
{
using (var reader = new StreamReader(source))
{
- while (!reader.EndOfStream)
+ await foreach (var line in reader.ReadAllLinesAsync().ConfigureAwait(false))
{
- var line = await reader.ReadLineAsync().ConfigureAwait(false);
-
var bytes = Encoding.UTF8.GetBytes(Environment.NewLine + line);
- await target.WriteAsync(bytes, 0, bytes.Length).ConfigureAwait(false);
+ await target.WriteAsync(bytes.AsMemory()).ConfigureAwait(false);
await target.FlushAsync().ConfigureAwait(false);
}
}
diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs
index 1926e738f..9af65cabb 100644
--- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs
+++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs
@@ -787,14 +787,11 @@ namespace Emby.Server.Implementations.LiveTv.Listings
{
var channelNumber = GetChannelNumber(channel);
- var station = allStations.Find(item => string.Equals(item.stationID, channel.stationID, StringComparison.OrdinalIgnoreCase));
- if (station == null)
- {
- station = new ScheduleDirect.Station
+ var station = allStations.Find(item => string.Equals(item.stationID, channel.stationID, StringComparison.OrdinalIgnoreCase))
+ ?? new ScheduleDirect.Station
{
stationID = channel.stationID
};
- }
var channelInfo = new ChannelInfo
{
diff --git a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs
index 63a3146aa..1145d8aa1 100644
--- a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs
+++ b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs
@@ -987,10 +987,7 @@ namespace Emby.Server.Implementations.LiveTv
var externalProgramId = programTuple.Item2;
string externalSeriesId = programTuple.Item3;
- if (timerList == null)
- {
- timerList = (await GetTimersInternal(new TimerQuery(), cancellationToken).ConfigureAwait(false)).Items;
- }
+ timerList ??= (await GetTimersInternal(new TimerQuery(), cancellationToken).ConfigureAwait(false)).Items;
var timer = timerList.FirstOrDefault(i => string.Equals(i.ProgramId, externalProgramId, StringComparison.OrdinalIgnoreCase));
var foundSeriesTimer = false;
@@ -1018,10 +1015,7 @@ namespace Emby.Server.Implementations.LiveTv
continue;
}
- if (seriesTimerList == null)
- {
- seriesTimerList = (await GetSeriesTimersInternal(new SeriesTimerQuery(), cancellationToken).ConfigureAwait(false)).Items;
- }
+ seriesTimerList ??= (await GetSeriesTimersInternal(new SeriesTimerQuery(), cancellationToken).ConfigureAwait(false)).Items;
var seriesTimer = seriesTimerList.FirstOrDefault(i => string.Equals(i.SeriesId, externalSeriesId, StringComparison.OrdinalIgnoreCase));
@@ -1974,10 +1968,7 @@ namespace Emby.Server.Implementations.LiveTv
};
}
- if (service == null)
- {
- service = _services[0];
- }
+ service ??= _services[0];
var info = await service.GetNewTimerDefaultsAsync(cancellationToken, programInfo).ConfigureAwait(false);
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs
index 1dcc78687..324109bcf 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs
@@ -182,16 +182,16 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false);
using var sr = new StreamReader(stream, System.Text.Encoding.UTF8);
var tuners = new List<LiveTvTunerInfo>();
- while (!sr.EndOfStream)
+ await foreach (var line in sr.ReadAllLinesAsync().ConfigureAwait(false))
{
- string line = StripXML(sr.ReadLine());
- if (line.Contains("Channel", StringComparison.Ordinal))
+ string stripedLine = StripXML(line);
+ if (stripedLine.Contains("Channel", StringComparison.Ordinal))
{
LiveTvTunerStatus status;
- var index = line.IndexOf("Channel", StringComparison.OrdinalIgnoreCase);
- var name = line.Substring(0, index - 1);
- var currentChannel = line.Substring(index + 7);
- if (currentChannel != "none")
+ var index = stripedLine.IndexOf("Channel", StringComparison.OrdinalIgnoreCase);
+ var name = stripedLine.Substring(0, index - 1);
+ var currentChannel = stripedLine.Substring(index + 7);
+ if (string.Equals(currentChannel, "none", StringComparison.Ordinal))
{
status = LiveTvTunerStatus.LiveTv;
}
@@ -421,10 +421,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
string audioCodec = channelInfo.AudioCodec;
- if (!videoBitrate.HasValue)
- {
- videoBitrate = isHd ? 15000000 : 2000000;
- }
+ videoBitrate ??= isHd ? 15000000 : 2000000;
int? audioBitrate = isHd ? 448000 : 192000;
@@ -661,7 +658,9 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
_modelCache.Clear();
}
- cancellationToken = CancellationTokenSource.CreateLinkedTokenSource(new CancellationTokenSource(discoveryDurationMs).Token, cancellationToken).Token;
+ using var timedCancellationToken = new CancellationTokenSource(discoveryDurationMs);
+ using var linkedCancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(timedCancellationToken.Token, cancellationToken);
+ cancellationToken = linkedCancellationTokenSource.Token;
var list = new List<TunerHostInfo>();
// Create udp broadcast discovery message
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs
index 78e62ff0a..f8baf55da 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs
@@ -150,7 +150,8 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
public async Task CopyToAsync(Stream stream, CancellationToken cancellationToken)
{
- cancellationToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, LiveStreamCancellationTokenSource.Token).Token;
+ using var linkedCancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, LiveStreamCancellationTokenSource.Token);
+ cancellationToken = linkedCancellationTokenSource.Token;
// use non-async filestream on windows along with read due to https://github.com/dotnet/corefx/issues/6039
var allowAsync = Environment.OSVersion.Platform != PlatformID.Win32NT;
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs
index cc30a516d..84d416149 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs
@@ -35,16 +35,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
// Read the file and display it line by line.
using (var reader = new StreamReader(await GetListingsStream(info, cancellationToken).ConfigureAwait(false)))
{
- return GetChannels(reader, channelIdPrefix, info.Id);
- }
- }
-
- public List<ChannelInfo> ParseString(string text, string channelIdPrefix, string tunerHostId)
- {
- // Read the file and display it line by line.
- using (var reader = new StringReader(text))
- {
- return GetChannels(reader, channelIdPrefix, tunerHostId);
+ return await GetChannelsAsync(reader, channelIdPrefix, info.Id).ConfigureAwait(false);
}
}
@@ -70,43 +61,42 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
private const string ExtInfPrefix = "#EXTINF:";
- private List<ChannelInfo> GetChannels(TextReader reader, string channelIdPrefix, string tunerHostId)
+ private async Task<List<ChannelInfo>> GetChannelsAsync(TextReader reader, string channelIdPrefix, string tunerHostId)
{
var channels = new List<ChannelInfo>();
- string line;
string extInf = string.Empty;
- while ((line = reader.ReadLine()) != null)
+ await foreach (var line in reader.ReadAllLinesAsync().ConfigureAwait(false))
{
- line = line.Trim();
- if (string.IsNullOrWhiteSpace(line))
+ var trimmedLine = line.Trim();
+ if (string.IsNullOrWhiteSpace(trimmedLine))
{
continue;
}
- if (line.StartsWith("#EXTM3U", StringComparison.OrdinalIgnoreCase))
+ if (trimmedLine.StartsWith("#EXTM3U", StringComparison.OrdinalIgnoreCase))
{
continue;
}
- if (line.StartsWith(ExtInfPrefix, StringComparison.OrdinalIgnoreCase))
+ if (trimmedLine.StartsWith(ExtInfPrefix, StringComparison.OrdinalIgnoreCase))
{
- extInf = line.Substring(ExtInfPrefix.Length).Trim();
+ extInf = trimmedLine.Substring(ExtInfPrefix.Length).Trim();
_logger.LogInformation("Found m3u channel: {0}", extInf);
}
- else if (!string.IsNullOrWhiteSpace(extInf) && !line.StartsWith('#'))
+ else if (!string.IsNullOrWhiteSpace(extInf) && !trimmedLine.StartsWith('#'))
{
- var channel = GetChannelnfo(extInf, tunerHostId, line);
+ var channel = GetChannelnfo(extInf, tunerHostId, trimmedLine);
if (string.IsNullOrWhiteSpace(channel.Id))
{
- channel.Id = channelIdPrefix + line.GetMD5().ToString("N", CultureInfo.InvariantCulture);
+ channel.Id = channelIdPrefix + trimmedLine.GetMD5().ToString("N", CultureInfo.InvariantCulture);
}
else
{
channel.Id = channelIdPrefix + channel.Id.GetMD5().ToString("N", CultureInfo.InvariantCulture);
}
- channel.Path = line;
+ channel.Path = trimmedLine;
channels.Add(channel);
extInf = string.Empty;
}
diff --git a/Emby.Server.Implementations/Localization/Core/af.json b/Emby.Server.Implementations/Localization/Core/af.json
index b029b7042..4f21c66bc 100644
--- a/Emby.Server.Implementations/Localization/Core/af.json
+++ b/Emby.Server.Implementations/Localization/Core/af.json
@@ -115,5 +115,7 @@
"TaskRefreshChapterImages": "Verkry Hoofstuk Beelde",
"Undefined": "Ongedefineerd",
"Forced": "Geforseer",
- "Default": "Oorspronklik"
+ "Default": "Oorspronklik",
+ "TaskCleanActivityLogDescription": "Verwyder aktiwiteitsaantekeninge ouer as die opgestelde ouderdom.",
+ "TaskCleanActivityLog": "Maak Aktiwiteitsaantekeninge Skoon"
}
diff --git a/Emby.Server.Implementations/Localization/Core/ar.json b/Emby.Server.Implementations/Localization/Core/ar.json
index 4b898e6fe..9f84d3a3c 100644
--- a/Emby.Server.Implementations/Localization/Core/ar.json
+++ b/Emby.Server.Implementations/Localization/Core/ar.json
@@ -113,5 +113,8 @@
"TaskRefreshPeopleDescription": "تحديث البيانات الوصفية للممثلين والمخرجين في مكتبة الوسائط الخاصة بك.",
"TaskRefreshPeople": "إعادة تحميل الأشخاص",
"TaskCleanLogsDescription": "حذف السجلات الأقدم من {0} يوم.",
- "TaskCleanLogs": "حذف دليل السجل"
+ "TaskCleanLogs": "حذف دليل السجل",
+ "TaskCleanActivityLogDescription": "يحذف سجل الأنشطة الأقدم من الوقت الموضوع.",
+ "TaskCleanActivityLog": "حذف سجل الأنشطة",
+ "Default": "الإعدادات الافتراضية"
}
diff --git a/Emby.Server.Implementations/Localization/Core/bn.json b/Emby.Server.Implementations/Localization/Core/bn.json
index a23037af8..f0e42a052 100644
--- a/Emby.Server.Implementations/Localization/Core/bn.json
+++ b/Emby.Server.Implementations/Localization/Core/bn.json
@@ -115,7 +115,7 @@
"TaskRefreshLibraryDescription": "নতুন ফাইলের জন্য মিডিয়া লাইব্রেরি স্ক্যান এবং মেটাডাটা রিফ্রেশ করুন।",
"Undefined": "অসঙ্গায়িত",
"Forced": "জোরকরে",
- "TaskCleanActivityLogDescription": "নির্ধারিত সময়ের আগের কাজের হিসাব মুছে দিন খালি করুন",
+ "TaskCleanActivityLogDescription": "নির্ধারিত সময়ের আগের কাজের হিসাব মুছে দিন খালি করুন.",
"TaskCleanActivityLog": "কাজের ফাইল খালি করুন",
"Default": "প্রাথমিক"
}
diff --git a/Emby.Server.Implementations/Localization/Core/cs.json b/Emby.Server.Implementations/Localization/Core/cs.json
index 775267183..ff14c1929 100644
--- a/Emby.Server.Implementations/Localization/Core/cs.json
+++ b/Emby.Server.Implementations/Localization/Core/cs.json
@@ -39,7 +39,7 @@
"MixedContent": "Smíšený obsah",
"Movies": "Filmy",
"Music": "Hudba",
- "MusicVideos": "Hudební klipy",
+ "MusicVideos": "Hudební videa",
"NameInstallFailed": "Instalace {0} selhala",
"NameSeasonNumber": "Sezóna {0}",
"NameSeasonUnknown": "Neznámá sezóna",
diff --git a/Emby.Server.Implementations/Localization/Core/da.json b/Emby.Server.Implementations/Localization/Core/da.json
index 051d6d009..3453507d9 100644
--- a/Emby.Server.Implementations/Localization/Core/da.json
+++ b/Emby.Server.Implementations/Localization/Core/da.json
@@ -39,7 +39,7 @@
"MixedContent": "Blandet indhold",
"Movies": "Film",
"Music": "Musik",
- "MusicVideos": "Musikvideoer",
+ "MusicVideos": "Musik videoer",
"NameInstallFailed": "{0} installationen mislykkedes",
"NameSeasonNumber": "Sæson {0}",
"NameSeasonUnknown": "Ukendt Sæson",
diff --git a/Emby.Server.Implementations/Localization/Core/fa.json b/Emby.Server.Implementations/Localization/Core/fa.json
index e9e4f61b8..8ab657e5b 100644
--- a/Emby.Server.Implementations/Localization/Core/fa.json
+++ b/Emby.Server.Implementations/Localization/Core/fa.json
@@ -34,7 +34,7 @@
"Latest": "جدیدترین‌ها",
"MessageApplicationUpdated": "سرور Jellyfin بروزرسانی شد",
"MessageApplicationUpdatedTo": "سرور Jellyfin به نسخه {0} بروزرسانی شد",
- "MessageNamedServerConfigurationUpdatedWithValue": "پکربندی بخش {0} سرور بروزرسانی شد",
+ "MessageNamedServerConfigurationUpdatedWithValue": "پکربندی بخش {0} سرور بروزرسانی شد",
"MessageServerConfigurationUpdated": "پیکربندی سرور بروزرسانی شد",
"MixedContent": "محتوای مخلوط",
"Movies": "فیلم‌ها",
diff --git a/Emby.Server.Implementations/Localization/Core/fi.json b/Emby.Server.Implementations/Localization/Core/fi.json
index fd6148e78..633968d26 100644
--- a/Emby.Server.Implementations/Localization/Core/fi.json
+++ b/Emby.Server.Implementations/Localization/Core/fi.json
@@ -1,5 +1,5 @@
{
- "HeaderLiveTV": "Live TV",
+ "HeaderLiveTV": "Suora TV",
"NewVersionIsAvailable": "Uusi versio Jellyfin-palvelimesta on ladattavissa.",
"NameSeasonUnknown": "Tuntematon kausi",
"NameSeasonNumber": "Kausi {0}",
diff --git a/Emby.Server.Implementations/Localization/Core/fr.json b/Emby.Server.Implementations/Localization/Core/fr.json
index 1e195378f..ce1493be8 100644
--- a/Emby.Server.Implementations/Localization/Core/fr.json
+++ b/Emby.Server.Implementations/Localization/Core/fr.json
@@ -15,7 +15,7 @@
"Favorites": "Favoris",
"Folders": "Dossiers",
"Genres": "Genres",
- "HeaderAlbumArtists": "Artistes",
+ "HeaderAlbumArtists": "Artistes de l'album",
"HeaderContinueWatching": "Continuer à regarder",
"HeaderFavoriteAlbums": "Albums favoris",
"HeaderFavoriteArtists": "Artistes préférés",
@@ -39,7 +39,7 @@
"MixedContent": "Contenu mixte",
"Movies": "Films",
"Music": "Musique",
- "MusicVideos": "Vidéos musicales",
+ "MusicVideos": "Clips musicaux",
"NameInstallFailed": "{0} échec de l'installation",
"NameSeasonNumber": "Saison {0}",
"NameSeasonUnknown": "Saison Inconnue",
@@ -99,7 +99,7 @@
"TaskRefreshChannels": "Rafraîchir les chaines",
"TaskCleanTranscodeDescription": "Supprime les fichiers transcodés de plus d'un jour.",
"TaskCleanTranscode": "Nettoyer les dossier des transcodages",
- "TaskUpdatePluginsDescription": "Télécharge et installe les mises à jours des extensions configurés pour être mises à jour automatiquement.",
+ "TaskUpdatePluginsDescription": "Télécharge et installe les mises à jours des extensions configurées pour être mises à jour automatiquement.",
"TaskUpdatePlugins": "Mettre à jour les extensions",
"TaskRefreshPeopleDescription": "Met à jour les métadonnées pour les acteurs et réalisateurs dans votre bibliothèque.",
"TaskRefreshPeople": "Rafraîchir les acteurs",
@@ -107,7 +107,7 @@
"TaskCleanLogs": "Nettoyer le répertoire des journaux",
"TaskRefreshLibraryDescription": "Scanne toute les bibliothèques pour trouver les nouveaux fichiers et rafraîchit les métadonnées.",
"TaskRefreshLibrary": "Scanner toutes les Bibliothèques",
- "TaskRefreshChapterImagesDescription": "Crée des images de miniature pour les vidéos ayant des chapitres.",
+ "TaskRefreshChapterImagesDescription": "Crée des vignettes pour les vidéos ayant des chapitres.",
"TaskRefreshChapterImages": "Extraire les images de chapitre",
"TaskCleanCacheDescription": "Supprime les fichiers de cache dont le système n'a plus besoin.",
"TaskCleanCache": "Vider le répertoire cache",
diff --git a/Emby.Server.Implementations/Localization/Core/gl.json b/Emby.Server.Implementations/Localization/Core/gl.json
index 11139d32a..0398e1c9e 100644
--- a/Emby.Server.Implementations/Localization/Core/gl.json
+++ b/Emby.Server.Implementations/Localization/Core/gl.json
@@ -79,5 +79,14 @@
"PluginUninstalledWithName": "{0} foi desinstalado",
"PluginInstalledWithName": "{0} foi instalado",
"Playlists": "Listas de reproducción",
- "Photos": "Fotos"
+ "Photos": "Fotos",
+ "UserLockedOutWithName": "O usuario {0} foi bloqueado",
+ "UserDownloadingItemWithValues": "{0} está a ser transferido {1}",
+ "UserDeletedWithName": "O usuario {0} foi borrado",
+ "UserCreatedWithName": "O usuario {0} foi creado",
+ "Plugin": "Plugin",
+ "NotificationOptionVideoPlaybackStopped": "Reproducción de vídeo parada",
+ "NotificationOptionVideoPlayback": "Reproducción de vídeo iniciada",
+ "NotificationOptionUserLockedOut": "Usuario bloqueado",
+ "NotificationOptionTaskFailed": "Falla na tarefa axendada"
}
diff --git a/Emby.Server.Implementations/Localization/Core/hi.json b/Emby.Server.Implementations/Localization/Core/hi.json
index ef3697b15..82dc601bc 100644
--- a/Emby.Server.Implementations/Localization/Core/hi.json
+++ b/Emby.Server.Implementations/Localization/Core/hi.json
@@ -51,5 +51,14 @@
"Latest": "सबसे नया",
"LabelIpAddressValue": "आई पी एड्रेस: {0}",
"ItemRemovedWithName": "{0} लाइब्रेरी में से निकाल दिया है",
- "HomeVideos": "होम वीडियोस"
+ "HomeVideos": "होम वीडियोस",
+ "NotificationOptionVideoPlayback": "वीडियो प्लेबैक शुरू हुआ",
+ "NotificationOptionUserLockedOut": "उपयोगकर्ता लॉक हो गया",
+ "NotificationOptionTaskFailed": "निर्धारित कार्य विफलता",
+ "NotificationOptionServerRestartRequired": "सर्वर पुनरारंभ आवश्यक है",
+ "NotificationOptionPluginUpdateInstalled": "प्लगइन अद्यतन स्थापित",
+ "NotificationOptionNewLibraryContent": "नई सामग्री जोड़ी गई",
+ "LabelRunningTimeValue": "चलने का समय: {0}",
+ "ItemAddedWithName": "{0} को लाइब्रेरी में जोड़ा गया",
+ "Inherit": "इनहेरिट"
}
diff --git a/Emby.Server.Implementations/Localization/Core/hu.json b/Emby.Server.Implementations/Localization/Core/hu.json
index ef8070503..85848fed6 100644
--- a/Emby.Server.Implementations/Localization/Core/hu.json
+++ b/Emby.Server.Implementations/Localization/Core/hu.json
@@ -39,7 +39,7 @@
"MixedContent": "Vegyes tartalom",
"Movies": "Filmek",
"Music": "Zene",
- "MusicVideos": "Zenei videók",
+ "MusicVideos": "Zenei videóklippek",
"NameInstallFailed": "{0} sikertelen telepítés",
"NameSeasonNumber": "{0}. évad",
"NameSeasonUnknown": "Ismeretlen évad",
@@ -74,7 +74,7 @@
"Songs": "Dalok",
"StartupEmbyServerIsLoading": "A Jellyfin Szerver betöltődik. Kérlek, próbáld újra hamarosan.",
"SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}",
- "SubtitleDownloadFailureFromForItem": "Nem sikerült a felirat letöltése innen: {0} ehhez: {1}",
+ "SubtitleDownloadFailureFromForItem": "Nem sikerült a felirat letöltése innen: {0} ehhez: {1}",
"Sync": "Szinkronizál",
"System": "Rendszer",
"TvShows": "TV műsorok",
@@ -82,12 +82,12 @@
"UserCreatedWithName": "{0} felhasználó létrehozva",
"UserDeletedWithName": "{0} felhasználó törölve",
"UserDownloadingItemWithValues": "{0} letölti {1}",
- "UserLockedOutWithName": "{0} felhasználó zárolva van",
- "UserOfflineFromDevice": "{0} kijelentkezett innen: {1}",
+ "UserLockedOutWithName": "{0} felhasználó zárolva van",
+ "UserOfflineFromDevice": "{0} kijelentkezett innen: {1}",
"UserOnlineFromDevice": "{0} online innen: {1}",
"UserPasswordChangedWithName": "Jelszó megváltozott a következő felhasználó számára: {0}",
"UserPolicyUpdatedWithName": "A felhasználói házirend frissítve lett neki: {0}",
- "UserStartedPlayingItemWithValues": "{0} elkezdte játszani a következőt: {1} itt: {2}",
+ "UserStartedPlayingItemWithValues": "{0} elkezdte játszani a következőt: {1} itt: {2}",
"UserStoppedPlayingItemWithValues": "{0} befejezte {1} lejátászását itt: {2}",
"ValueHasBeenAddedToLibrary": "{0} hozzáadva a médiatárhoz",
"ValueSpecialEpisodeName": "Special - {0}",
diff --git a/Emby.Server.Implementations/Localization/Core/is.json b/Emby.Server.Implementations/Localization/Core/is.json
index 0f769eaad..b262a8b42 100644
--- a/Emby.Server.Implementations/Localization/Core/is.json
+++ b/Emby.Server.Implementations/Localization/Core/is.json
@@ -25,7 +25,7 @@
"Channels": "Stöðvar",
"CameraImageUploadedFrom": "Ný ljósmynd frá myndavél hefur verið hlaðið upp frá {0}",
"Books": "Bækur",
- "AuthenticationSucceededWithUserName": "{0} náði að auðkennast",
+ "AuthenticationSucceededWithUserName": "{0} auðkenning tókst",
"Artists": "Listamaður",
"Application": "Forrit",
"AppDeviceValues": "Snjallforrit: {0}, Tæki: {1}",
@@ -106,5 +106,6 @@
"TasksChannelsCategory": "Netrásir",
"TasksApplicationCategory": "Forrit",
"TasksLibraryCategory": "Miðlasafn",
- "TasksMaintenanceCategory": "Viðhald"
+ "TasksMaintenanceCategory": "Viðhald",
+ "Default": "Sjálfgefið"
}
diff --git a/Emby.Server.Implementations/Localization/Core/it.json b/Emby.Server.Implementations/Localization/Core/it.json
index 110f8043d..bd06f0a25 100644
--- a/Emby.Server.Implementations/Localization/Core/it.json
+++ b/Emby.Server.Implementations/Localization/Core/it.json
@@ -62,7 +62,7 @@
"NotificationOptionVideoPlaybackStopped": "La riproduzione video è stata interrotta",
"Photos": "Foto",
"Playlists": "Playlist",
- "Plugin": "Plug-in",
+ "Plugin": "Plugin",
"PluginInstalledWithName": "{0} è stato Installato",
"PluginUninstalledWithName": "{0} è stato disinstallato",
"PluginUpdatedWithName": "{0} è stato aggiornato",
@@ -87,7 +87,7 @@
"UserOnlineFromDevice": "{0} è online su {1}",
"UserPasswordChangedWithName": "La password è stata cambiata per l'utente {0}",
"UserPolicyUpdatedWithName": "La policy dell'utente è stata aggiornata per {0}",
- "UserStartedPlayingItemWithValues": "{0} ha avviato la riproduzione di {1} su {2}",
+ "UserStartedPlayingItemWithValues": "{0} ha avviato la riproduzione di \"{1}\" su {2}",
"UserStoppedPlayingItemWithValues": "{0} ha interrotto la riproduzione di {1} su {2}",
"ValueHasBeenAddedToLibrary": "{0} è stato aggiunto alla tua libreria multimediale",
"ValueSpecialEpisodeName": "Speciale - {0}",
diff --git a/Emby.Server.Implementations/Localization/Core/kk.json b/Emby.Server.Implementations/Localization/Core/kk.json
index 829a29ad4..4eee36989 100644
--- a/Emby.Server.Implementations/Localization/Core/kk.json
+++ b/Emby.Server.Implementations/Localization/Core/kk.json
@@ -5,23 +5,23 @@
"Artists": "Oryndauşylar",
"AuthenticationSucceededWithUserName": "{0} tüpnūsqalyq rastaluy sättı aiaqtaldy",
"Books": "Kıtaptar",
- "CameraImageUploadedFrom": "{0} kamerasynan jaŋa suret jüktep salyndy",
+ "CameraImageUploadedFrom": "{0} kamerasynan jaña suret jüktep salyndy",
"Channels": "Arnalar",
"ChapterNameValue": "{0}-sahna",
"Collections": "Jiyntyqtar",
"DeviceOfflineWithName": "{0} ajyratylğan",
"DeviceOnlineWithName": "{0} qosylğan",
"FailedLoginAttemptWithUserName": "{0} tarapynan kıru äreketı sätsız aiaqtaldy",
- "Favorites": "Taŋdaulylar",
+ "Favorites": "Tañdaulylar",
"Folders": "Qaltalar",
"Genres": "Janrlar",
"HeaderAlbumArtists": "Älbom oryndauşylary",
"HeaderContinueWatching": "Qaraudy jalğastyru",
- "HeaderFavoriteAlbums": "Taŋdauly älbomdar",
- "HeaderFavoriteArtists": "Taŋdauly oryndauşylar",
- "HeaderFavoriteEpisodes": "Taŋdauly telebölımder",
- "HeaderFavoriteShows": "Taŋdauly körsetımder",
- "HeaderFavoriteSongs": "Taŋdauly äuender",
+ "HeaderFavoriteAlbums": "Tañdauly älbomdar",
+ "HeaderFavoriteArtists": "Tañdauly oryndauşylar",
+ "HeaderFavoriteEpisodes": "Tañdauly telebölımder",
+ "HeaderFavoriteShows": "Tañdauly körsetımder",
+ "HeaderFavoriteSongs": "Tañdauly äuender",
"HeaderLiveTV": "Efir",
"HeaderNextUp": "Kezektı",
"HeaderRecordingGroups": "Jazba toptary",
@@ -31,11 +31,11 @@
"ItemRemovedWithName": "{0} tasyğyşhanadan alastaldy",
"LabelIpAddressValue": "IP-mekenjaiy: {0}",
"LabelRunningTimeValue": "Oinatu uaqyty: {0}",
- "Latest": "Eŋ keiıngı",
- "MessageApplicationUpdated": "Jellyfin Serverı jaŋartyldy",
- "MessageApplicationUpdatedTo": "Jellyfin Serverı {0} nūsqasyna jaŋartyldy",
- "MessageNamedServerConfigurationUpdatedWithValue": "Server teŋşelımderınıŋ {0} bölımı jaŋartyldy",
- "MessageServerConfigurationUpdated": "Server teŋşelımderı jaŋartyldy",
+ "Latest": "Eñ keiıngı",
+ "MessageApplicationUpdated": "Jellyfin Serverı jañartyldy",
+ "MessageApplicationUpdatedTo": "Jellyfin Serverı {0} nūsqasyna jañartyldy",
+ "MessageNamedServerConfigurationUpdatedWithValue": "Server teñşelımderınıñ {0} bölımı jañartyldy",
+ "MessageServerConfigurationUpdated": "Server teñşelımderı jañartyldy",
"MixedContent": "Aralas mazmūn",
"Movies": "Filmder",
"Music": "Muzyka",
@@ -43,18 +43,18 @@
"NameInstallFailed": "{0} ornatyluy sätsız",
"NameSeasonNumber": "{0}-mausym",
"NameSeasonUnknown": "Belgısız mausym",
- "NewVersionIsAvailable": "Jaŋa Jellyfin Server nūsqasy jüktep aluğa qoljetımdı.",
- "NotificationOptionApplicationUpdateAvailable": "Qoldanba jaŋartuy qoljetımdı",
- "NotificationOptionApplicationUpdateInstalled": "Qoldanba jaŋartuy ornatyldy",
+ "NewVersionIsAvailable": "Jaña Jellyfin Server nūsqasy jüktep aluğa qoljetımdı.",
+ "NotificationOptionApplicationUpdateAvailable": "Qoldanba jañartuy qoljetımdı",
+ "NotificationOptionApplicationUpdateInstalled": "Qoldanba jañartuy ornatyldy",
"NotificationOptionAudioPlayback": "Dybys oinatuy bastaldy",
"NotificationOptionAudioPlaybackStopped": "Dybys oinatuy toqtatyldy",
"NotificationOptionCameraImageUploaded": "Kameradan fotosuret jüktep salynğan",
"NotificationOptionInstallationFailed": "Ornatu sätsızdıgı",
- "NotificationOptionNewLibraryContent": "Jaŋa mazmūn üstelıngen",
+ "NotificationOptionNewLibraryContent": "Jaña mazmūn üstelıngen",
"NotificationOptionPluginError": "Plagin sätsızdıgı",
"NotificationOptionPluginInstalled": "Plagin ornatyldy",
"NotificationOptionPluginUninstalled": "Plagin ornatuy boldyrylmady",
- "NotificationOptionPluginUpdateInstalled": "Plagin jaŋartuy ornatyldy",
+ "NotificationOptionPluginUpdateInstalled": "Plagin jañartuy ornatyldy",
"NotificationOptionServerRestartRequired": "Serverdı qaita ıske qosu qajet",
"NotificationOptionTaskFailed": "Josparlağan tapsyrma sätsızdıgı",
"NotificationOptionUserLockedOut": "Paidalanuşy qūrsauly",
@@ -65,14 +65,14 @@
"Plugin": "Plagin",
"PluginInstalledWithName": "{0} ornatyldy",
"PluginUninstalledWithName": "{0} joiyldy",
- "PluginUpdatedWithName": "{0} jaŋartyldy",
+ "PluginUpdatedWithName": "{0} jañartyldy",
"ProviderValue": "Jetkızuşı: {0}",
"ScheduledTaskFailedWithName": "{0} sätsız",
"ScheduledTaskStartedWithName": "{0} ıske qosyldy",
"ServerNameNeedsToBeRestarted": "{0} qaita ıske qosu qajet",
"Shows": "Körsetımder",
"Songs": "Äuender",
- "StartupEmbyServerIsLoading": "Jellyfin Server jüktelude. Ärekettı köp ūzamai qaitalaŋyz.",
+ "StartupEmbyServerIsLoading": "Jellyfin Server jüktelude. Ärekettı köp ūzamai qaitalañyz.",
"SubtitleDownloadFailureForItem": "Субтитрлер {0} үшін жүктеліп алынуы сәтсіз",
"SubtitleDownloadFailureFromForItem": "{1} üşın subtitrlerdı {0} közınen jüktep alu sätsız",
"Sync": "Ündestıru",
@@ -86,7 +86,7 @@
"UserOfflineFromDevice": "{0} — {1} tarapynan ajyratyldy",
"UserOnlineFromDevice": "{0} — {1} tarapynan qosyldy",
"UserPasswordChangedWithName": "Paidalanuşy {0} üşın paröl özgertıldı",
- "UserPolicyUpdatedWithName": "Paidalanuşy {0} üşın saiasattary jaŋartyldy",
+ "UserPolicyUpdatedWithName": "Paidalanuşy {0} üşın saiasattary jañartyldy",
"UserStartedPlayingItemWithValues": "{0} — {2} tarapynan {1} oinatuda",
"UserStoppedPlayingItemWithValues": "{0} — {2} tarapynan {1} oinatuyn toqtatty",
"ValueHasBeenAddedToLibrary": "{0} tasyğyşhanağa üstelındı",
@@ -94,10 +94,10 @@
"VersionNumber": "Nūsqasy {0}",
"Default": "Ädepkı",
"TaskDownloadMissingSubtitles": "Joq subtitrlerdı jüktep alu",
- "TaskRefreshChannels": "Arnalardy jaŋğyrtu",
+ "TaskRefreshChannels": "Arnalardy jañğyrtu",
"TaskCleanTranscode": "Qaita kodtau katalogyn tazalau",
- "TaskUpdatePlugins": "Plaginderdı jaŋartu",
- "TaskRefreshPeople": "Adamdardy jaŋğyrtu",
+ "TaskUpdatePlugins": "Plaginderdı jañartu",
+ "TaskRefreshPeople": "Adamdardy jañğyrtu",
"TaskCleanLogs": "Jūrnal katalogyn tazalau",
"TaskRefreshLibrary": "Tasyğyşhanany skanerleu",
"TaskRefreshChapterImages": "Sahna suretterın şyğaryp alu",
@@ -109,14 +109,14 @@
"TasksMaintenanceCategory": "Qyzmet körsetu",
"Undefined": "Anyqtalmağan",
"Forced": "Mäjbürlı",
- "TaskDownloadMissingSubtitlesDescription": "Metaderekter teŋşelımderı negızınde joq subtitrlerdı İnternetten ızdeidı.",
- "TaskRefreshChannelsDescription": "Internet-arnalar mälımetterın jaŋğyrtady.",
+ "TaskDownloadMissingSubtitlesDescription": "Metaderekter teñşelımderı negızınde joq subtitrlerdı İnternetten ızdeidı.",
+ "TaskRefreshChannelsDescription": "Internet-arnalar mälımetterın jañğyrtady.",
"TaskCleanTranscodeDescription": "Bіr künnen asqan qaita kodtau faildaryn joiady.",
- "TaskUpdatePluginsDescription": "Avtomatty türde jaŋartuğa teŋşelgen plaginder üşın jaŋartulardy jüktep alady jäne ornatady.",
- "TaskRefreshPeopleDescription": "Tasyğyşhanadağy aktörler men rejisörler metaderekterın jaŋartady.",
+ "TaskUpdatePluginsDescription": "Avtomatty türde jañartuğa teñşelgen plaginder üşın jañartulardy jüktep alady jäne ornatady.",
+ "TaskRefreshPeopleDescription": "Tasyğyşhanadağy aktörler men rejisörler metaderekterın jañartady.",
"TaskCleanLogsDescription": "{0} künnen asqan jūrnal faildaryn joiady.",
- "TaskRefreshLibraryDescription": "Tasyğyşhanadağy jaŋa faildardy skanerleidі jäne metaderekterdı jaŋğyrtady.",
+ "TaskRefreshLibraryDescription": "Tasyğyşhanadağy jaña faildardy skanerleidі jäne metaderekterdı jañğyrtady.",
"TaskRefreshChapterImagesDescription": "Sahnalary bar beineler üşın nobailar jasaidy.",
"TaskCleanCacheDescription": "Jüiede qajet emes keştelgen faildardy joiady.",
- "TaskCleanActivityLogDescription": "Äreket jūrnalyndağy teŋşelgen jasynan asqan jazbalary joiady."
+ "TaskCleanActivityLogDescription": "Äreket jūrnalyndağy teñşelgen jasynan asqan jazbalary joiady."
}
diff --git a/Emby.Server.Implementations/Localization/Core/lt-LT.json b/Emby.Server.Implementations/Localization/Core/lt-LT.json
index 9920ef4d5..f3a131d40 100644
--- a/Emby.Server.Implementations/Localization/Core/lt-LT.json
+++ b/Emby.Server.Implementations/Localization/Core/lt-LT.json
@@ -114,8 +114,9 @@
"TasksApplicationCategory": "Programa",
"TasksLibraryCategory": "Mediateka",
"TasksMaintenanceCategory": "Priežiūra",
- "TaskCleanActivityLog": "Švarus veiklos žurnalas",
+ "TaskCleanActivityLog": "Išvalyti veiklos žurnalą",
"Undefined": "Neapibrėžtas",
"Forced": "Priverstas",
- "Default": "Numatytas"
+ "Default": "Numatytas",
+ "TaskCleanActivityLogDescription": "Ištrina veiklos žuranlo įrašus, kurie yra senesni nei nustatytas amžius."
}
diff --git a/Emby.Server.Implementations/Localization/Core/ms.json b/Emby.Server.Implementations/Localization/Core/ms.json
index 5e3d095ff..0b0458691 100644
--- a/Emby.Server.Implementations/Localization/Core/ms.json
+++ b/Emby.Server.Implementations/Localization/Core/ms.json
@@ -39,20 +39,20 @@
"MixedContent": "Kandungan campuran",
"Movies": "Filem",
"Music": "Muzik",
- "MusicVideos": "Video muzik",
+ "MusicVideos": "Muzik video",
"NameInstallFailed": "{0} pemasangan gagal",
"NameSeasonNumber": "Musim {0}",
"NameSeasonUnknown": "Musim Tidak Diketahui",
"NewVersionIsAvailable": "Versi terbaru Jellyfin Server bersedia untuk dimuat turunkan.",
"NotificationOptionApplicationUpdateAvailable": "Kemas kini aplikasi telah sedia",
- "NotificationOptionApplicationUpdateInstalled": "Application update installed",
- "NotificationOptionAudioPlayback": "Audio playback started",
- "NotificationOptionAudioPlaybackStopped": "Audio playback stopped",
- "NotificationOptionCameraImageUploaded": "Camera image uploaded",
+ "NotificationOptionApplicationUpdateInstalled": "Kemas kini aplikasi telah dipasang",
+ "NotificationOptionAudioPlayback": "Ulangmain audio bermula",
+ "NotificationOptionAudioPlaybackStopped": "Ulangmain audio dihentikan",
+ "NotificationOptionCameraImageUploaded": "Imej kamera telah dimuatnaik",
"NotificationOptionInstallationFailed": "Pemasangan gagal",
- "NotificationOptionNewLibraryContent": "New content added",
- "NotificationOptionPluginError": "Plugin failure",
- "NotificationOptionPluginInstalled": "Plugin installed",
+ "NotificationOptionNewLibraryContent": "Kandungan baru telah ditambah",
+ "NotificationOptionPluginError": "Kegagalan plugin",
+ "NotificationOptionPluginInstalled": "Plugin telah dipasang",
"NotificationOptionPluginUninstalled": "Plugin uninstalled",
"NotificationOptionPluginUpdateInstalled": "Plugin update installed",
"NotificationOptionServerRestartRequired": "Server restart required",
@@ -60,8 +60,8 @@
"NotificationOptionUserLockedOut": "User locked out",
"NotificationOptionVideoPlayback": "Video playback started",
"NotificationOptionVideoPlaybackStopped": "Video playback stopped",
- "Photos": "Photos",
- "Playlists": "Playlists",
+ "Photos": "Gambar-gambar",
+ "Playlists": "Senarai main",
"Plugin": "Plugin",
"PluginInstalledWithName": "{0} was installed",
"PluginUninstalledWithName": "{0} was uninstalled",
@@ -71,8 +71,8 @@
"ScheduledTaskStartedWithName": "{0} bermula",
"ServerNameNeedsToBeRestarted": "{0} needs to be restarted",
"Shows": "Series",
- "Songs": "Songs",
- "StartupEmbyServerIsLoading": "Jellyfin Server is loading. Please try again shortly.",
+ "Songs": "Lagu-lagu",
+ "StartupEmbyServerIsLoading": "Jellyfin Server sedang dimuatkan. Sila cuba sebentar lagi.",
"SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}",
"SubtitleDownloadFailureFromForItem": "Subtitles failed to download from {0} for {1}",
"Sync": "Sync",
@@ -82,14 +82,24 @@
"UserCreatedWithName": "User {0} has been created",
"UserDeletedWithName": "User {0} has been deleted",
"UserDownloadingItemWithValues": "{0} is downloading {1}",
- "UserLockedOutWithName": "User {0} has been locked out",
- "UserOfflineFromDevice": "{0} has disconnected from {1}",
- "UserOnlineFromDevice": "{0} is online from {1}",
- "UserPasswordChangedWithName": "Password has been changed for user {0}",
- "UserPolicyUpdatedWithName": "User policy has been updated for {0}",
+ "UserLockedOutWithName": "Pengguna {0} telah dikunci",
+ "UserOfflineFromDevice": "{0} telah terputus dari {1}",
+ "UserOnlineFromDevice": "{0} berada dalam talian dari {1}",
+ "UserPasswordChangedWithName": "Kata laluan telah ditukar bagi pengguna {0}",
+ "UserPolicyUpdatedWithName": "Dasar pengguna telah dikemas kini untuk {0}",
"UserStartedPlayingItemWithValues": "{0} is playing {1} on {2}",
"UserStoppedPlayingItemWithValues": "{0} has finished playing {1} on {2}",
"ValueHasBeenAddedToLibrary": "{0} has been added to your media library",
"ValueSpecialEpisodeName": "Khas - {0}",
- "VersionNumber": "Versi {0}"
+ "VersionNumber": "Versi {0}",
+ "TaskCleanActivityLog": "Log Aktiviti Bersih",
+ "TasksChannelsCategory": "Saluran Internet",
+ "TasksApplicationCategory": "Aplikasi",
+ "TasksLibraryCategory": "Perpustakaan",
+ "TasksMaintenanceCategory": "Penyelenggaraan",
+ "Undefined": "Tidak ditentukan",
+ "Forced": "Paksa",
+ "Default": "Asal",
+ "TaskCleanCache": "Bersihkan Direktori Cache",
+ "TaskCleanActivityLogDescription": "Padamkan entri log aktiviti yang lebih tua daripada usia yang dikonfigurasi."
}
diff --git a/Emby.Server.Implementations/Localization/Core/nb.json b/Emby.Server.Implementations/Localization/Core/nb.json
index d5bca9f6c..fbe1f7c4d 100644
--- a/Emby.Server.Implementations/Localization/Core/nb.json
+++ b/Emby.Server.Implementations/Localization/Core/nb.json
@@ -30,20 +30,20 @@
"ItemAddedWithName": "{0} ble lagt til i biblioteket",
"ItemRemovedWithName": "{0} ble fjernet fra biblioteket",
"LabelIpAddressValue": "IP-adresse: {0}",
- "LabelRunningTimeValue": "Kjøretid {0}",
+ "LabelRunningTimeValue": "Spilletid {0}",
"Latest": "Siste",
- "MessageApplicationUpdated": "Jellyfin Server har blitt oppdatert",
- "MessageApplicationUpdatedTo": "Jellyfin Server ble oppdatert til {0}",
- "MessageNamedServerConfigurationUpdatedWithValue": "Serverkonfigurasjon seksjon {0} har blitt oppdatert",
- "MessageServerConfigurationUpdated": "Serverkonfigurasjon er oppdatert",
+ "MessageApplicationUpdated": "Jellyfin-tjeneren har blitt oppdatert",
+ "MessageApplicationUpdatedTo": "Jellyfin-tjeneren ble oppdatert til {0}",
+ "MessageNamedServerConfigurationUpdatedWithValue": "Tjenerkonfigurasjonsseksjon {0} har blitt oppdatert",
+ "MessageServerConfigurationUpdated": "Tjenerkonfigurasjon er oppdatert",
"MixedContent": "Blandet innhold",
"Movies": "Filmer",
"Music": "Musikk",
"MusicVideos": "Musikkvideoer",
- "NameInstallFailed": "{0}-installasjonen mislyktes",
+ "NameInstallFailed": "Installasjonen av {0} mislyktes",
"NameSeasonNumber": "Sesong {0}",
- "NameSeasonUnknown": "Sesong ukjent",
- "NewVersionIsAvailable": "En ny versjon av Jellyfin Server er tilgjengelig for nedlasting.",
+ "NameSeasonUnknown": "Ukjent sesong",
+ "NewVersionIsAvailable": "En ny versjon av Jellyfin-tjeneren er tilgjengelig for nedlasting.",
"NotificationOptionApplicationUpdateAvailable": "En programvareoppdatering er tilgjengelig",
"NotificationOptionApplicationUpdateInstalled": "Applikasjonsoppdatering installert",
"NotificationOptionAudioPlayback": "Lydavspilling startet",
@@ -51,18 +51,18 @@
"NotificationOptionCameraImageUploaded": "Kamerabilde lastet opp",
"NotificationOptionInstallationFailed": "Installasjonen feilet",
"NotificationOptionNewLibraryContent": "Nytt innhold lagt til",
- "NotificationOptionPluginError": "Pluginfeil",
- "NotificationOptionPluginInstalled": "Plugin installert",
- "NotificationOptionPluginUninstalled": "Plugin avinstallert",
- "NotificationOptionPluginUpdateInstalled": "Pluginoppdatering installert",
- "NotificationOptionServerRestartRequired": "Serveromstart er nødvendig",
+ "NotificationOptionPluginError": "Programvareutvidelsesfeil",
+ "NotificationOptionPluginInstalled": "Programvareutvidelse installert",
+ "NotificationOptionPluginUninstalled": "Programvareutvidelse avinstallert",
+ "NotificationOptionPluginUpdateInstalled": "Programvareutvidelsesoppdatering installert",
+ "NotificationOptionServerRestartRequired": "Tjeneromstart er nødvendig",
"NotificationOptionTaskFailed": "Feil under utføring av planlagt oppgave",
"NotificationOptionUserLockedOut": "Bruker er utestengt",
"NotificationOptionVideoPlayback": "Videoavspilling startet",
"NotificationOptionVideoPlaybackStopped": "Videoavspilling stoppet",
"Photos": "Bilder",
"Playlists": "Spillelister",
- "Plugin": "Plugin",
+ "Plugin": "Programvareutvidelse",
"PluginInstalledWithName": "{0} ble installert",
"PluginUninstalledWithName": "{0} ble avinstallert",
"PluginUpdatedWithName": "{0} ble oppdatert",
@@ -72,7 +72,7 @@
"ServerNameNeedsToBeRestarted": "{0} må startes på nytt",
"Shows": "Program",
"Songs": "Sanger",
- "StartupEmbyServerIsLoading": "Jellyfin Server laster. Prøv igjen snart.",
+ "StartupEmbyServerIsLoading": "Jellyfin-tjener laster. Prøv igjen snart.",
"SubtitleDownloadFailureForItem": "En feil oppstå under nedlasting av undertekster for {0}",
"SubtitleDownloadFailureFromForItem": "Kunne ikke laste ned undertekster fra {0} for {1}",
"Sync": "Synkroniser",
@@ -86,37 +86,37 @@
"UserOfflineFromDevice": "{0} har koblet fra {1}",
"UserOnlineFromDevice": "{0} er tilkoblet fra {1}",
"UserPasswordChangedWithName": "Passordet for {0} er oppdatert",
- "UserPolicyUpdatedWithName": "Brukerpolicyen har blitt oppdatert for {0}",
+ "UserPolicyUpdatedWithName": "Brukerretningslinjene har blitt oppdatert for {0}",
"UserStartedPlayingItemWithValues": "{0} har startet avspilling {1} på {2}",
- "UserStoppedPlayingItemWithValues": "{0} har stoppet avspilling {1}",
+ "UserStoppedPlayingItemWithValues": "{0} har stoppet avspilling {1}",
"ValueHasBeenAddedToLibrary": "{0} har blitt lagt til i mediebiblioteket ditt",
"ValueSpecialEpisodeName": "Spesialepisode - {0}",
"VersionNumber": "Versjon {0}",
- "TasksChannelsCategory": "Internett kanaler",
+ "TasksChannelsCategory": "Internettkanaler",
"TasksApplicationCategory": "Applikasjon",
"TasksLibraryCategory": "Bibliotek",
"TasksMaintenanceCategory": "Vedlikehold",
- "TaskCleanCache": "Tøm buffer katalog",
+ "TaskCleanCache": "Tøm hurtigbuffer",
"TaskRefreshLibrary": "Skann mediebibliotek",
"TaskRefreshChapterImagesDescription": "Lager forhåndsvisningsbilder for videoer som har kapitler.",
- "TaskRefreshChapterImages": "Trekk ut Kapittelbilder",
+ "TaskRefreshChapterImages": "Trekk ut kapittelbilder",
"TaskCleanCacheDescription": "Sletter mellomlagrede filer som ikke lengre trengs av systemet.",
- "TaskDownloadMissingSubtitlesDescription": "Søker etter manglende underteksting på nett basert på metadatakonfigurasjon.",
- "TaskDownloadMissingSubtitles": "Last ned manglende underteksting",
- "TaskRefreshChannelsDescription": "Frisker opp internettkanalinformasjon.",
- "TaskRefreshChannels": "Oppfrisk kanaler",
+ "TaskDownloadMissingSubtitlesDescription": "Søker etter manglende undertekster på nett basert på metadatakonfigurasjon.",
+ "TaskDownloadMissingSubtitles": "Last ned manglende undertekster",
+ "TaskRefreshChannelsDescription": "Oppdaterer internettkanalinformasjon.",
+ "TaskRefreshChannels": "Oppdater kanaler",
"TaskCleanTranscodeDescription": "Sletter omkodede filer som er mer enn én dag gamle.",
"TaskCleanTranscode": "Tøm transkodingmappe",
- "TaskUpdatePluginsDescription": "Laster ned og installerer oppdateringer for utvidelser som er stilt inn til å oppdatere automatisk.",
- "TaskUpdatePlugins": "Oppdater utvidelser",
+ "TaskUpdatePluginsDescription": "Laster ned og installerer oppdateringer for programvareutvidelser som er stilt inn til å oppdatere automatisk.",
+ "TaskUpdatePlugins": "Oppdater programvareutvidelse",
"TaskRefreshPeopleDescription": "Oppdaterer metadata for skuespillere og regissører i mediebiblioteket ditt.",
- "TaskRefreshPeople": "Oppfrisk personer",
+ "TaskRefreshPeople": "Oppdater personer",
"TaskCleanLogsDescription": "Sletter loggfiler som er eldre enn {0} dager gamle.",
"TaskCleanLogs": "Tøm loggmappe",
"TaskRefreshLibraryDescription": "Skanner mediebibliotekene dine for nye filer og oppdaterer metadata.",
"TaskCleanActivityLog": "Tøm aktivitetslogg",
"Undefined": "Udefinert",
- "Forced": "Tvungen",
+ "Forced": "Tvunget",
"Default": "Standard",
"TaskCleanActivityLogDescription": "Sletter oppføringer i aktivitetsloggen som er eldre enn den konfigurerte alderen."
}
diff --git a/Emby.Server.Implementations/Localization/Core/nl.json b/Emby.Server.Implementations/Localization/Core/nl.json
index ffc329e35..2973c8c6e 100644
--- a/Emby.Server.Implementations/Localization/Core/nl.json
+++ b/Emby.Server.Implementations/Localization/Core/nl.json
@@ -3,9 +3,9 @@
"AppDeviceValues": "App: {0}, Apparaat: {1}",
"Application": "Applicatie",
"Artists": "Artiesten",
- "AuthenticationSucceededWithUserName": "{0} is succesvol geverifieerd",
+ "AuthenticationSucceededWithUserName": "{0} is succesvol geauthenticeerd",
"Books": "Boeken",
- "CameraImageUploadedFrom": "Er is een nieuwe camera afbeelding toegevoegd via {0}",
+ "CameraImageUploadedFrom": "Nieuwe camera afbeelding toegevoegd vanaf {0}",
"Channels": "Kanalen",
"ChapterNameValue": "Hoofdstuk {0}",
"Collections": "Verzamelingen",
diff --git a/Emby.Server.Implementations/Localization/Core/nn.json b/Emby.Server.Implementations/Localization/Core/nn.json
index 6236515b2..16511e686 100644
--- a/Emby.Server.Implementations/Localization/Core/nn.json
+++ b/Emby.Server.Implementations/Localization/Core/nn.json
@@ -1,25 +1,25 @@
{
- "MessageServerConfigurationUpdated": "Tenar konfigurasjonen har blitt oppdatert",
+ "MessageServerConfigurationUpdated": "Tenarkonfigurasjonen har blitt oppdatert",
"MessageNamedServerConfigurationUpdatedWithValue": "Tenar konfigurasjon seksjon {0} har blitt oppdatert",
- "MessageApplicationUpdatedTo": "Jellyfin Tenaren har blitt oppdatert til {0}",
- "MessageApplicationUpdated": "Jellyfin Tenaren har blitt oppdatert",
+ "MessageApplicationUpdatedTo": "Jellyfin-tenaren har blitt oppdatert til {0}",
+ "MessageApplicationUpdated": "Jellyfin-tenaren har blitt oppdatert",
"Latest": "Nyaste",
"LabelRunningTimeValue": "Speletid: {0}",
- "LabelIpAddressValue": "IP adresse: {0}",
+ "LabelIpAddressValue": "IP-adresse: {0}",
"ItemRemovedWithName": "{0} vart fjerna frå biblioteket",
"ItemAddedWithName": "{0} vart lagt til i biblioteket",
- "Inherit": "Arv",
- "HomeVideos": "Heime Videoar",
+ "Inherit": "Arve",
+ "HomeVideos": "Heimevideoar",
"HeaderRecordingGroups": "Innspelingsgrupper",
"HeaderNextUp": "Neste",
"HeaderLiveTV": "Direkte TV",
- "HeaderFavoriteSongs": "Favoritt Songar",
- "HeaderFavoriteShows": "Favoritt Seriar",
- "HeaderFavoriteEpisodes": "Favoritt Episodar",
- "HeaderFavoriteArtists": "Favoritt Artistar",
- "HeaderFavoriteAlbums": "Favoritt Album",
+ "HeaderFavoriteSongs": "Favorittsongar",
+ "HeaderFavoriteShows": "Favorittseriar",
+ "HeaderFavoriteEpisodes": "Favorittepisodar",
+ "HeaderFavoriteArtists": "Favorittartistar",
+ "HeaderFavoriteAlbums": "Favorittalbum",
"HeaderContinueWatching": "Fortsett å sjå",
- "HeaderAlbumArtists": "Album Artist",
+ "HeaderAlbumArtists": "Albumartistar",
"Genres": "Sjangrar",
"Folders": "Mapper",
"Favorites": "Favorittar",
@@ -37,10 +37,10 @@
"AppDeviceValues": "App: {0}, Eining: {1}",
"Albums": "Album",
"NotificationOptionServerRestartRequired": "Tenaren krev omstart",
- "NotificationOptionPluginUpdateInstalled": "Tilleggsprogram-oppdatering vart installert",
- "NotificationOptionPluginUninstalled": "Tilleggsprogram avinstallert",
- "NotificationOptionPluginInstalled": "Tilleggsprogram installert",
- "NotificationOptionPluginError": "Tilleggsprogram feila",
+ "NotificationOptionPluginUpdateInstalled": "Programvaretilleggoppdatering vart installert",
+ "NotificationOptionPluginUninstalled": "Programvaretillegg avinstallert",
+ "NotificationOptionPluginInstalled": "Programvaretillegg installert",
+ "NotificationOptionPluginError": "Programvaretillegg feila",
"NotificationOptionNewLibraryContent": "Nytt innhald er lagt til",
"NotificationOptionInstallationFailed": "Installasjonsfeil",
"NotificationOptionCameraImageUploaded": "Kamerabilde vart lasta opp",
@@ -48,33 +48,33 @@
"NotificationOptionAudioPlayback": "Lydavspilling påbyrja",
"NotificationOptionApplicationUpdateInstalled": "Applikasjonsoppdatering er installert",
"NotificationOptionApplicationUpdateAvailable": "Applikasjonsoppdatering er tilgjengeleg",
- "NewVersionIsAvailable": "Ein ny versjon av Jellyfin serveren er tilgjengeleg for nedlasting.",
+ "NewVersionIsAvailable": "Ein ny versjon av Jellyfin-tjenaren er tilgjengeleg for nedlasting.",
"NameSeasonUnknown": "Ukjend sesong",
"NameSeasonNumber": "Sesong {0}",
- "NameInstallFailed": "{0} Installasjonen feila",
+ "NameInstallFailed": "Installasjonen av {0} feila",
"MusicVideos": "Musikkvideoar",
"Music": "Musikk",
"Movies": "Filmar",
"MixedContent": "Blanda innhald",
- "Sync": "Synkronisera",
+ "Sync": "Synkroniser",
"TaskDownloadMissingSubtitlesDescription": "Søk Internettet for manglande undertekstar basert på metadatainnstillingar.",
"TaskDownloadMissingSubtitles": "Last ned manglande undertekstar",
"TaskRefreshChannelsDescription": "Oppdater internettkanalinformasjon.",
"TaskRefreshChannels": "Oppdater kanalar",
- "TaskCleanTranscodeDescription": "Slett transkodefiler som er meir enn ein dag gamal.",
- "TaskCleanTranscode": "Reins transkodemappe",
+ "TaskCleanTranscodeDescription": "Slett transkodefiler som er meir enn ein dag gammal.",
+ "TaskCleanTranscode": "Fjern transkodemappe",
"TaskUpdatePluginsDescription": "Laster ned og installerer oppdateringar for programtillegg som er sette opp til å oppdaterast automatisk.",
- "TaskUpdatePlugins": "Oppdaterer programtillegg",
+ "TaskUpdatePlugins": "Oppdaterer programvaretillegg",
"TaskRefreshPeopleDescription": "Oppdaterer metadata for skodespelarar og regissørar i mediebiblioteket ditt.",
"TaskRefreshPeople": "Oppdater personar",
"TaskCleanLogsDescription": "Slett loggfiler som er meir enn {0} dagar gamle.",
- "TaskCleanLogs": "Reins loggmappe",
+ "TaskCleanLogs": "Slett loggmappa",
"TaskRefreshLibraryDescription": "Skannar mediebiblioteket ditt for nye filer og oppdaterer metadata.",
"TaskRefreshLibrary": "Skann mediebibliotek",
"TaskRefreshChapterImagesDescription": "Lager miniatyrbilete for videoar som har kapittel.",
"TaskRefreshChapterImages": "Trekk ut kapittelbilete",
- "TaskCleanCacheDescription": "Slettar mellomlagra filer som ikkje lengre trengst av systemet.",
- "TaskCleanCache": "Rens mappe for hurtiglager",
+ "TaskCleanCacheDescription": "Sletter mellomlagra filer som ikkje lengre trengst av systemet.",
+ "TaskCleanCache": "Fjern hurtigbuffer",
"TasksChannelsCategory": "Internettkanalar",
"TasksApplicationCategory": "Applikasjon",
"TasksLibraryCategory": "Bibliotek",
@@ -96,7 +96,7 @@
"TvShows": "TV-seriar",
"System": "System",
"SubtitleDownloadFailureFromForItem": "Feila å laste ned undertekstar frå {0} for {1}",
- "StartupEmbyServerIsLoading": "Jellyfintenaren laster. Prøv igjen om litt.",
+ "StartupEmbyServerIsLoading": "Jellyfin-tenaren laster. Prøv igjen seinare.",
"Songs": "Songar",
"Shows": "Program",
"ServerNameNeedsToBeRestarted": "{0} må omstartast",
@@ -106,11 +106,16 @@
"PluginUpdatedWithName": "{0} blei oppdatert",
"PluginUninstalledWithName": "{0} blei avinstallert",
"PluginInstalledWithName": "{0} blei installert",
- "Plugin": "Programtillegg",
+ "Plugin": "Programvaretillegg",
"Playlists": "Speleliste",
- "Photos": "Foto",
+ "Photos": "Bilete",
"NotificationOptionVideoPlaybackStopped": "Videoavspeling stoppa",
"NotificationOptionVideoPlayback": "Videoavspeling starta",
"NotificationOptionUserLockedOut": "Brukar er utestengd",
- "NotificationOptionTaskFailed": "Planlagt oppgåve feila"
+ "NotificationOptionTaskFailed": "Planlagt oppgåve feila",
+ "TaskCleanActivityLogDescription": "Sletter aktivitetslogginnlegg som er eldre enn den konfigurerte alderen.",
+ "TaskCleanActivityLog": "Slett aktivitetslogg",
+ "Undefined": "Udefinert",
+ "Forced": "Tvungen",
+ "Default": "Standard"
}
diff --git a/Emby.Server.Implementations/Localization/Core/pa.json b/Emby.Server.Implementations/Localization/Core/pa.json
index 469fa89b6..d1db09232 100644
--- a/Emby.Server.Implementations/Localization/Core/pa.json
+++ b/Emby.Server.Implementations/Localization/Core/pa.json
@@ -1,5 +1,5 @@
{
- "TaskRefreshChapterImages": "ਐਬਸਟਰੈਕਟ ਅਧਿਆਇ ਅਧਿਆਇ",
+ "TaskRefreshChapterImages": "ਐਕਸਟਰੈਕਟ ਚੈਪਟਰ ਚਿੱਤਰ",
"TaskDownloadMissingSubtitlesDescription": "ਮੈਟਾਡੇਟਾ ਕੌਂਫਿਗਰੇਸ਼ਨ ਦੇ ਅਧਾਰ ਤੇ ਗਾਇਬ ਉਪਸਿਰਲੇਖਾਂ ਲਈ ਇੰਟਰਨੈਟ ਦੀ ਭਾਲ ਕਰਦਾ ਹੈ.",
"TaskDownloadMissingSubtitles": "ਗਾਇਬ ਉਪਸਿਰਲੇਖ ਡਾ Download ਨਲੋਡ ਕਰੋ",
"TaskRefreshChannelsDescription": "ਇੰਟਰਨੈੱਟ ਚੈਨਲ ਦੀ ਜਾਣਕਾਰੀ ਨੂੰ ਤਾਜ਼ਾ ਕਰਦਾ ਹੈ.",
diff --git a/Emby.Server.Implementations/Localization/Core/ru.json b/Emby.Server.Implementations/Localization/Core/ru.json
index 46b47cf4a..e58f8c39d 100644
--- a/Emby.Server.Implementations/Localization/Core/ru.json
+++ b/Emby.Server.Implementations/Localization/Core/ru.json
@@ -39,7 +39,7 @@
"MixedContent": "Смешанное содержимое",
"Movies": "Кино",
"Music": "Музыка",
- "MusicVideos": "Музыкальные клипы",
+ "MusicVideos": "Муз. видео",
"NameInstallFailed": "Установка {0} неудачна",
"NameSeasonNumber": "Сезон {0}",
"NameSeasonUnknown": "Сезон неопознан",
@@ -75,7 +75,7 @@
"StartupEmbyServerIsLoading": "Jellyfin Server загружается. Повторите попытку в ближайшее время.",
"SubtitleDownloadFailureForItem": "Субтитры к {0} не удалось загрузить",
"SubtitleDownloadFailureFromForItem": "Субтитры к {1} не удалось загрузить с {0}",
- "Sync": "Синхронизация",
+ "Sync": "Синхро",
"System": "Система",
"TvShows": "ТВ",
"User": "Пользователь",
diff --git a/Emby.Server.Implementations/Localization/Core/sv.json b/Emby.Server.Implementations/Localization/Core/sv.json
index b5a7fa5b8..d992bf79b 100644
--- a/Emby.Server.Implementations/Localization/Core/sv.json
+++ b/Emby.Server.Implementations/Localization/Core/sv.json
@@ -39,7 +39,7 @@
"MixedContent": "Blandat innehåll",
"Movies": "Filmer",
"Music": "Musik",
- "MusicVideos": "Musikvideos",
+ "MusicVideos": "Musikvideor",
"NameInstallFailed": "{0} installationen misslyckades",
"NameSeasonNumber": "Säsong {0}",
"NameSeasonUnknown": "Okänd säsong",
diff --git a/Emby.Server.Implementations/Localization/Core/ta.json b/Emby.Server.Implementations/Localization/Core/ta.json
index c737ba42b..129986ed0 100644
--- a/Emby.Server.Implementations/Localization/Core/ta.json
+++ b/Emby.Server.Implementations/Localization/Core/ta.json
@@ -69,7 +69,7 @@
"NameSeasonUnknown": "அறியப்படாத பருவம்",
"NameSeasonNumber": "பருவம் {0}",
"NameInstallFailed": "{0} நிறுவல் தோல்வியடைந்தது",
- "MusicVideos": "இசைப்படங்கள்",
+ "MusicVideos": "இசை கானொளி",
"Music": "இசை",
"Movies": "திரைப்படங்கள்",
"Latest": "புதியவை",
diff --git a/Emby.Server.Implementations/Localization/Core/th.json b/Emby.Server.Implementations/Localization/Core/th.json
index 5bf58baf8..e26010423 100644
--- a/Emby.Server.Implementations/Localization/Core/th.json
+++ b/Emby.Server.Implementations/Localization/Core/th.json
@@ -113,5 +113,9 @@
"Sync": "ซิงค์",
"SubtitleDownloadFailureFromForItem": "ไม่สามารถดาวน์โหลดคำบรรยายจาก {0} สำหรับ {1} ได้",
"StartupEmbyServerIsLoading": "กำลังโหลดเซิร์ฟเวอร์ Jellyfin โปรดลองอีกครั้งในอีกสักครู่",
- "Default": "ค่าเริ่มต้น"
+ "Default": "ค่าเริ่มต้น",
+ "TaskCleanActivityLogDescription": "ลบบันทึกกิจกรรมที่เก่ากว่าค่าที่กำหนดไว้",
+ "TaskCleanActivityLog": "ล้างบันทึกกิจกรรม",
+ "Undefined": "ไม่ได้กำหนด",
+ "Forced": "บังคับใช้"
}
diff --git a/Emby.Server.Implementations/Localization/Core/uk.json b/Emby.Server.Implementations/Localization/Core/uk.json
index b6073bf6a..5a2069df5 100644
--- a/Emby.Server.Implementations/Localization/Core/uk.json
+++ b/Emby.Server.Implementations/Localization/Core/uk.json
@@ -1,5 +1,5 @@
{
- "MusicVideos": "Музичні кліпи",
+ "MusicVideos": "Музичні відеокліпи",
"Music": "Музика",
"Movies": "Фільми",
"MessageApplicationUpdatedTo": "Jellyfin Server оновлено до версії {0}",
@@ -113,7 +113,7 @@
"MessageNamedServerConfigurationUpdatedWithValue": "Розділ конфігурації сервера {0} оновлено",
"Inherit": "Успадкувати",
"HeaderRecordingGroups": "Групи запису",
- "Forced": "Примусово",
+ "Forced": "Форсовані",
"TaskCleanActivityLogDescription": "Видаляє старші за встановлений термін записи з журналу активності.",
"TaskCleanActivityLog": "Очистити журнал активності",
"Undefined": "Не визначено",
diff --git a/Emby.Server.Implementations/Localization/Core/zh-TW.json b/Emby.Server.Implementations/Localization/Core/zh-TW.json
index affb0e099..c3b223f63 100644
--- a/Emby.Server.Implementations/Localization/Core/zh-TW.json
+++ b/Emby.Server.Implementations/Localization/Core/zh-TW.json
@@ -37,7 +37,7 @@
"MixedContent": "混合內容",
"Movies": "電影",
"Music": "音樂",
- "MusicVideos": "音樂MV",
+ "MusicVideos": "音樂錄影帶",
"NameInstallFailed": "{0} 安裝失敗",
"NameSeasonNumber": "第 {0} 季",
"NameSeasonUnknown": "未知季數",
diff --git a/Emby.Server.Implementations/Localization/LocalizationManager.cs b/Emby.Server.Implementations/Localization/LocalizationManager.cs
index 2fdc2b4d9..220e423bf 100644
--- a/Emby.Server.Implementations/Localization/LocalizationManager.cs
+++ b/Emby.Server.Implementations/Localization/LocalizationManager.cs
@@ -7,6 +7,7 @@ using System.Linq;
using System.Reflection;
using System.Text.Json;
using System.Threading.Tasks;
+using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.Json;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Model.Entities;
@@ -72,8 +73,7 @@ namespace Emby.Server.Implementations.Localization
using (var str = _assembly.GetManifestResourceStream(resource))
using (var reader = new StreamReader(str))
{
- string line;
- while ((line = await reader.ReadLineAsync().ConfigureAwait(false)) != null)
+ await foreach (var line in reader.ReadAllLinesAsync().ConfigureAwait(false))
{
if (string.IsNullOrWhiteSpace(line))
{
@@ -118,10 +118,8 @@ namespace Emby.Server.Implementations.Localization
using (var stream = _assembly.GetManifestResourceStream(ResourcePath))
using (var reader = new StreamReader(stream))
{
- while (!reader.EndOfStream)
+ await foreach (var line in reader.ReadAllLinesAsync().ConfigureAwait(false))
{
- var line = await reader.ReadLineAsync().ConfigureAwait(false);
-
if (string.IsNullOrWhiteSpace(line))
{
continue;
@@ -179,7 +177,7 @@ namespace Emby.Server.Implementations.Localization
/// <inheritdoc />
public IEnumerable<CountryInfo> GetCountries()
{
- StreamReader reader = new StreamReader(_assembly.GetManifestResourceStream("Emby.Server.Implementations.Localization.countries.json"));
+ using StreamReader reader = new StreamReader(_assembly.GetManifestResourceStream("Emby.Server.Implementations.Localization.countries.json"));
return JsonSerializer.Deserialize<IEnumerable<CountryInfo>>(reader.ReadToEnd(), _jsonOptions);
}
@@ -315,10 +313,9 @@ namespace Emby.Server.Implementations.Localization
}
const string Prefix = "Core";
- var key = Prefix + culture;
return _dictionaries.GetOrAdd(
- key,
+ culture,
f => GetDictionary(Prefix, culture, DefaultCulture + ".json").GetAwaiter().GetResult());
}
diff --git a/Emby.Server.Implementations/Playlists/PlaylistManager.cs b/Emby.Server.Implementations/Playlists/PlaylistManager.cs
index 932f721ab..2d1a559f1 100644
--- a/Emby.Server.Implementations/Playlists/PlaylistManager.cs
+++ b/Emby.Server.Implementations/Playlists/PlaylistManager.cs
@@ -215,7 +215,7 @@ namespace Emby.Server.Implementations.Playlists
// Create a list of the new linked children to add to the playlist
var childrenToAdd = newItems
- .Select(i => LinkedChild.Create(i))
+ .Select(LinkedChild.Create)
.ToList();
// Log duplicates that have been ignored, if any
diff --git a/Emby.Server.Implementations/Plugins/PluginManager.cs b/Emby.Server.Implementations/Plugins/PluginManager.cs
index 3a8296455..14df20936 100644
--- a/Emby.Server.Implementations/Plugins/PluginManager.cs
+++ b/Emby.Server.Implementations/Plugins/PluginManager.cs
@@ -44,12 +44,7 @@ namespace Emby.Server.Implementations.Plugins
{
get
{
- if (_httpClientFactory == null)
- {
- _httpClientFactory = _appHost.Resolve<IHttpClientFactory>();
- }
-
- return _httpClientFactory;
+ return _httpClientFactory ?? (_httpClientFactory = _appHost.Resolve<IHttpClientFactory>());
}
}
@@ -166,9 +161,7 @@ namespace Emby.Server.Implementations.Plugins
/// </summary>
public void CreatePlugins()
{
- _ = _appHost.GetExports<IPlugin>(CreatePluginInstance)
- .Where(i => i != null)
- .ToArray();
+ _ = _appHost.GetExports<IPlugin>(CreatePluginInstance);
}
/// <summary>
@@ -278,11 +271,7 @@ namespace Emby.Server.Implementations.Plugins
// If no version is given, return the current instance.
var plugins = _plugins.Where(p => p.Id.Equals(id)).ToList();
- plugin = plugins.FirstOrDefault(p => p.Instance != null);
- if (plugin == null)
- {
- plugin = plugins.OrderByDescending(p => p.Version).FirstOrDefault();
- }
+ plugin = plugins.FirstOrDefault(p => p.Instance != null) ?? plugins.OrderByDescending(p => p.Version).FirstOrDefault();
}
else
{
diff --git a/Emby.Server.Implementations/QuickConnect/QuickConnectManager.cs b/Emby.Server.Implementations/QuickConnect/QuickConnectManager.cs
index 22739a008..0259dc436 100644
--- a/Emby.Server.Implementations/QuickConnect/QuickConnectManager.cs
+++ b/Emby.Server.Implementations/QuickConnect/QuickConnectManager.cs
@@ -257,20 +257,17 @@ namespace Emby.Server.Implementations.QuickConnect
}
// Expire stale connection requests
- var code = string.Empty;
- var values = _currentRequests.Values.ToList();
-
- for (int i = 0; i < values.Count; i++)
+ foreach (var (_, currentRequest) in _currentRequests)
{
- var added = values[i].DateAdded ?? DateTime.UnixEpoch;
- if (DateTime.UtcNow > added.AddMinutes(Timeout) || expireAll)
+ var added = currentRequest.DateAdded ?? DateTime.UnixEpoch;
+ if (expireAll || DateTime.UtcNow > added.AddMinutes(Timeout))
{
- code = values[i].Code;
- _logger.LogDebug("Removing expired request {code}", code);
+ var code = currentRequest.Code;
+ _logger.LogDebug("Removing expired request {Code}", code);
if (!_currentRequests.TryRemove(code, out _))
{
- _logger.LogWarning("Request {code} already expired", code);
+ _logger.LogWarning("Request {Code} already expired", code);
}
}
}
diff --git a/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs b/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs
index 9c0e92705..101d9b537 100644
--- a/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs
+++ b/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs
@@ -301,12 +301,7 @@ namespace Emby.Server.Implementations.ScheduledTasks
{
get
{
- if (_id == null)
- {
- _id = ScheduledTask.GetType().FullName.GetMD5().ToString("N", CultureInfo.InvariantCulture);
- }
-
- return _id;
+ return _id ??= ScheduledTask.GetType().FullName.GetMD5().ToString("N", CultureInfo.InvariantCulture);
}
}
@@ -348,9 +343,7 @@ namespace Emby.Server.Implementations.ScheduledTasks
{
var trigger = (ITaskTrigger)sender;
- var configurableTask = ScheduledTask as IConfigurableScheduledTask;
-
- if (configurableTask != null && !configurableTask.IsEnabled)
+ if (ScheduledTask is IConfigurableScheduledTask configurableTask && !configurableTask.IsEnabled)
{
return;
}
diff --git a/Emby.Server.Implementations/Session/SessionManager.cs b/Emby.Server.Implementations/Session/SessionManager.cs
index 6f21ec31e..6844152ea 100644
--- a/Emby.Server.Implementations/Session/SessionManager.cs
+++ b/Emby.Server.Implementations/Session/SessionManager.cs
@@ -1475,10 +1475,7 @@ namespace Emby.Server.Implementations.Session
user = _userManager.GetUserById(request.UserId);
}
- if (user == null)
- {
- user = _userManager.GetUserByName(request.Username);
- }
+ user ??= _userManager.GetUserByName(request.Username);
if (enforcePassword)
{
diff --git a/Emby.Server.Implementations/SyncPlay/SyncPlayManager.cs b/Emby.Server.Implementations/SyncPlay/SyncPlayManager.cs
index aee959c53..72c0a838e 100644
--- a/Emby.Server.Implementations/SyncPlay/SyncPlayManager.cs
+++ b/Emby.Server.Implementations/SyncPlay/SyncPlayManager.cs
@@ -87,7 +87,7 @@ namespace Emby.Server.Implementations.SyncPlay
_sessionManager = sessionManager;
_libraryManager = libraryManager;
_logger = loggerFactory.CreateLogger<SyncPlayManager>();
- _sessionManager.SessionControllerConnected += OnSessionControllerConnected;
+ _sessionManager.SessionEnded += OnSessionEnded;
}
/// <inheritdoc />
@@ -269,14 +269,17 @@ namespace Emby.Server.Implementations.SyncPlay
var user = _userManager.GetUserById(session.UserId);
List<GroupInfoDto> list = new List<GroupInfoDto>();
- foreach (var group in _groups.Values)
+ lock (_groupsLock)
{
- // Locking required as group is not thread-safe.
- lock (group)
+ foreach (var (_, group) in _groups)
{
- if (group.HasAccessToPlayQueue(user))
+ // Locking required as group is not thread-safe.
+ lock (group)
{
- list.Add(group.GetInfo());
+ if (group.HasAccessToPlayQueue(user))
+ {
+ list.Add(group.GetInfo());
+ }
}
}
}
@@ -352,18 +355,18 @@ namespace Emby.Server.Implementations.SyncPlay
return;
}
- _sessionManager.SessionControllerConnected -= OnSessionControllerConnected;
+ _sessionManager.SessionEnded -= OnSessionEnded;
_disposed = true;
}
- private void OnSessionControllerConnected(object sender, SessionEventArgs e)
+ private void OnSessionEnded(object sender, SessionEventArgs e)
{
var session = e.SessionInfo;
if (_sessionToGroupMap.TryGetValue(session.Id, out var group))
{
- var request = new JoinGroupRequest(group.GroupId);
- JoinGroup(session, request, CancellationToken.None);
+ var leaveGroupRequest = new LeaveGroupRequest();
+ LeaveGroup(session, leaveGroupRequest, CancellationToken.None);
}
}
diff --git a/Emby.Server.Implementations/TV/TVSeriesManager.cs b/Emby.Server.Implementations/TV/TVSeriesManager.cs
index d3f6fa34d..829df64bf 100644
--- a/Emby.Server.Implementations/TV/TVSeriesManager.cs
+++ b/Emby.Server.Implementations/TV/TVSeriesManager.cs
@@ -43,9 +43,7 @@ namespace Emby.Server.Implementations.TV
string presentationUniqueKey = null;
if (!string.IsNullOrEmpty(request.SeriesId))
{
- var series = _libraryManager.GetItemById(request.SeriesId) as Series;
-
- if (series != null)
+ if (_libraryManager.GetItemById(request.SeriesId) is Series series)
{
presentationUniqueKey = GetUniqueSeriesKey(series);
}
@@ -95,9 +93,7 @@ namespace Emby.Server.Implementations.TV
int? limit = null;
if (!string.IsNullOrEmpty(request.SeriesId))
{
- var series = _libraryManager.GetItemById(request.SeriesId) as Series;
-
- if (series != null)
+ if (_libraryManager.GetItemById(request.SeriesId) is Series series)
{
presentationUniqueKey = GetUniqueSeriesKey(series);
limit = 1;
diff --git a/Jellyfin.Api/Auth/BaseAuthorizationHandler.cs b/Jellyfin.Api/Auth/BaseAuthorizationHandler.cs
index 7d68aecf9..392498c53 100644
--- a/Jellyfin.Api/Auth/BaseAuthorizationHandler.cs
+++ b/Jellyfin.Api/Auth/BaseAuthorizationHandler.cs
@@ -77,8 +77,9 @@ namespace Jellyfin.Api.Auth
return false;
}
- var ip = _httpContextAccessor.HttpContext.GetNormalizedRemoteIp();
- var isInLocalNetwork = _networkManager.IsInLocalNetwork(ip);
+ var isInLocalNetwork = _httpContextAccessor.HttpContext != null
+ && _networkManager.IsInLocalNetwork(_httpContextAccessor.HttpContext.GetNormalizedRemoteIp());
+
// User cannot access remotely and user is remote
if (!user.HasPermission(PermissionKind.EnableRemoteAccess) && !isInLocalNetwork)
{
diff --git a/Jellyfin.Api/Controllers/ConfigurationController.cs b/Jellyfin.Api/Controllers/ConfigurationController.cs
index 049a4bed7..b6309baab 100644
--- a/Jellyfin.Api/Controllers/ConfigurationController.cs
+++ b/Jellyfin.Api/Controllers/ConfigurationController.cs
@@ -1,3 +1,4 @@
+using System;
using System.ComponentModel.DataAnnotations;
using System.Net.Mime;
using System.Text.Json;
@@ -94,6 +95,11 @@ namespace Jellyfin.Api.Controllers
{
var configurationType = _configurationManager.GetConfigurationType(key);
var configuration = await JsonSerializer.DeserializeAsync(Request.Body, configurationType, _serializerOptions).ConfigureAwait(false);
+ if (configuration == null)
+ {
+ throw new ArgumentException("Body doesn't contain a valid configuration");
+ }
+
_configurationManager.SaveConfiguration(key, configuration);
return NoContent();
}
diff --git a/Jellyfin.Api/Controllers/ItemLookupController.cs b/Jellyfin.Api/Controllers/ItemLookupController.cs
index dabd4deb7..9fa307858 100644
--- a/Jellyfin.Api/Controllers/ItemLookupController.cs
+++ b/Jellyfin.Api/Controllers/ItemLookupController.cs
@@ -238,48 +238,6 @@ namespace Jellyfin.Api.Controllers
}
/// <summary>
- /// Gets a remote image.
- /// </summary>
- /// <param name="imageUrl">The image url.</param>
- /// <param name="providerName">The provider name.</param>
- /// <response code="200">Remote image retrieved.</response>
- /// <returns>
- /// A <see cref="Task" /> that represents the asynchronous operation to get the remote search results.
- /// The task result contains an <see cref="FileStreamResult"/> containing the images file stream.
- /// </returns>
- [HttpGet("Items/RemoteSearch/Image")]
- [ProducesResponseType(StatusCodes.Status200OK)]
- [ProducesImageFile]
- public async Task<ActionResult> GetRemoteSearchImage(
- [FromQuery, Required] string imageUrl,
- [FromQuery, Required] string providerName)
- {
- var urlHash = imageUrl.GetMD5();
- var pointerCachePath = GetFullCachePath(urlHash.ToString());
-
- try
- {
- var contentPath = await System.IO.File.ReadAllTextAsync(pointerCachePath).ConfigureAwait(false);
- if (System.IO.File.Exists(contentPath))
- {
- return PhysicalFile(contentPath, MimeTypes.GetMimeType(contentPath));
- }
- }
- catch (FileNotFoundException)
- {
- // Means the file isn't cached yet
- }
- catch (IOException)
- {
- // Means the file isn't cached yet
- }
-
- await DownloadImage(providerName, imageUrl, urlHash, pointerCachePath).ConfigureAwait(false);
- var updatedContentPath = await System.IO.File.ReadAllTextAsync(pointerCachePath).ConfigureAwait(false);
- return PhysicalFile(updatedContentPath, MimeTypes.GetMimeType(updatedContentPath));
- }
-
- /// <summary>
/// Applies search criteria to an item and refreshes metadata.
/// </summary>
/// <param name="itemId">Item id.</param>
@@ -320,54 +278,5 @@ namespace Jellyfin.Api.Controllers
return NoContent();
}
-
- /// <summary>
- /// Downloads the image.
- /// </summary>
- /// <param name="providerName">Name of the provider.</param>
- /// <param name="url">The URL.</param>
- /// <param name="urlHash">The URL hash.</param>
- /// <param name="pointerCachePath">The pointer cache path.</param>
- /// <returns>Task.</returns>
- private async Task DownloadImage(string providerName, string url, Guid urlHash, string pointerCachePath)
- {
- using var result = await _providerManager.GetSearchImage(providerName, url, CancellationToken.None).ConfigureAwait(false);
- if (result.Content.Headers.ContentType?.MediaType == null)
- {
- throw new ResourceNotFoundException(nameof(result.Content.Headers.ContentType));
- }
-
- var ext = result.Content.Headers.ContentType.MediaType.Split('/')[^1];
- var fullCachePath = GetFullCachePath(urlHash + "." + ext);
-
- var directory = Path.GetDirectoryName(fullCachePath) ?? throw new ResourceNotFoundException($"Provided path ({fullCachePath}) is not valid.");
- Directory.CreateDirectory(directory);
- using (var stream = result.Content)
- {
- // use FileShare.None as this bypasses dotnet bug dotnet/runtime#42790 .
- await using var fileStream = new FileStream(
- fullCachePath,
- FileMode.Create,
- FileAccess.Write,
- FileShare.None,
- IODefaults.FileStreamBufferSize,
- true);
-
- await stream.CopyToAsync(fileStream).ConfigureAwait(false);
- }
-
- var pointerCacheDirectory = Path.GetDirectoryName(pointerCachePath) ?? throw new ArgumentException($"Provided path ({pointerCachePath}) is not valid.", nameof(pointerCachePath));
-
- Directory.CreateDirectory(pointerCacheDirectory);
- await System.IO.File.WriteAllTextAsync(pointerCachePath, fullCachePath).ConfigureAwait(false);
- }
-
- /// <summary>
- /// Gets the full cache path.
- /// </summary>
- /// <param name="filename">The filename.</param>
- /// <returns>System.String.</returns>
- private string GetFullCachePath(string filename)
- => Path.Combine(_appPaths.CachePath, "remote-images", filename.Substring(0, 1), filename);
}
}
diff --git a/Jellyfin.Api/Controllers/LibraryController.cs b/Jellyfin.Api/Controllers/LibraryController.cs
index 1d4bbe61e..4ed15e1d5 100644
--- a/Jellyfin.Api/Controllers/LibraryController.cs
+++ b/Jellyfin.Api/Controllers/LibraryController.cs
@@ -600,7 +600,7 @@ namespace Jellyfin.Api.Controllers
{
foreach (var item in dto.Updates)
{
- _libraryMonitor.ReportFileSystemChanged(item.Path);
+ _libraryMonitor.ReportFileSystemChanged(item.Path ?? throw new ArgumentException("Item path can't be null."));
}
return NoContent();
diff --git a/Jellyfin.Api/Controllers/MoviesController.cs b/Jellyfin.Api/Controllers/MoviesController.cs
index d0a2358ae..010a3b19a 100644
--- a/Jellyfin.Api/Controllers/MoviesController.cs
+++ b/Jellyfin.Api/Controllers/MoviesController.cs
@@ -18,6 +18,7 @@ using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Querying;
using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace Jellyfin.Api.Controllers
@@ -300,9 +301,8 @@ namespace Jellyfin.Api.Controllers
private IEnumerable<string> GetActors(IEnumerable<BaseItem> items)
{
- var people = _libraryManager.GetPeople(new InternalPeopleQuery
+ var people = _libraryManager.GetPeople(new InternalPeopleQuery(Array.Empty<string>(), new[] { PersonType.Director })
{
- ExcludePersonTypes = new[] { PersonType.Director },
MaxListOrder = 3
});
@@ -316,10 +316,9 @@ namespace Jellyfin.Api.Controllers
private IEnumerable<string> GetDirectors(IEnumerable<BaseItem> items)
{
- var people = _libraryManager.GetPeople(new InternalPeopleQuery
- {
- PersonTypes = new[] { PersonType.Director }
- });
+ var people = _libraryManager.GetPeople(new InternalPeopleQuery(
+ new[] { PersonType.Director },
+ Array.Empty<string>()));
var itemIds = items.Select(i => i.Id).ToList();
diff --git a/Jellyfin.Api/Controllers/PersonsController.cs b/Jellyfin.Api/Controllers/PersonsController.cs
index 70a94e27c..b98307f87 100644
--- a/Jellyfin.Api/Controllers/PersonsController.cs
+++ b/Jellyfin.Api/Controllers/PersonsController.cs
@@ -94,10 +94,10 @@ namespace Jellyfin.Api.Controllers
}
var isFavoriteInFilters = filters.Any(f => f == ItemFilter.IsFavorite);
- var peopleItems = _libraryManager.GetPeopleItems(new InternalPeopleQuery
+ var peopleItems = _libraryManager.GetPeopleItems(new InternalPeopleQuery(
+ personTypes,
+ excludePersonTypes)
{
- PersonTypes = personTypes,
- ExcludePersonTypes = excludePersonTypes,
NameContains = searchTerm,
User = user,
IsFavorite = !isFavorite.HasValue && isFavoriteInFilters ? true : isFavorite,
diff --git a/Jellyfin.Api/Controllers/PluginsController.cs b/Jellyfin.Api/Controllers/PluginsController.cs
index adec86a10..7a6130719 100644
--- a/Jellyfin.Api/Controllers/PluginsController.cs
+++ b/Jellyfin.Api/Controllers/PluginsController.cs
@@ -207,12 +207,7 @@ namespace Jellyfin.Api.Controllers
var plugins = _pluginManager.Plugins.Where(p => p.Id.Equals(pluginId));
// Select the un-instanced one first.
- var plugin = plugins.FirstOrDefault(p => p.Instance == null);
- if (plugin == null)
- {
- // Then by the status.
- plugin = plugins.OrderBy(p => p.Manifest.Status).FirstOrDefault();
- }
+ var plugin = plugins.FirstOrDefault(p => p.Instance == null) ?? plugins.OrderBy(p => p.Manifest.Status).FirstOrDefault();
if (plugin != null)
{
diff --git a/Jellyfin.Api/Controllers/RemoteImageController.cs b/Jellyfin.Api/Controllers/RemoteImageController.cs
index e226adc64..ec836f43e 100644
--- a/Jellyfin.Api/Controllers/RemoteImageController.cs
+++ b/Jellyfin.Api/Controllers/RemoteImageController.cs
@@ -146,58 +146,6 @@ namespace Jellyfin.Api.Controllers
}
/// <summary>
- /// Gets a remote image.
- /// </summary>
- /// <param name="imageUrl">The image url.</param>
- /// <response code="200">Remote image returned.</response>
- /// <response code="404">Remote image not found.</response>
- /// <returns>Image Stream.</returns>
- [HttpGet("Images/Remote")]
- [Produces(MediaTypeNames.Application.Octet)]
- [ProducesResponseType(StatusCodes.Status200OK)]
- [ProducesResponseType(StatusCodes.Status404NotFound)]
- [ProducesImageFile]
- public async Task<ActionResult> GetRemoteImage([FromQuery, Required] Uri imageUrl)
- {
- var urlHash = imageUrl.ToString().GetMD5();
- var pointerCachePath = GetFullCachePath(urlHash.ToString());
-
- string? contentPath = null;
- var hasFile = false;
-
- try
- {
- contentPath = await System.IO.File.ReadAllTextAsync(pointerCachePath).ConfigureAwait(false);
- if (System.IO.File.Exists(contentPath))
- {
- hasFile = true;
- }
- }
- catch (FileNotFoundException)
- {
- // The file isn't cached yet
- }
- catch (IOException)
- {
- // The file isn't cached yet
- }
-
- if (!hasFile)
- {
- await DownloadImage(imageUrl, urlHash, pointerCachePath).ConfigureAwait(false);
- contentPath = await System.IO.File.ReadAllTextAsync(pointerCachePath).ConfigureAwait(false);
- }
-
- if (string.IsNullOrEmpty(contentPath))
- {
- return NotFound();
- }
-
- var contentType = MimeTypes.GetMimeType(contentPath);
- return PhysicalFile(contentPath, contentType);
- }
-
- /// <summary>
/// Downloads a remote image for an item.
/// </summary>
/// <param name="itemId">Item Id.</param>
diff --git a/Jellyfin.Api/Controllers/SearchController.cs b/Jellyfin.Api/Controllers/SearchController.cs
index 6c22050a7..73bdf9018 100644
--- a/Jellyfin.Api/Controllers/SearchController.cs
+++ b/Jellyfin.Api/Controllers/SearchController.cs
@@ -228,10 +228,7 @@ namespace Jellyfin.Api.Controllers
itemWithImage = GetParentWithImage<Series>(item, ImageType.Thumb);
}
- if (itemWithImage == null)
- {
- itemWithImage = GetParentWithImage<BaseItem>(item, ImageType.Thumb);
- }
+ itemWithImage ??= GetParentWithImage<BaseItem>(item, ImageType.Thumb);
if (itemWithImage != null)
{
diff --git a/Jellyfin.Api/Controllers/UniversalAudioController.cs b/Jellyfin.Api/Controllers/UniversalAudioController.cs
index dcdd8b367..679f055bc 100644
--- a/Jellyfin.Api/Controllers/UniversalAudioController.cs
+++ b/Jellyfin.Api/Controllers/UniversalAudioController.cs
@@ -298,9 +298,9 @@ namespace Jellyfin.Api.Controllers
{
Type = DlnaProfileType.Audio,
Context = EncodingContext.Streaming,
- Container = transcodingContainer,
- AudioCodec = audioCodec,
- Protocol = transcodingProtocol,
+ Container = transcodingContainer ?? "mp3",
+ AudioCodec = audioCodec ?? "mp3",
+ Protocol = transcodingProtocol ?? "http",
BreakOnNonKeyFrames = breakOnNonKeyFrames ?? false,
MaxAudioChannels = transcodingAudioChannels?.ToString(CultureInfo.InvariantCulture)
}
diff --git a/Jellyfin.Api/Controllers/VideosController.cs b/Jellyfin.Api/Controllers/VideosController.cs
index 8dbb6aaa5..e544d001e 100644
--- a/Jellyfin.Api/Controllers/VideosController.cs
+++ b/Jellyfin.Api/Controllers/VideosController.cs
@@ -527,7 +527,7 @@ namespace Jellyfin.Api.Controllers
/// <param name="deviceProfileId">Optional. The dlna device profile id to utilize.</param>
/// <param name="playSessionId">The play session id.</param>
/// <param name="segmentContainer">The segment container.</param>
- /// <param name="segmentLength">The segment lenght.</param>
+ /// <param name="segmentLength">The segment length.</param>
/// <param name="minSegments">The minimum number of segments.</param>
/// <param name="mediaSourceId">The media version id, if playing an alternate version.</param>
/// <param name="deviceId">The device id of the client requesting. Used to stop encoding processes when needed.</param>
@@ -556,7 +556,7 @@ namespace Jellyfin.Api.Controllers
/// <param name="maxVideoBitDepth">Optional. The maximum video bit depth.</param>
/// <param name="requireAvc">Optional. Whether to require avc.</param>
/// <param name="deInterlace">Optional. Whether to deinterlace the video.</param>
- /// <param name="requireNonAnamorphic">Optional. Whether to require a non anamporphic stream.</param>
+ /// <param name="requireNonAnamorphic">Optional. Whether to require a non anamorphic stream.</param>
/// <param name="transcodingMaxAudioChannels">Optional. The maximum number of audio channels to transcode.</param>
/// <param name="cpuCoreLimit">Optional. The limit of how many cpu cores to use.</param>
/// <param name="liveStreamId">The live stream id.</param>
@@ -570,8 +570,8 @@ namespace Jellyfin.Api.Controllers
/// <param name="streamOptions">Optional. The streaming options.</param>
/// <response code="200">Video stream returned.</response>
/// <returns>A <see cref="FileResult"/> containing the audio file.</returns>
- [HttpGet("{itemId}/{stream=stream}.{container}")]
- [HttpHead("{itemId}/{stream=stream}.{container}", Name = "HeadVideoStreamByContainer")]
+ [HttpGet("{itemId}/stream.{container}")]
+ [HttpHead("{itemId}/stream.{container}", Name = "HeadVideoStreamByContainer")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesVideoFile]
public Task<ActionResult> GetVideoStreamByContainer(
diff --git a/Jellyfin.Api/Helpers/HlsHelpers.cs b/Jellyfin.Api/Helpers/HlsHelpers.cs
index 18e23fb5c..d0666034e 100644
--- a/Jellyfin.Api/Helpers/HlsHelpers.cs
+++ b/Jellyfin.Api/Helpers/HlsHelpers.cs
@@ -118,10 +118,7 @@ namespace Jellyfin.Api.Helpers
/// <returns>The playlist text as a string.</returns>
public static string GetLivePlaylistText(string path, StreamState state)
{
- using var stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
- using var reader = new StreamReader(stream);
-
- var text = reader.ReadToEnd();
+ var text = File.ReadAllText(path);
var segmentFormat = EncodingHelper.GetSegmentFileExtension(state.Request.SegmentContainer).TrimStart('.');
if (string.Equals(segmentFormat, "mp4", StringComparison.OrdinalIgnoreCase))
diff --git a/Jellyfin.Api/Helpers/ProgressiveFileCopier.cs b/Jellyfin.Api/Helpers/ProgressiveFileCopier.cs
index 8bddf00d5..963e17724 100644
--- a/Jellyfin.Api/Helpers/ProgressiveFileCopier.cs
+++ b/Jellyfin.Api/Helpers/ProgressiveFileCopier.cs
@@ -71,7 +71,8 @@ namespace Jellyfin.Api.Helpers
/// <returns>A <see cref="Task"/>.</returns>
public async Task WriteToAsync(Stream outputStream, CancellationToken cancellationToken)
{
- cancellationToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, _cancellationToken).Token;
+ using var linkedCancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, _cancellationToken);
+ cancellationToken = linkedCancellationTokenSource.Token;
try
{
diff --git a/Jellyfin.Api/Helpers/StreamingHelpers.cs b/Jellyfin.Api/Helpers/StreamingHelpers.cs
index 9218cb202..8cffe9c4c 100644
--- a/Jellyfin.Api/Helpers/StreamingHelpers.cs
+++ b/Jellyfin.Api/Helpers/StreamingHelpers.cs
@@ -116,14 +116,14 @@ namespace Jellyfin.Api.Helpers
if (!string.IsNullOrWhiteSpace(streamingRequest.AudioCodec))
{
state.SupportedAudioCodecs = streamingRequest.AudioCodec.Split(',', StringSplitOptions.RemoveEmptyEntries);
- state.Request.AudioCodec = state.SupportedAudioCodecs.FirstOrDefault(i => mediaEncoder.CanEncodeToAudioCodec(i))
+ state.Request.AudioCodec = state.SupportedAudioCodecs.FirstOrDefault(mediaEncoder.CanEncodeToAudioCodec)
?? state.SupportedAudioCodecs.FirstOrDefault();
}
if (!string.IsNullOrWhiteSpace(streamingRequest.SubtitleCodec))
{
state.SupportedSubtitleCodecs = streamingRequest.SubtitleCodec.Split(',', StringSplitOptions.RemoveEmptyEntries);
- state.Request.SubtitleCodec = state.SupportedSubtitleCodecs.FirstOrDefault(i => mediaEncoder.CanEncodeToSubtitleCodec(i))
+ state.Request.SubtitleCodec = state.SupportedSubtitleCodecs.FirstOrDefault(mediaEncoder.CanEncodeToSubtitleCodec)
?? state.SupportedSubtitleCodecs.FirstOrDefault();
}
@@ -292,10 +292,7 @@ namespace Jellyfin.Api.Helpers
}
}
- if (profile == null)
- {
- profile = dlnaManager.GetDefaultProfile();
- }
+ profile ??= dlnaManager.GetDefaultProfile();
var audioCodec = state.ActualOutputAudioCodec;
diff --git a/Jellyfin.Api/Jellyfin.Api.csproj b/Jellyfin.Api/Jellyfin.Api.csproj
index 3868882e5..c10c34b59 100644
--- a/Jellyfin.Api/Jellyfin.Api.csproj
+++ b/Jellyfin.Api/Jellyfin.Api.csproj
@@ -17,8 +17,8 @@
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Authorization" Version="5.0.5" />
<PackageReference Include="Microsoft.Extensions.Http" Version="5.0.0" />
- <PackageReference Include="Swashbuckle.AspNetCore" Version="6.1.3" />
- <PackageReference Include="Swashbuckle.AspNetCore.ReDoc" Version="6.1.3" />
+ <PackageReference Include="Swashbuckle.AspNetCore" Version="6.1.4" />
+ <PackageReference Include="Swashbuckle.AspNetCore.ReDoc" Version="6.1.4" />
</ItemGroup>
<ItemGroup>
diff --git a/Jellyfin.Data/Entities/AccessSchedule.cs b/Jellyfin.Data/Entities/AccessSchedule.cs
index 7974d3add..befc4ca02 100644
--- a/Jellyfin.Data/Entities/AccessSchedule.cs
+++ b/Jellyfin.Data/Entities/AccessSchedule.cs
@@ -26,20 +26,20 @@ namespace Jellyfin.Data.Entities
}
/// <summary>
- /// Gets or sets the id of this instance.
+ /// Gets the id of this instance.
/// </summary>
/// <remarks>
/// Identity, Indexed, Required.
/// </remarks>
[XmlIgnore]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
- public int Id { get; protected set; }
+ public int Id { get; private set; }
/// <summary>
- /// Gets or sets the id of the associated user.
+ /// Gets the id of the associated user.
/// </summary>
[XmlIgnore]
- public Guid UserId { get; protected set; }
+ public Guid UserId { get; private set; }
/// <summary>
/// Gets or sets the day of week.
diff --git a/Jellyfin.Data/Entities/ActivityLog.cs b/Jellyfin.Data/Entities/ActivityLog.cs
index e4534e8b5..1d1b86552 100644
--- a/Jellyfin.Data/Entities/ActivityLog.cs
+++ b/Jellyfin.Data/Entities/ActivityLog.cs
@@ -38,11 +38,10 @@ namespace Jellyfin.Data.Entities
}
/// <summary>
- /// Gets or sets the identity of this instance.
- /// This is the key in the backing database.
+ /// Gets the identity of this instance.
/// </summary>
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
- public int Id { get; protected set; }
+ public int Id { get; private set; }
/// <summary>
/// Gets or sets the name.
@@ -120,7 +119,7 @@ namespace Jellyfin.Data.Entities
/// <inheritdoc />
[ConcurrencyCheck]
- public uint RowVersion { get; set; }
+ public uint RowVersion { get; private set; }
/// <inheritdoc />
public void OnSavingChanges()
diff --git a/Jellyfin.Data/Entities/CustomItemDisplayPreferences.cs b/Jellyfin.Data/Entities/CustomItemDisplayPreferences.cs
index de37fb544..b07b7c731 100644
--- a/Jellyfin.Data/Entities/CustomItemDisplayPreferences.cs
+++ b/Jellyfin.Data/Entities/CustomItemDisplayPreferences.cs
@@ -27,13 +27,13 @@ namespace Jellyfin.Data.Entities
}
/// <summary>
- /// Gets or sets the Id.
+ /// Gets the Id.
/// </summary>
/// <remarks>
/// Required.
/// </remarks>
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
- public int Id { get; protected set; }
+ public int Id { get; private set; }
/// <summary>
/// Gets or sets the user Id.
diff --git a/Jellyfin.Data/Entities/DisplayPreferences.cs b/Jellyfin.Data/Entities/DisplayPreferences.cs
index 64cd6812a..646961238 100644
--- a/Jellyfin.Data/Entities/DisplayPreferences.cs
+++ b/Jellyfin.Data/Entities/DisplayPreferences.cs
@@ -1,6 +1,4 @@
-#pragma warning disable CA2227
-
-using System;
+using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
@@ -35,13 +33,13 @@ namespace Jellyfin.Data.Entities
}
/// <summary>
- /// Gets or sets the Id.
+ /// Gets the Id.
/// </summary>
/// <remarks>
/// Required.
/// </remarks>
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
- public int Id { get; protected set; }
+ public int Id { get; private set; }
/// <summary>
/// Gets or sets the user Id.
@@ -145,8 +143,8 @@ namespace Jellyfin.Data.Entities
public string? TvHome { get; set; }
/// <summary>
- /// Gets or sets the home sections.
+ /// Gets the home sections.
/// </summary>
- public virtual ICollection<HomeSection> HomeSections { get; protected set; }
+ public virtual ICollection<HomeSection> HomeSections { get; private set; }
}
}
diff --git a/Jellyfin.Data/Entities/Group.cs b/Jellyfin.Data/Entities/Group.cs
index b14e22b7b..14da0bb15 100644
--- a/Jellyfin.Data/Entities/Group.cs
+++ b/Jellyfin.Data/Entities/Group.cs
@@ -1,5 +1,3 @@
-#pragma warning disable CA2227
-
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
@@ -33,12 +31,12 @@ namespace Jellyfin.Data.Entities
}
/// <summary>
- /// Gets or sets the id of this group.
+ /// Gets the id of this group.
/// </summary>
/// <remarks>
/// Identity, Indexed, Required.
/// </remarks>
- public Guid Id { get; protected set; }
+ public Guid Id { get; private set; }
/// <summary>
/// Gets or sets the group's name.
@@ -52,17 +50,17 @@ namespace Jellyfin.Data.Entities
/// <inheritdoc />
[ConcurrencyCheck]
- public uint RowVersion { get; set; }
+ public uint RowVersion { get; private set; }
/// <summary>
- /// Gets or sets a collection containing the group's permissions.
+ /// Gets a collection containing the group's permissions.
/// </summary>
- public virtual ICollection<Permission> Permissions { get; protected set; }
+ public virtual ICollection<Permission> Permissions { get; private set; }
/// <summary>
- /// Gets or sets a collection containing the group's preferences.
+ /// Gets a collection containing the group's preferences.
/// </summary>
- public virtual ICollection<Preference> Preferences { get; protected set; }
+ public virtual ICollection<Preference> Preferences { get; private set; }
/// <inheritdoc/>
public bool HasPermission(PermissionKind kind)
diff --git a/Jellyfin.Data/Entities/HomeSection.cs b/Jellyfin.Data/Entities/HomeSection.cs
index d03d0f7a8..e194aa537 100644
--- a/Jellyfin.Data/Entities/HomeSection.cs
+++ b/Jellyfin.Data/Entities/HomeSection.cs
@@ -9,13 +9,13 @@ namespace Jellyfin.Data.Entities
public class HomeSection
{
/// <summary>
- /// Gets or sets the id.
+ /// Gets the id.
/// </summary>
/// <remarks>
/// Identity. Required.
/// </remarks>
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
- public int Id { get; protected set; }
+ public int Id { get; private set; }
/// <summary>
/// Gets or sets the Id of the associated display preferences.
diff --git a/Jellyfin.Data/Entities/ImageInfo.cs b/Jellyfin.Data/Entities/ImageInfo.cs
index e0c37047d..b5c7a1c12 100644
--- a/Jellyfin.Data/Entities/ImageInfo.cs
+++ b/Jellyfin.Data/Entities/ImageInfo.cs
@@ -20,18 +20,18 @@ namespace Jellyfin.Data.Entities
}
/// <summary>
- /// Gets or sets the id.
+ /// Gets the id.
/// </summary>
/// <remarks>
/// Identity, Indexed, Required.
/// </remarks>
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
- public int Id { get; protected set; }
+ public int Id { get; private set; }
/// <summary>
- /// Gets or sets the user id.
+ /// Gets the user id.
/// </summary>
- public Guid? UserId { get; protected set; }
+ public Guid? UserId { get; private set; }
/// <summary>
/// Gets or sets the path of the image.
diff --git a/Jellyfin.Data/Entities/ItemDisplayPreferences.cs b/Jellyfin.Data/Entities/ItemDisplayPreferences.cs
index 4bfeb2fa3..948126d0a 100644
--- a/Jellyfin.Data/Entities/ItemDisplayPreferences.cs
+++ b/Jellyfin.Data/Entities/ItemDisplayPreferences.cs
@@ -29,13 +29,13 @@ namespace Jellyfin.Data.Entities
}
/// <summary>
- /// Gets or sets the Id.
+ /// Gets the id.
/// </summary>
/// <remarks>
/// Required.
/// </remarks>
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
- public int Id { get; protected set; }
+ public int Id { get; private set; }
/// <summary>
/// Gets or sets the user Id.
diff --git a/Jellyfin.Data/Entities/Libraries/Artwork.cs b/Jellyfin.Data/Entities/Libraries/Artwork.cs
index 84a524de2..923525fc5 100644
--- a/Jellyfin.Data/Entities/Libraries/Artwork.cs
+++ b/Jellyfin.Data/Entities/Libraries/Artwork.cs
@@ -1,5 +1,3 @@
-#pragma warning disable CA2227
-
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
@@ -30,13 +28,13 @@ namespace Jellyfin.Data.Entities.Libraries
}
/// <summary>
- /// Gets or sets the id.
+ /// Gets the id.
/// </summary>
/// <remarks>
/// Identity, Indexed, Required.
/// </remarks>
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
- public int Id { get; protected set; }
+ public int Id { get; private set; }
/// <summary>
/// Gets or sets the path.
@@ -58,7 +56,7 @@ namespace Jellyfin.Data.Entities.Libraries
/// <inheritdoc />
[ConcurrencyCheck]
- public uint RowVersion { get; set; }
+ public uint RowVersion { get; private set; }
/// <inheritdoc />
public void OnSavingChanges()
diff --git a/Jellyfin.Data/Entities/Libraries/Book.cs b/Jellyfin.Data/Entities/Libraries/Book.cs
index aea3d58d5..a838686d0 100644
--- a/Jellyfin.Data/Entities/Libraries/Book.cs
+++ b/Jellyfin.Data/Entities/Libraries/Book.cs
@@ -1,5 +1,3 @@
-#pragma warning disable CA2227
-
using System.Collections.Generic;
using Jellyfin.Data.Interfaces;
@@ -21,11 +19,11 @@ namespace Jellyfin.Data.Entities.Libraries
}
/// <summary>
- /// Gets or sets a collection containing the metadata for this book.
+ /// Gets a collection containing the metadata for this book.
/// </summary>
- public virtual ICollection<BookMetadata> BookMetadata { get; protected set; }
+ public virtual ICollection<BookMetadata> BookMetadata { get; private set; }
/// <inheritdoc />
- public virtual ICollection<Release> Releases { get; protected set; }
+ public virtual ICollection<Release> Releases { get; private set; }
}
}
diff --git a/Jellyfin.Data/Entities/Libraries/BookMetadata.cs b/Jellyfin.Data/Entities/Libraries/BookMetadata.cs
index 1ff4327b0..4a350d200 100644
--- a/Jellyfin.Data/Entities/Libraries/BookMetadata.cs
+++ b/Jellyfin.Data/Entities/Libraries/BookMetadata.cs
@@ -1,5 +1,3 @@
-#pragma warning disable CA2227
-
using System.Collections.Generic;
using Jellyfin.Data.Interfaces;
@@ -26,9 +24,9 @@ namespace Jellyfin.Data.Entities.Libraries
public long? Isbn { get; set; }
/// <summary>
- /// Gets or sets a collection of the publishers for this book.
+ /// Gets a collection of the publishers for this book.
/// </summary>
- public virtual ICollection<Company> Publishers { get; protected set; }
+ public virtual ICollection<Company> Publishers { get; private set; }
/// <inheritdoc />
public ICollection<Company> Companies => Publishers;
diff --git a/Jellyfin.Data/Entities/Libraries/Chapter.cs b/Jellyfin.Data/Entities/Libraries/Chapter.cs
index 11f53ae20..3d81f713d 100644
--- a/Jellyfin.Data/Entities/Libraries/Chapter.cs
+++ b/Jellyfin.Data/Entities/Libraries/Chapter.cs
@@ -1,5 +1,3 @@
-#pragma warning disable CA2227
-
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
@@ -29,13 +27,13 @@ namespace Jellyfin.Data.Entities.Libraries
}
/// <summary>
- /// Gets or sets the id.
+ /// Gets the id.
/// </summary>
/// <remarks>
/// Identity, Indexed, Required.
/// </remarks>
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
- public int Id { get; protected set; }
+ public int Id { get; private set; }
/// <summary>
/// Gets or sets the name.
@@ -74,7 +72,7 @@ namespace Jellyfin.Data.Entities.Libraries
/// <inheritdoc />
[ConcurrencyCheck]
- public uint RowVersion { get; protected set; }
+ public uint RowVersion { get; private set; }
/// <inheritdoc />
public void OnSavingChanges()
diff --git a/Jellyfin.Data/Entities/Libraries/Collection.cs b/Jellyfin.Data/Entities/Libraries/Collection.cs
index 4253b7ecc..7de601969 100644
--- a/Jellyfin.Data/Entities/Libraries/Collection.cs
+++ b/Jellyfin.Data/Entities/Libraries/Collection.cs
@@ -1,5 +1,4 @@
#pragma warning disable CA1711 // Identifiers should not have incorrect suffix
-#pragma warning disable CA2227
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
@@ -22,13 +21,13 @@ namespace Jellyfin.Data.Entities.Libraries
}
/// <summary>
- /// Gets or sets the id.
+ /// Gets the id.
/// </summary>
/// <remarks>
/// Identity, Indexed, Required.
/// </remarks>
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
- public int Id { get; protected set; }
+ public int Id { get; private set; }
/// <summary>
/// Gets or sets the name.
@@ -42,12 +41,12 @@ namespace Jellyfin.Data.Entities.Libraries
/// <inheritdoc />
[ConcurrencyCheck]
- public uint RowVersion { get; set; }
+ public uint RowVersion { get; private set; }
/// <summary>
- /// Gets or sets a collection containing this collection's items.
+ /// Gets a collection containing this collection's items.
/// </summary>
- public virtual ICollection<CollectionItem> Items { get; protected set; }
+ public virtual ICollection<CollectionItem> Items { get; private set; }
/// <inheritdoc />
public void OnSavingChanges()
diff --git a/Jellyfin.Data/Entities/Libraries/CollectionItem.cs b/Jellyfin.Data/Entities/Libraries/CollectionItem.cs
index e19362bdf..0cb4716db 100644
--- a/Jellyfin.Data/Entities/Libraries/CollectionItem.cs
+++ b/Jellyfin.Data/Entities/Libraries/CollectionItem.cs
@@ -29,7 +29,7 @@ namespace Jellyfin.Data.Entities.Libraries
/// <inheritdoc />
[ConcurrencyCheck]
- public uint RowVersion { get; set; }
+ public uint RowVersion { get; private set; }
/// <summary>
/// Gets or sets the library item.
diff --git a/Jellyfin.Data/Entities/Libraries/Company.cs b/Jellyfin.Data/Entities/Libraries/Company.cs
index 09050bb52..1abbee445 100644
--- a/Jellyfin.Data/Entities/Libraries/Company.cs
+++ b/Jellyfin.Data/Entities/Libraries/Company.cs
@@ -1,5 +1,3 @@
-#pragma warning disable CA2227
-
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
@@ -22,27 +20,27 @@ namespace Jellyfin.Data.Entities.Libraries
}
/// <summary>
- /// Gets or sets the id.
+ /// Gets the id.
/// </summary>
/// <remarks>
/// Identity, Indexed, Required.
/// </remarks>
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
- public int Id { get; protected set; }
+ public int Id { get; private set; }
/// <inheritdoc />
[ConcurrencyCheck]
- public uint RowVersion { get; set; }
+ public uint RowVersion { get; private set; }
/// <summary>
- /// Gets or sets a collection containing the metadata.
+ /// Gets a collection containing the metadata.
/// </summary>
- public virtual ICollection<CompanyMetadata> CompanyMetadata { get; protected set; }
+ public virtual ICollection<CompanyMetadata> CompanyMetadata { get; private set; }
/// <summary>
- /// Gets or sets a collection containing this company's child companies.
+ /// Gets a collection containing this company's child companies.
/// </summary>
- public virtual ICollection<Company> ChildCompanies { get; protected set; }
+ public virtual ICollection<Company> ChildCompanies { get; private set; }
/// <inheritdoc />
public ICollection<Company> Companies => ChildCompanies;
diff --git a/Jellyfin.Data/Entities/Libraries/CustomItem.cs b/Jellyfin.Data/Entities/Libraries/CustomItem.cs
index 88d1a0c25..e27d01d86 100644
--- a/Jellyfin.Data/Entities/Libraries/CustomItem.cs
+++ b/Jellyfin.Data/Entities/Libraries/CustomItem.cs
@@ -1,5 +1,3 @@
-#pragma warning disable CA2227
-
using System.Collections.Generic;
using Jellyfin.Data.Interfaces;
@@ -21,11 +19,11 @@ namespace Jellyfin.Data.Entities.Libraries
}
/// <summary>
- /// Gets or sets a collection containing the metadata for this item.
+ /// Gets a collection containing the metadata for this item.
/// </summary>
- public virtual ICollection<CustomItemMetadata> CustomItemMetadata { get; protected set; }
+ public virtual ICollection<CustomItemMetadata> CustomItemMetadata { get; private set; }
/// <inheritdoc />
- public virtual ICollection<Release> Releases { get; protected set; }
+ public virtual ICollection<Release> Releases { get; private set; }
}
}
diff --git a/Jellyfin.Data/Entities/Libraries/Episode.cs b/Jellyfin.Data/Entities/Libraries/Episode.cs
index 458c7d9f5..ce2f0c617 100644
--- a/Jellyfin.Data/Entities/Libraries/Episode.cs
+++ b/Jellyfin.Data/Entities/Libraries/Episode.cs
@@ -1,5 +1,3 @@
-#pragma warning disable CA2227
-
using System.Collections.Generic;
using Jellyfin.Data.Interfaces;
@@ -26,11 +24,11 @@ namespace Jellyfin.Data.Entities.Libraries
public int? EpisodeNumber { get; set; }
/// <inheritdoc />
- public virtual ICollection<Release> Releases { get; protected set; }
+ public virtual ICollection<Release> Releases { get; private set; }
/// <summary>
- /// Gets or sets a collection containing the metadata for this episode.
+ /// Gets a collection containing the metadata for this episode.
/// </summary>
- public virtual ICollection<EpisodeMetadata> EpisodeMetadata { get; protected set; }
+ public virtual ICollection<EpisodeMetadata> EpisodeMetadata { get; private set; }
}
}
diff --git a/Jellyfin.Data/Entities/Libraries/Genre.cs b/Jellyfin.Data/Entities/Libraries/Genre.cs
index 9f3d65028..3b822ee82 100644
--- a/Jellyfin.Data/Entities/Libraries/Genre.cs
+++ b/Jellyfin.Data/Entities/Libraries/Genre.cs
@@ -19,13 +19,13 @@ namespace Jellyfin.Data.Entities.Libraries
}
/// <summary>
- /// Gets or sets the id.
+ /// Gets the id.
/// </summary>
/// <remarks>
/// Identity, Indexed, Required.
/// </remarks>
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
- public int Id { get; protected set; }
+ public int Id { get; private set; }
/// <summary>
/// Gets or sets the name.
@@ -39,7 +39,7 @@ namespace Jellyfin.Data.Entities.Libraries
/// <inheritdoc />
[ConcurrencyCheck]
- public uint RowVersion { get; protected set; }
+ public uint RowVersion { get; private set; }
/// <inheritdoc />
public void OnSavingChanges()
diff --git a/Jellyfin.Data/Entities/Libraries/ItemMetadata.cs b/Jellyfin.Data/Entities/Libraries/ItemMetadata.cs
index d12e011a8..d429a90c6 100644
--- a/Jellyfin.Data/Entities/Libraries/ItemMetadata.cs
+++ b/Jellyfin.Data/Entities/Libraries/ItemMetadata.cs
@@ -1,5 +1,3 @@
-#pragma warning disable CA2227
-
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
@@ -43,13 +41,13 @@ namespace Jellyfin.Data.Entities.Libraries
}
/// <summary>
- /// Gets or sets the id.
+ /// Gets the id.
/// </summary>
/// <remarks>
/// Identity, Indexed, Required.
/// </remarks>
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
- public int Id { get; protected set; }
+ public int Id { get; private set; }
/// <summary>
/// Gets or sets the title.
@@ -99,12 +97,12 @@ namespace Jellyfin.Data.Entities.Libraries
public DateTimeOffset? ReleaseDate { get; set; }
/// <summary>
- /// Gets or sets the date added.
+ /// Gets the date added.
/// </summary>
/// <remarks>
/// Required.
/// </remarks>
- public DateTime DateAdded { get; protected set; }
+ public DateTime DateAdded { get; private set; }
/// <summary>
/// Gets or sets the date modified.
@@ -114,37 +112,32 @@ namespace Jellyfin.Data.Entities.Libraries
/// </remarks>
public DateTime DateModified { get; set; }
- /// <summary>
- /// Gets or sets the row version.
- /// </summary>
- /// <remarks>
- /// Required, ConcurrencyToken.
- /// </remarks>
+ /// <inheritdoc />
[ConcurrencyCheck]
- public uint RowVersion { get; set; }
+ public uint RowVersion { get; private set; }
/// <summary>
- /// Gets or sets a collection containing the person roles for this item.
+ /// Gets a collection containing the person roles for this item.
/// </summary>
- public virtual ICollection<PersonRole> PersonRoles { get; protected set; }
+ public virtual ICollection<PersonRole> PersonRoles { get; private set; }
/// <summary>
- /// Gets or sets a collection containing the genres for this item.
+ /// Gets a collection containing the genres for this item.
/// </summary>
- public virtual ICollection<Genre> Genres { get; protected set; }
+ public virtual ICollection<Genre> Genres { get; private set; }
/// <inheritdoc />
- public virtual ICollection<Artwork> Artwork { get; protected set; }
+ public virtual ICollection<Artwork> Artwork { get; private set; }
/// <summary>
- /// Gets or sets a collection containing the ratings for this item.
+ /// Gets a collection containing the ratings for this item.
/// </summary>
- public virtual ICollection<Rating> Ratings { get; protected set; }
+ public virtual ICollection<Rating> Ratings { get; private set; }
/// <summary>
- /// Gets or sets a collection containing the metadata sources for this item.
+ /// Gets a collection containing the metadata sources for this item.
/// </summary>
- public virtual ICollection<MetadataProviderId> Sources { get; protected set; }
+ public virtual ICollection<MetadataProviderId> Sources { get; private set; }
/// <inheritdoc />
public void OnSavingChanges()
diff --git a/Jellyfin.Data/Entities/Libraries/Library.cs b/Jellyfin.Data/Entities/Libraries/Library.cs
index e45384902..0db42a1c7 100644
--- a/Jellyfin.Data/Entities/Libraries/Library.cs
+++ b/Jellyfin.Data/Entities/Libraries/Library.cs
@@ -21,13 +21,13 @@ namespace Jellyfin.Data.Entities.Libraries
}
/// <summary>
- /// Gets or sets the id.
+ /// Gets the id.
/// </summary>
/// <remarks>
/// Identity, Indexed, Required.
/// </remarks>
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
- public int Id { get; protected set; }
+ public int Id { get; private set; }
/// <summary>
/// Gets or sets the name.
@@ -49,7 +49,7 @@ namespace Jellyfin.Data.Entities.Libraries
/// <inheritdoc />
[ConcurrencyCheck]
- public uint RowVersion { get; set; }
+ public uint RowVersion { get; private set; }
/// <inheritdoc />
public void OnSavingChanges()
diff --git a/Jellyfin.Data/Entities/Libraries/LibraryItem.cs b/Jellyfin.Data/Entities/Libraries/LibraryItem.cs
index 67ffad944..d889b871e 100644
--- a/Jellyfin.Data/Entities/Libraries/LibraryItem.cs
+++ b/Jellyfin.Data/Entities/Libraries/LibraryItem.cs
@@ -21,22 +21,22 @@ namespace Jellyfin.Data.Entities.Libraries
}
/// <summary>
- /// Gets or sets the id.
+ /// Gets the id.
/// </summary>
/// <remarks>
/// Identity, Indexed, Required.
/// </remarks>
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
- public int Id { get; protected set; }
+ public int Id { get; private set; }
/// <summary>
- /// Gets or sets the date this library item was added.
+ /// Gets the date this library item was added.
/// </summary>
- public DateTime DateAdded { get; protected set; }
+ public DateTime DateAdded { get; private set; }
/// <inheritdoc />
[ConcurrencyCheck]
- public uint RowVersion { get; protected set; }
+ public uint RowVersion { get; private set; }
/// <summary>
/// Gets or sets the library of this item.
diff --git a/Jellyfin.Data/Entities/Libraries/MediaFile.cs b/Jellyfin.Data/Entities/Libraries/MediaFile.cs
index f3e2fe653..36e1e4777 100644
--- a/Jellyfin.Data/Entities/Libraries/MediaFile.cs
+++ b/Jellyfin.Data/Entities/Libraries/MediaFile.cs
@@ -1,5 +1,3 @@
-#pragma warning disable CA2227
-
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
@@ -33,13 +31,13 @@ namespace Jellyfin.Data.Entities.Libraries
}
/// <summary>
- /// Gets or sets the id.
+ /// Gets the id.
/// </summary>
/// <remarks>
/// Identity, Indexed, Required.
/// </remarks>
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
- public int Id { get; protected set; }
+ public int Id { get; private set; }
/// <summary>
/// Gets or sets the path relative to the library root.
@@ -61,12 +59,12 @@ namespace Jellyfin.Data.Entities.Libraries
/// <inheritdoc />
[ConcurrencyCheck]
- public uint RowVersion { get; set; }
+ public uint RowVersion { get; private set; }
/// <summary>
- /// Gets or sets a collection containing the streams in this file.
+ /// Gets a collection containing the streams in this file.
/// </summary>
- public virtual ICollection<MediaFileStream> MediaFileStreams { get; protected set; }
+ public virtual ICollection<MediaFileStream> MediaFileStreams { get; private set; }
/// <inheritdoc />
public void OnSavingChanges()
diff --git a/Jellyfin.Data/Entities/Libraries/MediaFileStream.cs b/Jellyfin.Data/Entities/Libraries/MediaFileStream.cs
index ba21294fc..e24e73ecb 100644
--- a/Jellyfin.Data/Entities/Libraries/MediaFileStream.cs
+++ b/Jellyfin.Data/Entities/Libraries/MediaFileStream.cs
@@ -21,13 +21,13 @@ namespace Jellyfin.Data.Entities.Libraries
}
/// <summary>
- /// Gets or sets the id.
+ /// Gets the id.
/// </summary>
/// <remarks>
/// Identity, Indexed, Required.
/// </remarks>
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
- public int Id { get; protected set; }
+ public int Id { get; private set; }
/// <summary>
/// Gets or sets the stream number.
@@ -39,7 +39,7 @@ namespace Jellyfin.Data.Entities.Libraries
/// <inheritdoc />
[ConcurrencyCheck]
- public uint RowVersion { get; set; }
+ public uint RowVersion { get; private set; }
/// <inheritdoc />
public void OnSavingChanges()
diff --git a/Jellyfin.Data/Entities/Libraries/MetadataProvider.cs b/Jellyfin.Data/Entities/Libraries/MetadataProvider.cs
index fb2587882..b27196078 100644
--- a/Jellyfin.Data/Entities/Libraries/MetadataProvider.cs
+++ b/Jellyfin.Data/Entities/Libraries/MetadataProvider.cs
@@ -25,13 +25,13 @@ namespace Jellyfin.Data.Entities.Libraries
}
/// <summary>
- /// Gets or sets the id.
+ /// Gets the id.
/// </summary>
/// <remarks>
/// Identity, Indexed, Required.
/// </remarks>
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
- public int Id { get; protected set; }
+ public int Id { get; private set; }
/// <summary>
/// Gets or sets the name.
@@ -45,7 +45,7 @@ namespace Jellyfin.Data.Entities.Libraries
/// <inheritdoc />
[ConcurrencyCheck]
- public uint RowVersion { get; set; }
+ public uint RowVersion { get; private set; }
/// <inheritdoc />
public void OnSavingChanges()
diff --git a/Jellyfin.Data/Entities/Libraries/MetadataProviderId.cs b/Jellyfin.Data/Entities/Libraries/MetadataProviderId.cs
index 2a9c904c8..44c198518 100644
--- a/Jellyfin.Data/Entities/Libraries/MetadataProviderId.cs
+++ b/Jellyfin.Data/Entities/Libraries/MetadataProviderId.cs
@@ -27,13 +27,13 @@ namespace Jellyfin.Data.Entities.Libraries
}
/// <summary>
- /// Gets or sets the id.
+ /// Gets the id.
/// </summary>
/// <remarks>
/// Identity, Indexed, Required.
/// </remarks>
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
- public int Id { get; protected set; }
+ public int Id { get; private set; }
/// <summary>
/// Gets or sets the provider id.
@@ -47,7 +47,7 @@ namespace Jellyfin.Data.Entities.Libraries
/// <inheritdoc />
[ConcurrencyCheck]
- public uint RowVersion { get; set; }
+ public uint RowVersion { get; private set; }
/// <summary>
/// Gets or sets the metadata provider.
diff --git a/Jellyfin.Data/Entities/Libraries/Movie.cs b/Jellyfin.Data/Entities/Libraries/Movie.cs
index f89cacff4..499fafd0e 100644
--- a/Jellyfin.Data/Entities/Libraries/Movie.cs
+++ b/Jellyfin.Data/Entities/Libraries/Movie.cs
@@ -1,5 +1,3 @@
-#pragma warning disable CA2227
-
using System.Collections.Generic;
using Jellyfin.Data.Interfaces;
@@ -21,11 +19,11 @@ namespace Jellyfin.Data.Entities.Libraries
}
/// <inheritdoc />
- public virtual ICollection<Release> Releases { get; protected set; }
+ public virtual ICollection<Release> Releases { get; private set; }
/// <summary>
- /// Gets or sets a collection containing the metadata for this movie.
+ /// Gets a collection containing the metadata for this movie.
/// </summary>
- public virtual ICollection<MovieMetadata> MovieMetadata { get; protected set; }
+ public virtual ICollection<MovieMetadata> MovieMetadata { get; private set; }
}
}
diff --git a/Jellyfin.Data/Entities/Libraries/MovieMetadata.cs b/Jellyfin.Data/Entities/Libraries/MovieMetadata.cs
index fb181dea6..44b5f34d7 100644
--- a/Jellyfin.Data/Entities/Libraries/MovieMetadata.cs
+++ b/Jellyfin.Data/Entities/Libraries/MovieMetadata.cs
@@ -1,5 +1,3 @@
-#pragma warning disable CA2227
-
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using Jellyfin.Data.Interfaces;
@@ -62,9 +60,9 @@ namespace Jellyfin.Data.Entities.Libraries
public string? Country { get; set; }
/// <summary>
- /// Gets or sets the studios that produced this movie.
+ /// Gets the studios that produced this movie.
/// </summary>
- public virtual ICollection<Company> Studios { get; protected set; }
+ public virtual ICollection<Company> Studios { get; private set; }
/// <inheritdoc />
public ICollection<Company> Companies => Studios;
diff --git a/Jellyfin.Data/Entities/Libraries/MusicAlbum.cs b/Jellyfin.Data/Entities/Libraries/MusicAlbum.cs
index 4049cdac8..d6231bbf0 100644
--- a/Jellyfin.Data/Entities/Libraries/MusicAlbum.cs
+++ b/Jellyfin.Data/Entities/Libraries/MusicAlbum.cs
@@ -1,5 +1,3 @@
-#pragma warning disable CA2227
-
using System.Collections.Generic;
namespace Jellyfin.Data.Entities.Libraries
@@ -20,13 +18,13 @@ namespace Jellyfin.Data.Entities.Libraries
}
/// <summary>
- /// Gets or sets a collection containing the album metadata.
+ /// Gets a collection containing the album metadata.
/// </summary>
- public virtual ICollection<MusicAlbumMetadata> MusicAlbumMetadata { get; protected set; }
+ public virtual ICollection<MusicAlbumMetadata> MusicAlbumMetadata { get; private set; }
/// <summary>
- /// Gets or sets a collection containing the tracks.
+ /// Gets a collection containing the tracks.
/// </summary>
- public virtual ICollection<Track> Tracks { get; protected set; }
+ public virtual ICollection<Track> Tracks { get; private set; }
}
}
diff --git a/Jellyfin.Data/Entities/Libraries/MusicAlbumMetadata.cs b/Jellyfin.Data/Entities/Libraries/MusicAlbumMetadata.cs
index 3080bd692..691f3504f 100644
--- a/Jellyfin.Data/Entities/Libraries/MusicAlbumMetadata.cs
+++ b/Jellyfin.Data/Entities/Libraries/MusicAlbumMetadata.cs
@@ -1,5 +1,3 @@
-#pragma warning disable CA2227
-
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
@@ -51,8 +49,8 @@ namespace Jellyfin.Data.Entities.Libraries
public string? Country { get; set; }
/// <summary>
- /// Gets or sets a collection containing the labels.
+ /// Gets a collection containing the labels.
/// </summary>
- public virtual ICollection<Company> Labels { get; protected set; }
+ public virtual ICollection<Company> Labels { get; private set; }
}
}
diff --git a/Jellyfin.Data/Entities/Libraries/Person.cs b/Jellyfin.Data/Entities/Libraries/Person.cs
index 159bd47be..8b67d920d 100644
--- a/Jellyfin.Data/Entities/Libraries/Person.cs
+++ b/Jellyfin.Data/Entities/Libraries/Person.cs
@@ -1,5 +1,3 @@
-#pragma warning disable CA2227
-
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
@@ -32,13 +30,13 @@ namespace Jellyfin.Data.Entities.Libraries
}
/// <summary>
- /// Gets or sets the id.
+ /// Gets the id.
/// </summary>
/// <remarks>
/// Identity, Indexed, Required.
/// </remarks>
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
- public int Id { get; protected set; }
+ public int Id { get; private set; }
/// <summary>
/// Gets or sets the name.
@@ -61,12 +59,12 @@ namespace Jellyfin.Data.Entities.Libraries
public string? SourceId { get; set; }
/// <summary>
- /// Gets or sets the date added.
+ /// Gets the date added.
/// </summary>
/// <remarks>
/// Required.
/// </remarks>
- public DateTime DateAdded { get; protected set; }
+ public DateTime DateAdded { get; private set; }
/// <summary>
/// Gets or sets the date modified.
@@ -78,12 +76,12 @@ namespace Jellyfin.Data.Entities.Libraries
/// <inheritdoc />
[ConcurrencyCheck]
- public uint RowVersion { get; set; }
+ public uint RowVersion { get; private set; }
/// <summary>
- /// Gets or sets a list of metadata sources for this person.
+ /// Gets a list of metadata sources for this person.
/// </summary>
- public virtual ICollection<MetadataProviderId> Sources { get; protected set; }
+ public virtual ICollection<MetadataProviderId> Sources { get; private set; }
/// <inheritdoc />
public void OnSavingChanges()
diff --git a/Jellyfin.Data/Entities/Libraries/PersonRole.cs b/Jellyfin.Data/Entities/Libraries/PersonRole.cs
index 988aa84ba..7d40bdf44 100644
--- a/Jellyfin.Data/Entities/Libraries/PersonRole.cs
+++ b/Jellyfin.Data/Entities/Libraries/PersonRole.cs
@@ -1,5 +1,3 @@
-#pragma warning disable CA2227
-
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
@@ -27,13 +25,13 @@ namespace Jellyfin.Data.Entities.Libraries
}
/// <summary>
- /// Gets or sets the id.
+ /// Gets the id.
/// </summary>
/// <remarks>
/// Identity, Indexed, Required.
/// </remarks>
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
- public int Id { get; protected set; }
+ public int Id { get; private set; }
/// <summary>
/// Gets or sets the name of the person's role.
@@ -55,7 +53,7 @@ namespace Jellyfin.Data.Entities.Libraries
/// <inheritdoc />
[ConcurrencyCheck]
- public uint RowVersion { get; protected set; }
+ public uint RowVersion { get; private set; }
/// <summary>
/// Gets or sets the person.
@@ -66,12 +64,12 @@ namespace Jellyfin.Data.Entities.Libraries
public virtual Person Person { get; set; }
/// <inheritdoc />
- public virtual ICollection<Artwork> Artwork { get; protected set; }
+ public virtual ICollection<Artwork> Artwork { get; private set; }
/// <summary>
- /// Gets or sets a collection containing the metadata sources for this person role.
+ /// Gets a collection containing the metadata sources for this person role.
/// </summary>
- public virtual ICollection<MetadataProviderId> Sources { get; protected set; }
+ public virtual ICollection<MetadataProviderId> Sources { get; private set; }
/// <inheritdoc />
public void OnSavingChanges()
diff --git a/Jellyfin.Data/Entities/Libraries/Photo.cs b/Jellyfin.Data/Entities/Libraries/Photo.cs
index eb5c96267..4b459432b 100644
--- a/Jellyfin.Data/Entities/Libraries/Photo.cs
+++ b/Jellyfin.Data/Entities/Libraries/Photo.cs
@@ -1,5 +1,3 @@
-#pragma warning disable CA2227
-
using System.Collections.Generic;
using Jellyfin.Data.Interfaces;
@@ -21,11 +19,11 @@ namespace Jellyfin.Data.Entities.Libraries
}
/// <summary>
- /// Gets or sets a collection containing the photo metadata.
+ /// Gets a collection containing the photo metadata.
/// </summary>
- public virtual ICollection<PhotoMetadata> PhotoMetadata { get; protected set; }
+ public virtual ICollection<PhotoMetadata> PhotoMetadata { get; private set; }
/// <inheritdoc />
- public virtual ICollection<Release> Releases { get; protected set; }
+ public virtual ICollection<Release> Releases { get; private set; }
}
}
diff --git a/Jellyfin.Data/Entities/Libraries/Rating.cs b/Jellyfin.Data/Entities/Libraries/Rating.cs
index 6862012a8..58c8fa49e 100644
--- a/Jellyfin.Data/Entities/Libraries/Rating.cs
+++ b/Jellyfin.Data/Entities/Libraries/Rating.cs
@@ -19,13 +19,13 @@ namespace Jellyfin.Data.Entities.Libraries
}
/// <summary>
- /// Gets or sets the id.
+ /// Gets the id.
/// </summary>
/// <remarks>
/// Identity, Indexed, Required.
/// </remarks>
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
- public int Id { get; protected set; }
+ public int Id { get; private set; }
/// <summary>
/// Gets or sets the value.
@@ -42,7 +42,7 @@ namespace Jellyfin.Data.Entities.Libraries
/// <inheritdoc />
[ConcurrencyCheck]
- public uint RowVersion { get; set; }
+ public uint RowVersion { get; private set; }
/// <summary>
/// Gets or sets the rating type.
diff --git a/Jellyfin.Data/Entities/Libraries/RatingSource.cs b/Jellyfin.Data/Entities/Libraries/RatingSource.cs
index ae0d806ff..0f3a07324 100644
--- a/Jellyfin.Data/Entities/Libraries/RatingSource.cs
+++ b/Jellyfin.Data/Entities/Libraries/RatingSource.cs
@@ -21,13 +21,13 @@ namespace Jellyfin.Data.Entities.Libraries
}
/// <summary>
- /// Gets or sets the id.
+ /// Gets the id.
/// </summary>
/// <remarks>
/// Identity, Indexed, Required.
/// </remarks>
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
- public int Id { get; protected set; }
+ public int Id { get; private set; }
/// <summary>
/// Gets or sets the name.
@@ -57,7 +57,7 @@ namespace Jellyfin.Data.Entities.Libraries
/// <inheritdoc />
[ConcurrencyCheck]
- public uint RowVersion { get; set; }
+ public uint RowVersion { get; private set; }
/// <summary>
/// Gets or sets the metadata source.
diff --git a/Jellyfin.Data/Entities/Libraries/Release.cs b/Jellyfin.Data/Entities/Libraries/Release.cs
index 21d403979..d3d52bf5c 100644
--- a/Jellyfin.Data/Entities/Libraries/Release.cs
+++ b/Jellyfin.Data/Entities/Libraries/Release.cs
@@ -1,5 +1,3 @@
-#pragma warning disable CA2227
-
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
@@ -31,13 +29,13 @@ namespace Jellyfin.Data.Entities.Libraries
}
/// <summary>
- /// Gets or sets the id.
+ /// Gets the id.
/// </summary>
/// <remarks>
/// Identity, Indexed, Required.
/// </remarks>
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
- public int Id { get; protected set; }
+ public int Id { get; private set; }
/// <summary>
/// Gets or sets the name.
@@ -51,17 +49,17 @@ namespace Jellyfin.Data.Entities.Libraries
/// <inheritdoc />
[ConcurrencyCheck]
- public uint RowVersion { get; set; }
+ public uint RowVersion { get; private set; }
/// <summary>
- /// Gets or sets a collection containing the media files for this release.
+ /// Gets a collection containing the media files for this release.
/// </summary>
- public virtual ICollection<MediaFile> MediaFiles { get; protected set; }
+ public virtual ICollection<MediaFile> MediaFiles { get; private set; }
/// <summary>
- /// Gets or sets a collection containing the chapters for this release.
+ /// Gets a collection containing the chapters for this release.
/// </summary>
- public virtual ICollection<Chapter> Chapters { get; protected set; }
+ public virtual ICollection<Chapter> Chapters { get; private set; }
/// <inheritdoc />
public void OnSavingChanges()
diff --git a/Jellyfin.Data/Entities/Libraries/Season.cs b/Jellyfin.Data/Entities/Libraries/Season.cs
index 04f723a1d..fc110b49d 100644
--- a/Jellyfin.Data/Entities/Libraries/Season.cs
+++ b/Jellyfin.Data/Entities/Libraries/Season.cs
@@ -1,5 +1,3 @@
-#pragma warning disable CA2227
-
using System.Collections.Generic;
namespace Jellyfin.Data.Entities.Libraries
@@ -25,13 +23,13 @@ namespace Jellyfin.Data.Entities.Libraries
public int? SeasonNumber { get; set; }
/// <summary>
- /// Gets or sets the season metadata.
+ /// Gets the season metadata.
/// </summary>
- public virtual ICollection<SeasonMetadata> SeasonMetadata { get; protected set; }
+ public virtual ICollection<SeasonMetadata> SeasonMetadata { get; private set; }
/// <summary>
- /// Gets or sets a collection containing the number of episodes.
+ /// Gets a collection containing the number of episodes.
/// </summary>
- public virtual ICollection<Episode> Episodes { get; protected set; }
+ public virtual ICollection<Episode> Episodes { get; private set; }
}
}
diff --git a/Jellyfin.Data/Entities/Libraries/Series.cs b/Jellyfin.Data/Entities/Libraries/Series.cs
index 59508831e..0354433e0 100644
--- a/Jellyfin.Data/Entities/Libraries/Series.cs
+++ b/Jellyfin.Data/Entities/Libraries/Series.cs
@@ -1,5 +1,3 @@
-#pragma warning disable CA2227
-
using System;
using System.Collections.Generic;
@@ -16,7 +14,6 @@ namespace Jellyfin.Data.Entities.Libraries
/// <param name="library">The library.</param>
public Series(Library library) : base(library)
{
- DateAdded = DateTime.UtcNow;
Seasons = new HashSet<Season>();
SeriesMetadata = new HashSet<SeriesMetadata>();
}
@@ -37,13 +34,13 @@ namespace Jellyfin.Data.Entities.Libraries
public DateTime? FirstAired { get; set; }
/// <summary>
- /// Gets or sets a collection containing the series metadata.
+ /// Gets a collection containing the series metadata.
/// </summary>
- public virtual ICollection<SeriesMetadata> SeriesMetadata { get; protected set; }
+ public virtual ICollection<SeriesMetadata> SeriesMetadata { get; private set; }
/// <summary>
- /// Gets or sets a collection containing the seasons.
+ /// Gets a collection containing the seasons.
/// </summary>
- public virtual ICollection<Season> Seasons { get; protected set; }
+ public virtual ICollection<Season> Seasons { get; private set; }
}
}
diff --git a/Jellyfin.Data/Entities/Libraries/SeriesMetadata.cs b/Jellyfin.Data/Entities/Libraries/SeriesMetadata.cs
index cc04d033a..42115802c 100644
--- a/Jellyfin.Data/Entities/Libraries/SeriesMetadata.cs
+++ b/Jellyfin.Data/Entities/Libraries/SeriesMetadata.cs
@@ -1,5 +1,3 @@
-#pragma warning disable CA2227
-
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using Jellyfin.Data.Interfaces;
@@ -62,9 +60,9 @@ namespace Jellyfin.Data.Entities.Libraries
public string? Country { get; set; }
/// <summary>
- /// Gets or sets a collection containing the networks.
+ /// Gets a collection containing the networks.
/// </summary>
- public virtual ICollection<Company> Networks { get; protected set; }
+ public virtual ICollection<Company> Networks { get; private set; }
/// <inheritdoc />
public ICollection<Company> Companies => Networks;
diff --git a/Jellyfin.Data/Entities/Libraries/Track.cs b/Jellyfin.Data/Entities/Libraries/Track.cs
index 86a3edff8..d35400033 100644
--- a/Jellyfin.Data/Entities/Libraries/Track.cs
+++ b/Jellyfin.Data/Entities/Libraries/Track.cs
@@ -1,5 +1,3 @@
-#pragma warning disable CA2227
-
using System.Collections.Generic;
using Jellyfin.Data.Interfaces;
@@ -26,11 +24,11 @@ namespace Jellyfin.Data.Entities.Libraries
public int? TrackNumber { get; set; }
/// <inheritdoc />
- public virtual ICollection<Release> Releases { get; protected set; }
+ public virtual ICollection<Release> Releases { get; private set; }
/// <summary>
- /// Gets or sets a collection containing the track metadata.
+ /// Gets a collection containing the track metadata.
/// </summary>
- public virtual ICollection<TrackMetadata> TrackMetadata { get; protected set; }
+ public virtual ICollection<TrackMetadata> TrackMetadata { get; private set; }
}
}
diff --git a/Jellyfin.Data/Entities/Permission.cs b/Jellyfin.Data/Entities/Permission.cs
index f059dedfa..6d2e68077 100644
--- a/Jellyfin.Data/Entities/Permission.cs
+++ b/Jellyfin.Data/Entities/Permission.cs
@@ -1,5 +1,6 @@
#pragma warning disable CA1711 // Identifiers should not have incorrect suffix
+using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using Jellyfin.Data.Enums;
@@ -25,21 +26,26 @@ namespace Jellyfin.Data.Entities
}
/// <summary>
- /// Gets or sets the id of this permission.
+ /// Gets the id of this permission.
/// </summary>
/// <remarks>
/// Identity, Indexed, Required.
/// </remarks>
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
- public int Id { get; protected set; }
+ public int Id { get; private set; }
/// <summary>
- /// Gets or sets the type of this permission.
+ /// Gets or sets the id of the associated user.
+ /// </summary>
+ public Guid? UserId { get; set; }
+
+ /// <summary>
+ /// Gets the type of this permission.
/// </summary>
/// <remarks>
/// Required.
/// </remarks>
- public PermissionKind Kind { get; protected set; }
+ public PermissionKind Kind { get; private set; }
/// <summary>
/// Gets or sets a value indicating whether the associated user has this permission.
@@ -51,7 +57,7 @@ namespace Jellyfin.Data.Entities
/// <inheritdoc />
[ConcurrencyCheck]
- public uint RowVersion { get; set; }
+ public uint RowVersion { get; private set; }
/// <inheritdoc/>
public void OnSavingChanges()
diff --git a/Jellyfin.Data/Entities/Preference.cs b/Jellyfin.Data/Entities/Preference.cs
index a8813ab88..a6ab275d3 100644
--- a/Jellyfin.Data/Entities/Preference.cs
+++ b/Jellyfin.Data/Entities/Preference.cs
@@ -24,21 +24,26 @@ namespace Jellyfin.Data.Entities
}
/// <summary>
- /// Gets or sets the id of this preference.
+ /// Gets the id of this preference.
/// </summary>
/// <remarks>
/// Identity, Indexed, Required.
/// </remarks>
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
- public int Id { get; protected set; }
+ public int Id { get; private set; }
/// <summary>
- /// Gets or sets the type of this preference.
+ /// Gets or sets the id of the associated user.
+ /// </summary>
+ public Guid? UserId { get; set; }
+
+ /// <summary>
+ /// Gets the type of this preference.
/// </summary>
/// <remarks>
/// Required.
/// </remarks>
- public PreferenceKind Kind { get; protected set; }
+ public PreferenceKind Kind { get; private set; }
/// <summary>
/// Gets or sets the value of this preference.
@@ -52,7 +57,7 @@ namespace Jellyfin.Data.Entities
/// <inheritdoc/>
[ConcurrencyCheck]
- public uint RowVersion { get; set; }
+ public uint RowVersion { get; private set; }
/// <inheritdoc/>
public void OnSavingChanges()
diff --git a/Jellyfin.Data/Entities/User.cs b/Jellyfin.Data/Entities/User.cs
index 74331726c..e309e54de 100644
--- a/Jellyfin.Data/Entities/User.cs
+++ b/Jellyfin.Data/Entities/User.cs
@@ -1,5 +1,3 @@
-#pragma warning disable CA2227
-
using System;
using System.Collections.Generic;
using System.ComponentModel;
@@ -302,64 +300,54 @@ namespace Jellyfin.Data.Entities
public virtual ImageInfo? ProfileImage { get; set; }
/// <summary>
- /// Gets or sets the user's display preferences.
+ /// Gets the user's display preferences.
/// </summary>
- /// <remarks>
- /// Required.
- /// </remarks>
- public virtual ICollection<DisplayPreferences> DisplayPreferences { get; set; }
+ public virtual ICollection<DisplayPreferences> DisplayPreferences { get; private set; }
/// <summary>
/// Gets or sets the level of sync play permissions this user has.
/// </summary>
public SyncPlayUserAccessType SyncPlayAccess { get; set; }
- /// <summary>
- /// Gets or sets the row version.
- /// </summary>
- /// <remarks>
- /// Required, Concurrency Token.
- /// </remarks>
+ /// <inheritdoc />
[ConcurrencyCheck]
- public uint RowVersion { get; set; }
+ public uint RowVersion { get; private set; }
/// <summary>
- /// Gets or sets the list of access schedules this user has.
+ /// Gets the list of access schedules this user has.
/// </summary>
- public virtual ICollection<AccessSchedule> AccessSchedules { get; protected set; }
+ public virtual ICollection<AccessSchedule> AccessSchedules { get; private set; }
/// <summary>
- /// Gets or sets the list of item display preferences.
+ /// Gets the list of item display preferences.
/// </summary>
- public virtual ICollection<ItemDisplayPreferences> ItemDisplayPreferences { get; protected set; }
+ public virtual ICollection<ItemDisplayPreferences> ItemDisplayPreferences { get; private set; }
/*
/// <summary>
- /// Gets or sets the list of groups this user is a member of.
+ /// Gets the list of groups this user is a member of.
/// </summary>
- [ForeignKey("Group_Groups_Guid")]
- public virtual ICollection<Group> Groups { get; protected set; }
+ public virtual ICollection<Group> Groups { get; private set; }
*/
/// <summary>
- /// Gets or sets the list of permissions this user has.
+ /// Gets the list of permissions this user has.
/// </summary>
[ForeignKey("Permission_Permissions_Guid")]
- public virtual ICollection<Permission> Permissions { get; protected set; }
+ public virtual ICollection<Permission> Permissions { get; private set; }
/*
/// <summary>
- /// Gets or sets the list of provider mappings this user has.
+ /// Gets the list of provider mappings this user has.
/// </summary>
- [ForeignKey("ProviderMapping_ProviderMappings_Id")]
- public virtual ICollection<ProviderMapping> ProviderMappings { get; protected set; }
+ public virtual ICollection<ProviderMapping> ProviderMappings { get; private set; }
*/
/// <summary>
- /// Gets or sets the list of preferences this user has.
+ /// Gets the list of preferences this user has.
/// </summary>
[ForeignKey("Preference_Preferences_Guid")]
- public virtual ICollection<Preference> Preferences { get; protected set; }
+ public virtual ICollection<Preference> Preferences { get; private set; }
/// <inheritdoc/>
public void OnSavingChanges()
diff --git a/Jellyfin.Data/Enums/HomeSectionType.cs b/Jellyfin.Data/Enums/HomeSectionType.cs
index e597c9431..9bcd097dc 100644
--- a/Jellyfin.Data/Enums/HomeSectionType.cs
+++ b/Jellyfin.Data/Enums/HomeSectionType.cs
@@ -48,6 +48,11 @@
/// <summary>
/// Live TV.
/// </summary>
- LiveTv = 8
+ LiveTv = 8,
+
+ /// <summary>
+ /// Continue Reading.
+ /// </summary>
+ ResumeBook = 9
}
}
diff --git a/Jellyfin.Drawing.Skia/StripCollageBuilder.cs b/Jellyfin.Drawing.Skia/StripCollageBuilder.cs
index e9f9aad57..09a370238 100644
--- a/Jellyfin.Drawing.Skia/StripCollageBuilder.cs
+++ b/Jellyfin.Drawing.Skia/StripCollageBuilder.cs
@@ -68,7 +68,7 @@ namespace Jellyfin.Drawing.Skia
/// <param name="outputPath">The path at which to place the resulting collage image.</param>
/// <param name="width">The desired width of the collage.</param>
/// <param name="height">The desired height of the collage.</param>
- public void BuildSquareCollage(string[] paths, string outputPath, int width, int height)
+ public void BuildSquareCollage(IReadOnlyList<string> paths, string outputPath, int width, int height)
{
using var bitmap = BuildSquareCollageBitmap(paths, width, height);
using var outputStream = new SKFileWStream(outputPath);
@@ -84,7 +84,7 @@ namespace Jellyfin.Drawing.Skia
/// <param name="width">The desired width of the collage.</param>
/// <param name="height">The desired height of the collage.</param>
/// <param name="libraryName">The name of the library to draw on the collage.</param>
- public void BuildThumbCollage(string[] paths, string outputPath, int width, int height, string? libraryName)
+ public void BuildThumbCollage(IReadOnlyList<string> paths, string outputPath, int width, int height, string? libraryName)
{
using var bitmap = BuildThumbCollageBitmap(paths, width, height, libraryName);
using var outputStream = new SKFileWStream(outputPath);
@@ -92,7 +92,7 @@ namespace Jellyfin.Drawing.Skia
pixmap.Encode(outputStream, GetEncodedFormat(outputPath), 90);
}
- private SKBitmap BuildThumbCollageBitmap(string[] paths, int width, int height, string? libraryName)
+ private SKBitmap BuildThumbCollageBitmap(IReadOnlyList<string> paths, int width, int height, string? libraryName)
{
var bitmap = new SKBitmap(width, height);
@@ -152,14 +152,14 @@ namespace Jellyfin.Drawing.Skia
return bitmap;
}
- private SKBitmap? GetNextValidImage(string[] paths, int currentIndex, out int newIndex)
+ private SKBitmap? GetNextValidImage(IReadOnlyList<string> paths, int currentIndex, out int newIndex)
{
var imagesTested = new Dictionary<int, int>();
SKBitmap? bitmap = null;
- while (imagesTested.Count < paths.Length)
+ while (imagesTested.Count < paths.Count)
{
- if (currentIndex >= paths.Length)
+ if (currentIndex >= paths.Count)
{
currentIndex = 0;
}
@@ -180,7 +180,7 @@ namespace Jellyfin.Drawing.Skia
return bitmap;
}
- private SKBitmap BuildSquareCollageBitmap(string[] paths, int width, int height)
+ private SKBitmap BuildSquareCollageBitmap(IReadOnlyList<string> paths, int width, int height)
{
var bitmap = new SKBitmap(width, height);
var imageIndex = 0;
diff --git a/Jellyfin.Networking/Manager/NetworkManager.cs b/Jellyfin.Networking/Manager/NetworkManager.cs
index 73e8b2cd7..4078fd126 100644
--- a/Jellyfin.Networking/Manager/NetworkManager.cs
+++ b/Jellyfin.Networking/Manager/NetworkManager.cs
@@ -1067,7 +1067,7 @@ namespace Jellyfin.Networking.Manager
}
// Internal interfaces must be private, not excluded and part of the LocalNetworkSubnet.
- _internalInterfaces = CreateCollection(_interfaceAddresses.Where(i => IsInLocalNetwork(i)));
+ _internalInterfaces = CreateCollection(_interfaceAddresses.Where(IsInLocalNetwork));
}
_logger.LogInformation("Defined LAN addresses : {0}", _lanSubnets.AsString());
diff --git a/Jellyfin.Server.Implementations/JellyfinDb.cs b/Jellyfin.Server.Implementations/JellyfinDb.cs
index 39f842354..db648472d 100644
--- a/Jellyfin.Server.Implementations/JellyfinDb.cs
+++ b/Jellyfin.Server.Implementations/JellyfinDb.cs
@@ -149,21 +149,77 @@ namespace Jellyfin.Server.Implementations
modelBuilder.HasDefaultSchema("jellyfin");
+ // Collations
+
+ modelBuilder.Entity<User>()
+ .Property(user => user.Username)
+ .UseCollation("NOCASE");
+
+ // Delete behavior
+
+ modelBuilder.Entity<User>()
+ .HasOne(u => u.ProfileImage)
+ .WithOne()
+ .OnDelete(DeleteBehavior.Cascade);
+
+ modelBuilder.Entity<User>()
+ .HasMany(u => u.Permissions)
+ .WithOne()
+ .HasForeignKey(p => p.UserId)
+ .OnDelete(DeleteBehavior.Cascade);
+
+ modelBuilder.Entity<User>()
+ .HasMany(u => u.Preferences)
+ .WithOne()
+ .HasForeignKey(p => p.UserId)
+ .OnDelete(DeleteBehavior.Cascade);
+
+ modelBuilder.Entity<User>()
+ .HasMany(u => u.AccessSchedules)
+ .WithOne()
+ .OnDelete(DeleteBehavior.Cascade);
+
+ modelBuilder.Entity<User>()
+ .HasMany(u => u.DisplayPreferences)
+ .WithOne()
+ .OnDelete(DeleteBehavior.Cascade);
+
+ modelBuilder.Entity<User>()
+ .HasMany(u => u.ItemDisplayPreferences)
+ .WithOne()
+ .OnDelete(DeleteBehavior.Cascade);
+
modelBuilder.Entity<DisplayPreferences>()
- .HasIndex(entity => entity.UserId)
- .IsUnique(false);
+ .HasMany(d => d.HomeSections)
+ .WithOne()
+ .OnDelete(DeleteBehavior.Cascade);
+
+ // Indexes
+
+ modelBuilder.Entity<User>()
+ .HasIndex(entity => entity.Username)
+ .IsUnique();
modelBuilder.Entity<DisplayPreferences>()
.HasIndex(entity => new { entity.UserId, entity.ItemId, entity.Client })
.IsUnique();
modelBuilder.Entity<CustomItemDisplayPreferences>()
- .HasIndex(entity => entity.UserId)
- .IsUnique(false);
-
- modelBuilder.Entity<CustomItemDisplayPreferences>()
.HasIndex(entity => new { entity.UserId, entity.ItemId, entity.Client, entity.Key })
.IsUnique();
+
+ // Used to get a user's permissions or a specific permission for a user.
+ // Also prevents multiple values being created for a user.
+ // Filtered over non-null user ids for when other entities (groups, API keys) get permissions
+ modelBuilder.Entity<Permission>()
+ .HasIndex(p => new { p.UserId, p.Kind })
+ .HasFilter("[UserId] IS NOT NULL")
+ .IsUnique();
+
+ modelBuilder.Entity<Preference>()
+ .HasIndex(p => new { p.UserId, p.Kind })
+ .HasFilter("[UserId] IS NOT NULL")
+ .IsUnique();
}
}
}
diff --git a/Jellyfin.Server.Implementations/Migrations/20210320181425_AddIndexesAndCollations.Designer.cs b/Jellyfin.Server.Implementations/Migrations/20210320181425_AddIndexesAndCollations.Designer.cs
new file mode 100644
index 000000000..869676824
--- /dev/null
+++ b/Jellyfin.Server.Implementations/Migrations/20210320181425_AddIndexesAndCollations.Designer.cs
@@ -0,0 +1,535 @@
+#pragma warning disable CS1591
+
+// <auto-generated />
+using System;
+using Jellyfin.Server.Implementations;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+
+namespace Jellyfin.Server.Implementations.Migrations
+{
+ [DbContext(typeof(JellyfinDb))]
+ [Migration("20210320181425_AddIndexesAndCollations")]
+ partial class AddIndexesAndCollations
+ {
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasDefaultSchema("jellyfin")
+ .HasAnnotation("ProductVersion", "5.0.3");
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property<int>("DayOfWeek")
+ .HasColumnType("INTEGER");
+
+ b.Property<double>("EndHour")
+ .HasColumnType("REAL");
+
+ b.Property<double>("StartHour")
+ .HasColumnType("REAL");
+
+ b.Property<Guid>("UserId")
+ .HasColumnType("TEXT");
+
+ b.HasKey("Id");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("AccessSchedules");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.ActivityLog", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property<DateTime>("DateCreated")
+ .HasColumnType("TEXT");
+
+ b.Property<string>("ItemId")
+ .HasMaxLength(256)
+ .HasColumnType("TEXT");
+
+ b.Property<int>("LogSeverity")
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("Name")
+ .IsRequired()
+ .HasMaxLength(512)
+ .HasColumnType("TEXT");
+
+ b.Property<string>("Overview")
+ .HasMaxLength(512)
+ .HasColumnType("TEXT");
+
+ b.Property<uint>("RowVersion")
+ .IsConcurrencyToken()
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("ShortOverview")
+ .HasMaxLength(512)
+ .HasColumnType("TEXT");
+
+ b.Property<string>("Type")
+ .IsRequired()
+ .HasMaxLength(256)
+ .HasColumnType("TEXT");
+
+ b.Property<Guid>("UserId")
+ .HasColumnType("TEXT");
+
+ b.HasKey("Id");
+
+ b.ToTable("ActivityLogs");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.CustomItemDisplayPreferences", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("Client")
+ .IsRequired()
+ .HasMaxLength(32)
+ .HasColumnType("TEXT");
+
+ b.Property<Guid>("ItemId")
+ .HasColumnType("TEXT");
+
+ b.Property<string>("Key")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property<Guid>("UserId")
+ .HasColumnType("TEXT");
+
+ b.Property<string>("Value")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.HasKey("Id");
+
+ b.HasIndex("UserId", "ItemId", "Client", "Key")
+ .IsUnique();
+
+ b.ToTable("CustomItemDisplayPreferences");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property<int>("ChromecastVersion")
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("Client")
+ .IsRequired()
+ .HasMaxLength(32)
+ .HasColumnType("TEXT");
+
+ b.Property<string>("DashboardTheme")
+ .HasMaxLength(32)
+ .HasColumnType("TEXT");
+
+ b.Property<bool>("EnableNextVideoInfoOverlay")
+ .HasColumnType("INTEGER");
+
+ b.Property<int?>("IndexBy")
+ .HasColumnType("INTEGER");
+
+ b.Property<Guid>("ItemId")
+ .HasColumnType("TEXT");
+
+ b.Property<int>("ScrollDirection")
+ .HasColumnType("INTEGER");
+
+ b.Property<bool>("ShowBackdrop")
+ .HasColumnType("INTEGER");
+
+ b.Property<bool>("ShowSidebar")
+ .HasColumnType("INTEGER");
+
+ b.Property<int>("SkipBackwardLength")
+ .HasColumnType("INTEGER");
+
+ b.Property<int>("SkipForwardLength")
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("TvHome")
+ .HasMaxLength(32)
+ .HasColumnType("TEXT");
+
+ b.Property<Guid>("UserId")
+ .HasColumnType("TEXT");
+
+ b.HasKey("Id");
+
+ b.HasIndex("UserId", "ItemId", "Client")
+ .IsUnique();
+
+ b.ToTable("DisplayPreferences");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property<int>("DisplayPreferencesId")
+ .HasColumnType("INTEGER");
+
+ b.Property<int>("Order")
+ .HasColumnType("INTEGER");
+
+ b.Property<int>("Type")
+ .HasColumnType("INTEGER");
+
+ b.HasKey("Id");
+
+ b.HasIndex("DisplayPreferencesId");
+
+ b.ToTable("HomeSection");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property<DateTime>("LastModified")
+ .HasColumnType("TEXT");
+
+ b.Property<string>("Path")
+ .IsRequired()
+ .HasMaxLength(512)
+ .HasColumnType("TEXT");
+
+ b.Property<Guid?>("UserId")
+ .HasColumnType("TEXT");
+
+ b.HasKey("Id");
+
+ b.HasIndex("UserId")
+ .IsUnique();
+
+ b.ToTable("ImageInfos");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("Client")
+ .IsRequired()
+ .HasMaxLength(32)
+ .HasColumnType("TEXT");
+
+ b.Property<int?>("IndexBy")
+ .HasColumnType("INTEGER");
+
+ b.Property<Guid>("ItemId")
+ .HasColumnType("TEXT");
+
+ b.Property<bool>("RememberIndexing")
+ .HasColumnType("INTEGER");
+
+ b.Property<bool>("RememberSorting")
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("SortBy")
+ .IsRequired()
+ .HasMaxLength(64)
+ .HasColumnType("TEXT");
+
+ b.Property<int>("SortOrder")
+ .HasColumnType("INTEGER");
+
+ b.Property<Guid>("UserId")
+ .HasColumnType("TEXT");
+
+ b.Property<int>("ViewType")
+ .HasColumnType("INTEGER");
+
+ b.HasKey("Id");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("ItemDisplayPreferences");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property<int>("Kind")
+ .HasColumnType("INTEGER");
+
+ b.Property<Guid?>("Permission_Permissions_Guid")
+ .HasColumnType("TEXT");
+
+ b.Property<uint>("RowVersion")
+ .IsConcurrencyToken()
+ .HasColumnType("INTEGER");
+
+ b.Property<Guid?>("UserId")
+ .HasColumnType("TEXT");
+
+ b.Property<bool>("Value")
+ .HasColumnType("INTEGER");
+
+ b.HasKey("Id");
+
+ b.HasIndex("UserId", "Kind")
+ .IsUnique()
+ .HasFilter("[UserId] IS NOT NULL");
+
+ b.ToTable("Permissions");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property<int>("Kind")
+ .HasColumnType("INTEGER");
+
+ b.Property<Guid?>("Preference_Preferences_Guid")
+ .HasColumnType("TEXT");
+
+ b.Property<uint>("RowVersion")
+ .IsConcurrencyToken()
+ .HasColumnType("INTEGER");
+
+ b.Property<Guid?>("UserId")
+ .HasColumnType("TEXT");
+
+ b.Property<string>("Value")
+ .IsRequired()
+ .HasMaxLength(65535)
+ .HasColumnType("TEXT");
+
+ b.HasKey("Id");
+
+ b.HasIndex("UserId", "Kind")
+ .IsUnique()
+ .HasFilter("[UserId] IS NOT NULL");
+
+ b.ToTable("Preferences");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.User", b =>
+ {
+ b.Property<Guid>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("TEXT");
+
+ b.Property<string>("AudioLanguagePreference")
+ .HasMaxLength(255)
+ .HasColumnType("TEXT");
+
+ b.Property<string>("AuthenticationProviderId")
+ .IsRequired()
+ .HasMaxLength(255)
+ .HasColumnType("TEXT");
+
+ b.Property<bool>("DisplayCollectionsView")
+ .HasColumnType("INTEGER");
+
+ b.Property<bool>("DisplayMissingEpisodes")
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("EasyPassword")
+ .HasMaxLength(65535)
+ .HasColumnType("TEXT");
+
+ b.Property<bool>("EnableAutoLogin")
+ .HasColumnType("INTEGER");
+
+ b.Property<bool>("EnableLocalPassword")
+ .HasColumnType("INTEGER");
+
+ b.Property<bool>("EnableNextEpisodeAutoPlay")
+ .HasColumnType("INTEGER");
+
+ b.Property<bool>("EnableUserPreferenceAccess")
+ .HasColumnType("INTEGER");
+
+ b.Property<bool>("HidePlayedInLatest")
+ .HasColumnType("INTEGER");
+
+ b.Property<long>("InternalId")
+ .HasColumnType("INTEGER");
+
+ b.Property<int>("InvalidLoginAttemptCount")
+ .HasColumnType("INTEGER");
+
+ b.Property<DateTime?>("LastActivityDate")
+ .HasColumnType("TEXT");
+
+ b.Property<DateTime?>("LastLoginDate")
+ .HasColumnType("TEXT");
+
+ b.Property<int?>("LoginAttemptsBeforeLockout")
+ .HasColumnType("INTEGER");
+
+ b.Property<int>("MaxActiveSessions")
+ .HasColumnType("INTEGER");
+
+ b.Property<int?>("MaxParentalAgeRating")
+ .HasColumnType("INTEGER");
+
+ b.Property<bool>("MustUpdatePassword")
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("Password")
+ .HasMaxLength(65535)
+ .HasColumnType("TEXT");
+
+ b.Property<string>("PasswordResetProviderId")
+ .IsRequired()
+ .HasMaxLength(255)
+ .HasColumnType("TEXT");
+
+ b.Property<bool>("PlayDefaultAudioTrack")
+ .HasColumnType("INTEGER");
+
+ b.Property<bool>("RememberAudioSelections")
+ .HasColumnType("INTEGER");
+
+ b.Property<bool>("RememberSubtitleSelections")
+ .HasColumnType("INTEGER");
+
+ b.Property<int?>("RemoteClientBitrateLimit")
+ .HasColumnType("INTEGER");
+
+ b.Property<uint>("RowVersion")
+ .IsConcurrencyToken()
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("SubtitleLanguagePreference")
+ .HasMaxLength(255)
+ .HasColumnType("TEXT");
+
+ b.Property<int>("SubtitleMode")
+ .HasColumnType("INTEGER");
+
+ b.Property<int>("SyncPlayAccess")
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("Username")
+ .IsRequired()
+ .HasMaxLength(255)
+ .HasColumnType("TEXT")
+ .UseCollation("NOCASE");
+
+ b.HasKey("Id");
+
+ b.HasIndex("Username")
+ .IsUnique();
+
+ b.ToTable("Users");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b =>
+ {
+ b.HasOne("Jellyfin.Data.Entities.User", null)
+ .WithMany("AccessSchedules")
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b =>
+ {
+ b.HasOne("Jellyfin.Data.Entities.User", null)
+ .WithMany("DisplayPreferences")
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b =>
+ {
+ b.HasOne("Jellyfin.Data.Entities.DisplayPreferences", null)
+ .WithMany("HomeSections")
+ .HasForeignKey("DisplayPreferencesId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b =>
+ {
+ b.HasOne("Jellyfin.Data.Entities.User", null)
+ .WithOne("ProfileImage")
+ .HasForeignKey("Jellyfin.Data.Entities.ImageInfo", "UserId")
+ .OnDelete(DeleteBehavior.Cascade);
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b =>
+ {
+ b.HasOne("Jellyfin.Data.Entities.User", null)
+ .WithMany("ItemDisplayPreferences")
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b =>
+ {
+ b.HasOne("Jellyfin.Data.Entities.User", null)
+ .WithMany("Permissions")
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade);
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b =>
+ {
+ b.HasOne("Jellyfin.Data.Entities.User", null)
+ .WithMany("Preferences")
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade);
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b =>
+ {
+ b.Navigation("HomeSections");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.User", b =>
+ {
+ b.Navigation("AccessSchedules");
+
+ b.Navigation("DisplayPreferences");
+
+ b.Navigation("ItemDisplayPreferences");
+
+ b.Navigation("Permissions");
+
+ b.Navigation("Preferences");
+
+ b.Navigation("ProfileImage");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/Jellyfin.Server.Implementations/Migrations/20210320181425_AddIndexesAndCollations.cs b/Jellyfin.Server.Implementations/Migrations/20210320181425_AddIndexesAndCollations.cs
new file mode 100644
index 000000000..506e4ae66
--- /dev/null
+++ b/Jellyfin.Server.Implementations/Migrations/20210320181425_AddIndexesAndCollations.cs
@@ -0,0 +1,240 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1601
+
+using System;
+using Microsoft.EntityFrameworkCore.Migrations;
+
+namespace Jellyfin.Server.Implementations.Migrations
+{
+ public partial class AddIndexesAndCollations : Migration
+ {
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropForeignKey(
+ name: "FK_ImageInfos_Users_UserId",
+ schema: "jellyfin",
+ table: "ImageInfos");
+
+ migrationBuilder.DropForeignKey(
+ name: "FK_Permissions_Users_Permission_Permissions_Guid",
+ schema: "jellyfin",
+ table: "Permissions");
+
+ migrationBuilder.DropForeignKey(
+ name: "FK_Preferences_Users_Preference_Preferences_Guid",
+ schema: "jellyfin",
+ table: "Preferences");
+
+ migrationBuilder.DropIndex(
+ name: "IX_Preferences_Preference_Preferences_Guid",
+ schema: "jellyfin",
+ table: "Preferences");
+
+ migrationBuilder.DropIndex(
+ name: "IX_Permissions_Permission_Permissions_Guid",
+ schema: "jellyfin",
+ table: "Permissions");
+
+ migrationBuilder.DropIndex(
+ name: "IX_DisplayPreferences_UserId",
+ schema: "jellyfin",
+ table: "DisplayPreferences");
+
+ migrationBuilder.DropIndex(
+ name: "IX_CustomItemDisplayPreferences_UserId",
+ schema: "jellyfin",
+ table: "CustomItemDisplayPreferences");
+
+ migrationBuilder.AlterColumn<string>(
+ name: "Username",
+ schema: "jellyfin",
+ table: "Users",
+ type: "TEXT",
+ maxLength: 255,
+ nullable: false,
+ collation: "NOCASE",
+ oldClrType: typeof(string),
+ oldType: "TEXT",
+ oldMaxLength: 255);
+
+ migrationBuilder.AddColumn<Guid>(
+ name: "UserId",
+ schema: "jellyfin",
+ table: "Preferences",
+ type: "TEXT",
+ nullable: true);
+
+ migrationBuilder.AddColumn<Guid>(
+ name: "UserId",
+ schema: "jellyfin",
+ table: "Permissions",
+ type: "TEXT",
+ nullable: true);
+
+ migrationBuilder.Sql("UPDATE Preferences SET UserId = Preference_Preferences_Guid");
+ migrationBuilder.Sql("UPDATE Permissions SET UserId = Permission_Permissions_Guid");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_Users_Username",
+ schema: "jellyfin",
+ table: "Users",
+ column: "Username",
+ unique: true);
+
+ migrationBuilder.CreateIndex(
+ name: "IX_Preferences_UserId_Kind",
+ schema: "jellyfin",
+ table: "Preferences",
+ columns: new[] { "UserId", "Kind" },
+ unique: true,
+ filter: "[UserId] IS NOT NULL");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_Permissions_UserId_Kind",
+ schema: "jellyfin",
+ table: "Permissions",
+ columns: new[] { "UserId", "Kind" },
+ unique: true,
+ filter: "[UserId] IS NOT NULL");
+
+ migrationBuilder.AddForeignKey(
+ name: "FK_ImageInfos_Users_UserId",
+ schema: "jellyfin",
+ table: "ImageInfos",
+ column: "UserId",
+ principalSchema: "jellyfin",
+ principalTable: "Users",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Cascade);
+
+ migrationBuilder.AddForeignKey(
+ name: "FK_Permissions_Users_UserId",
+ schema: "jellyfin",
+ table: "Permissions",
+ column: "UserId",
+ principalSchema: "jellyfin",
+ principalTable: "Users",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Cascade);
+
+ migrationBuilder.AddForeignKey(
+ name: "FK_Preferences_Users_UserId",
+ schema: "jellyfin",
+ table: "Preferences",
+ column: "UserId",
+ principalSchema: "jellyfin",
+ principalTable: "Users",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Cascade);
+ }
+
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropForeignKey(
+ name: "FK_ImageInfos_Users_UserId",
+ schema: "jellyfin",
+ table: "ImageInfos");
+
+ migrationBuilder.DropForeignKey(
+ name: "FK_Permissions_Users_UserId",
+ schema: "jellyfin",
+ table: "Permissions");
+
+ migrationBuilder.DropForeignKey(
+ name: "FK_Preferences_Users_UserId",
+ schema: "jellyfin",
+ table: "Preferences");
+
+ migrationBuilder.DropIndex(
+ name: "IX_Users_Username",
+ schema: "jellyfin",
+ table: "Users");
+
+ migrationBuilder.DropIndex(
+ name: "IX_Preferences_UserId_Kind",
+ schema: "jellyfin",
+ table: "Preferences");
+
+ migrationBuilder.DropIndex(
+ name: "IX_Permissions_UserId_Kind",
+ schema: "jellyfin",
+ table: "Permissions");
+
+ migrationBuilder.DropColumn(
+ name: "UserId",
+ schema: "jellyfin",
+ table: "Preferences");
+
+ migrationBuilder.DropColumn(
+ name: "UserId",
+ schema: "jellyfin",
+ table: "Permissions");
+
+ migrationBuilder.AlterColumn<string>(
+ name: "Username",
+ schema: "jellyfin",
+ table: "Users",
+ type: "TEXT",
+ maxLength: 255,
+ nullable: false,
+ oldClrType: typeof(string),
+ oldType: "TEXT",
+ oldMaxLength: 255,
+ oldCollation: "NOCASE");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_Preferences_Preference_Preferences_Guid",
+ schema: "jellyfin",
+ table: "Preferences",
+ column: "Preference_Preferences_Guid");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_Permissions_Permission_Permissions_Guid",
+ schema: "jellyfin",
+ table: "Permissions",
+ column: "Permission_Permissions_Guid");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_DisplayPreferences_UserId",
+ schema: "jellyfin",
+ table: "DisplayPreferences",
+ column: "UserId");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_CustomItemDisplayPreferences_UserId",
+ schema: "jellyfin",
+ table: "CustomItemDisplayPreferences",
+ column: "UserId");
+
+ migrationBuilder.AddForeignKey(
+ name: "FK_ImageInfos_Users_UserId",
+ schema: "jellyfin",
+ table: "ImageInfos",
+ column: "UserId",
+ principalSchema: "jellyfin",
+ principalTable: "Users",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Restrict);
+
+ migrationBuilder.AddForeignKey(
+ name: "FK_Permissions_Users_Permission_Permissions_Guid",
+ schema: "jellyfin",
+ table: "Permissions",
+ column: "Permission_Permissions_Guid",
+ principalSchema: "jellyfin",
+ principalTable: "Users",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Restrict);
+
+ migrationBuilder.AddForeignKey(
+ name: "FK_Preferences_Users_Preference_Preferences_Guid",
+ schema: "jellyfin",
+ table: "Preferences",
+ column: "Preference_Preferences_Guid",
+ principalSchema: "jellyfin",
+ principalTable: "Users",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Restrict);
+ }
+ }
+}
diff --git a/Jellyfin.Server.Implementations/Migrations/JellyfinDbModelSnapshot.cs b/Jellyfin.Server.Implementations/Migrations/JellyfinDbModelSnapshot.cs
index 6a523ba68..286eb7468 100644
--- a/Jellyfin.Server.Implementations/Migrations/JellyfinDbModelSnapshot.cs
+++ b/Jellyfin.Server.Implementations/Migrations/JellyfinDbModelSnapshot.cs
@@ -114,8 +114,6 @@ namespace Jellyfin.Server.Implementations.Migrations
b.HasKey("Id");
- b.HasIndex("UserId");
-
b.HasIndex("UserId", "ItemId", "Client", "Key")
.IsUnique();
@@ -173,8 +171,6 @@ namespace Jellyfin.Server.Implementations.Migrations
b.HasKey("Id");
- b.HasIndex("UserId");
-
b.HasIndex("UserId", "ItemId", "Client")
.IsUnique();
@@ -288,12 +284,17 @@ namespace Jellyfin.Server.Implementations.Migrations
.IsConcurrencyToken()
.HasColumnType("INTEGER");
+ b.Property<Guid?>("UserId")
+ .HasColumnType("TEXT");
+
b.Property<bool>("Value")
.HasColumnType("INTEGER");
b.HasKey("Id");
- b.HasIndex("Permission_Permissions_Guid");
+ b.HasIndex("UserId", "Kind")
+ .IsUnique()
+ .HasFilter("[UserId] IS NOT NULL");
b.ToTable("Permissions");
});
@@ -314,6 +315,9 @@ namespace Jellyfin.Server.Implementations.Migrations
.IsConcurrencyToken()
.HasColumnType("INTEGER");
+ b.Property<Guid?>("UserId")
+ .HasColumnType("TEXT");
+
b.Property<string>("Value")
.IsRequired()
.HasMaxLength(65535)
@@ -321,7 +325,9 @@ namespace Jellyfin.Server.Implementations.Migrations
b.HasKey("Id");
- b.HasIndex("Preference_Preferences_Guid");
+ b.HasIndex("UserId", "Kind")
+ .IsUnique()
+ .HasFilter("[UserId] IS NOT NULL");
b.ToTable("Preferences");
});
@@ -428,10 +434,14 @@ namespace Jellyfin.Server.Implementations.Migrations
b.Property<string>("Username")
.IsRequired()
.HasMaxLength(255)
- .HasColumnType("TEXT");
+ .HasColumnType("TEXT")
+ .UseCollation("NOCASE");
b.HasKey("Id");
+ b.HasIndex("Username")
+ .IsUnique();
+
b.ToTable("Users");
});
@@ -466,7 +476,8 @@ namespace Jellyfin.Server.Implementations.Migrations
{
b.HasOne("Jellyfin.Data.Entities.User", null)
.WithOne("ProfileImage")
- .HasForeignKey("Jellyfin.Data.Entities.ImageInfo", "UserId");
+ .HasForeignKey("Jellyfin.Data.Entities.ImageInfo", "UserId")
+ .OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b =>
@@ -482,14 +493,16 @@ namespace Jellyfin.Server.Implementations.Migrations
{
b.HasOne("Jellyfin.Data.Entities.User", null)
.WithMany("Permissions")
- .HasForeignKey("Permission_Permissions_Guid");
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b =>
{
b.HasOne("Jellyfin.Data.Entities.User", null)
.WithMany("Preferences")
- .HasForeignKey("Preference_Preferences_Guid");
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b =>
diff --git a/Jellyfin.Server.Implementations/Users/UserManager.cs b/Jellyfin.Server.Implementations/Users/UserManager.cs
index a2c11cb8a..27d4f40d3 100644
--- a/Jellyfin.Server.Implementations/Users/UserManager.cs
+++ b/Jellyfin.Server.Implementations/Users/UserManager.cs
@@ -144,7 +144,13 @@ namespace Jellyfin.Server.Implementations.Users
throw new ArgumentException("The new and old names must be different.");
}
- if (Users.Any(u => u.Id != user.Id && u.Username.Equals(newName, StringComparison.OrdinalIgnoreCase)))
+ await using var dbContext = _dbProvider.CreateContext();
+
+ if (await dbContext.Users
+ .AsQueryable()
+ .Where(u => u.Username == newName && u.Id != user.Id)
+ .AnyAsync()
+ .ConfigureAwait(false))
{
throw new ArgumentException(string.Format(
CultureInfo.InvariantCulture,
@@ -251,16 +257,6 @@ namespace Jellyfin.Server.Implementations.Users
}
await using var dbContext = _dbProvider.CreateContext();
-
- // Clear all entities related to the user from the database.
- if (user.ProfileImage != null)
- {
- dbContext.Remove(user.ProfileImage);
- }
-
- dbContext.RemoveRange(user.Permissions);
- dbContext.RemoveRange(user.Preferences);
- dbContext.RemoveRange(user.AccessSchedules);
dbContext.Users.Remove(user);
await dbContext.SaveChangesAsync().ConfigureAwait(false);
_users.Remove(userId);
diff --git a/Jellyfin.Server/Migrations/Routines/CreateUserLoggingConfigFile.cs b/Jellyfin.Server/Migrations/Routines/CreateUserLoggingConfigFile.cs
index 6821630db..ee4f8b0ba 100644
--- a/Jellyfin.Server/Migrations/Routines/CreateUserLoggingConfigFile.cs
+++ b/Jellyfin.Server/Migrations/Routines/CreateUserLoggingConfigFile.cs
@@ -75,7 +75,7 @@ namespace Jellyfin.Server.Migrations.Routines
{
var existingConfigJson = JToken.Parse(File.ReadAllText(oldConfigPath));
return _defaultConfigHistory
- .Select(historicalConfigText => JToken.Parse(historicalConfigText))
+ .Select(JToken.Parse)
.Any(historicalConfigJson => JToken.DeepEquals(existingConfigJson, historicalConfigJson));
}
}
diff --git a/MediaBrowser.Common/Configuration/ConfigurationStore.cs b/MediaBrowser.Common/Configuration/ConfigurationStore.cs
index d31d45e4c..050ab1ab5 100644
--- a/MediaBrowser.Common/Configuration/ConfigurationStore.cs
+++ b/MediaBrowser.Common/Configuration/ConfigurationStore.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
namespace MediaBrowser.Common.Configuration
diff --git a/MediaBrowser.Common/Configuration/ConfigurationUpdateEventArgs.cs b/MediaBrowser.Common/Configuration/ConfigurationUpdateEventArgs.cs
index 344aecf53..2df87d879 100644
--- a/MediaBrowser.Common/Configuration/ConfigurationUpdateEventArgs.cs
+++ b/MediaBrowser.Common/Configuration/ConfigurationUpdateEventArgs.cs
@@ -1,3 +1,4 @@
+#nullable disable
#pragma warning disable CS1591
using System;
diff --git a/MediaBrowser.Common/Configuration/IApplicationPaths.cs b/MediaBrowser.Common/Configuration/IApplicationPaths.cs
index 57c654667..1370e6d79 100644
--- a/MediaBrowser.Common/Configuration/IApplicationPaths.cs
+++ b/MediaBrowser.Common/Configuration/IApplicationPaths.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
namespace MediaBrowser.Common.Configuration
{
/// <summary>
diff --git a/MediaBrowser.Common/Cryptography/PasswordHash.cs b/MediaBrowser.Common/Cryptography/PasswordHash.cs
index ec21d0580..0e2065302 100644
--- a/MediaBrowser.Common/Cryptography/PasswordHash.cs
+++ b/MediaBrowser.Common/Cryptography/PasswordHash.cs
@@ -1,5 +1,4 @@
#pragma warning disable CS1591
-#nullable enable
using System;
using System.Collections.Generic;
diff --git a/MediaBrowser.Common/Events/EventHelper.cs b/MediaBrowser.Common/Events/EventHelper.cs
index c9d3226ac..a9cf86fbc 100644
--- a/MediaBrowser.Common/Events/EventHelper.cs
+++ b/MediaBrowser.Common/Events/EventHelper.cs
@@ -17,7 +17,7 @@ namespace MediaBrowser.Common.Events
/// <param name="sender">The sender.</param>
/// <param name="args">The <see cref="EventArgs" /> instance containing the event data.</param>
/// <param name="logger">The logger.</param>
- public static void QueueEventIfNotNull(EventHandler handler, object sender, EventArgs args, ILogger logger)
+ public static void QueueEventIfNotNull(EventHandler? handler, object sender, EventArgs args, ILogger logger)
{
if (handler != null)
{
@@ -43,7 +43,7 @@ namespace MediaBrowser.Common.Events
/// <param name="sender">The sender.</param>
/// <param name="args">The args.</param>
/// <param name="logger">The logger.</param>
- public static void QueueEventIfNotNull<T>(EventHandler<T> handler, object sender, T args, ILogger logger)
+ public static void QueueEventIfNotNull<T>(EventHandler<T>? handler, object sender, T args, ILogger logger)
{
if (handler != null)
{
diff --git a/MediaBrowser.Common/Extensions/BaseExtensions.cs b/MediaBrowser.Common/Extensions/BaseExtensions.cs
index 40020093b..08964420e 100644
--- a/MediaBrowser.Common/Extensions/BaseExtensions.cs
+++ b/MediaBrowser.Common/Extensions/BaseExtensions.cs
@@ -1,5 +1,3 @@
-#nullable enable
-
using System;
using System.Security.Cryptography;
using System.Text;
diff --git a/MediaBrowser.Common/Extensions/CopyToExtensions.cs b/MediaBrowser.Common/Extensions/CopyToExtensions.cs
index 94bf7c740..2ecbc6539 100644
--- a/MediaBrowser.Common/Extensions/CopyToExtensions.cs
+++ b/MediaBrowser.Common/Extensions/CopyToExtensions.cs
@@ -1,5 +1,3 @@
-#nullable enable
-
using System.Collections.Generic;
namespace MediaBrowser.Common.Extensions
diff --git a/MediaBrowser.Common/Extensions/HttpContextExtensions.cs b/MediaBrowser.Common/Extensions/HttpContextExtensions.cs
index e51ad42d1..1e5877c84 100644
--- a/MediaBrowser.Common/Extensions/HttpContextExtensions.cs
+++ b/MediaBrowser.Common/Extensions/HttpContextExtensions.cs
@@ -17,7 +17,7 @@ namespace MediaBrowser.Common.Extensions
{
return (context.Connection.LocalIpAddress == null
&& context.Connection.RemoteIpAddress == null)
- || context.Connection.LocalIpAddress.Equals(context.Connection.RemoteIpAddress);
+ || Equals(context.Connection.LocalIpAddress, context.Connection.RemoteIpAddress);
}
/// <summary>
diff --git a/MediaBrowser.Common/Extensions/MethodNotAllowedException.cs b/MediaBrowser.Common/Extensions/MethodNotAllowedException.cs
index 258bd6662..48e758ee4 100644
--- a/MediaBrowser.Common/Extensions/MethodNotAllowedException.cs
+++ b/MediaBrowser.Common/Extensions/MethodNotAllowedException.cs
@@ -1,5 +1,3 @@
-#nullable enable
-
using System;
namespace MediaBrowser.Common.Extensions
diff --git a/MediaBrowser.Common/Extensions/ProcessExtensions.cs b/MediaBrowser.Common/Extensions/ProcessExtensions.cs
index 2f52ba196..c74787122 100644
--- a/MediaBrowser.Common/Extensions/ProcessExtensions.cs
+++ b/MediaBrowser.Common/Extensions/ProcessExtensions.cs
@@ -1,5 +1,3 @@
-#nullable enable
-
using System;
using System.Diagnostics;
using System.Threading;
diff --git a/MediaBrowser.Common/Extensions/RateLimitExceededException.cs b/MediaBrowser.Common/Extensions/RateLimitExceededException.cs
index 7c7bdaa92..95802a462 100644
--- a/MediaBrowser.Common/Extensions/RateLimitExceededException.cs
+++ b/MediaBrowser.Common/Extensions/RateLimitExceededException.cs
@@ -1,4 +1,3 @@
-#nullable enable
#pragma warning disable CS1591
using System;
diff --git a/MediaBrowser.Common/Extensions/ResourceNotFoundException.cs b/MediaBrowser.Common/Extensions/ResourceNotFoundException.cs
index ebac9d8e6..22130c5a1 100644
--- a/MediaBrowser.Common/Extensions/ResourceNotFoundException.cs
+++ b/MediaBrowser.Common/Extensions/ResourceNotFoundException.cs
@@ -1,5 +1,3 @@
-#nullable enable
-
using System;
namespace MediaBrowser.Common.Extensions
diff --git a/MediaBrowser.Common/Extensions/ShuffleExtensions.cs b/MediaBrowser.Common/Extensions/ShuffleExtensions.cs
index 6f0ea9bd5..2604abf85 100644
--- a/MediaBrowser.Common/Extensions/ShuffleExtensions.cs
+++ b/MediaBrowser.Common/Extensions/ShuffleExtensions.cs
@@ -1,5 +1,3 @@
-#nullable enable
-
using System;
using System.Collections.Generic;
diff --git a/MediaBrowser.Common/Extensions/SplitStringExtensions.cs b/MediaBrowser.Common/Extensions/SplitStringExtensions.cs
new file mode 100644
index 000000000..9c9108495
--- /dev/null
+++ b/MediaBrowser.Common/Extensions/SplitStringExtensions.cs
@@ -0,0 +1,95 @@
+/*
+MIT License
+
+Copyright (c) 2019 Gérald Barré
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+ */
+
+#pragma warning disable CS1591
+#pragma warning disable CA1034
+using System;
+using System.Diagnostics.Contracts;
+using System.Runtime.InteropServices;
+
+namespace MediaBrowser.Common.Extensions
+{
+ /// <summary>
+ /// Extension class for splitting lines without unnecessary allocations.
+ /// </summary>
+ public static class SplitStringExtensions
+ {
+ /// <summary>
+ /// Creates a new string split enumerator.
+ /// </summary>
+ /// <param name="str">The string to split.</param>
+ /// <param name="separator">The separator to split on.</param>
+ /// <returns>The enumerator struct.</returns>
+ [Pure]
+ public static SplitEnumerator SpanSplit(this string str, char separator) => new (str.AsSpan(), separator);
+
+ /// <summary>
+ /// Creates a new span split enumerator.
+ /// </summary>
+ /// <param name="str">The span to split.</param>
+ /// <param name="separator">The separator to split on.</param>
+ /// <returns>The enumerator struct.</returns>
+ [Pure]
+ public static SplitEnumerator Split(this ReadOnlySpan<char> str, char separator) => new (str, separator);
+
+ [StructLayout(LayoutKind.Auto)]
+ public ref struct SplitEnumerator
+ {
+ private readonly char _separator;
+ private ReadOnlySpan<char> _str;
+
+ public SplitEnumerator(ReadOnlySpan<char> str, char separator)
+ {
+ _str = str;
+ _separator = separator;
+ Current = default;
+ }
+
+ public ReadOnlySpan<char> Current { get; private set; }
+
+ public readonly SplitEnumerator GetEnumerator() => this;
+
+ public bool MoveNext()
+ {
+ if (_str.Length == 0)
+ {
+ return false;
+ }
+
+ var span = _str;
+ var index = span.IndexOf(_separator);
+ if (index == -1)
+ {
+ _str = ReadOnlySpan<char>.Empty;
+ Current = span;
+ return true;
+ }
+
+ Current = span.Slice(0, index);
+ _str = span[(index + 1)..];
+ return true;
+ }
+ }
+ }
+}
diff --git a/MediaBrowser.Common/Extensions/StreamExtensions.cs b/MediaBrowser.Common/Extensions/StreamExtensions.cs
index cd77be7b2..5cbf57d98 100644
--- a/MediaBrowser.Common/Extensions/StreamExtensions.cs
+++ b/MediaBrowser.Common/Extensions/StreamExtensions.cs
@@ -1,5 +1,3 @@
-#nullable enable
-
using System.Collections.Generic;
using System.IO;
using System.Linq;
@@ -35,11 +33,11 @@ namespace MediaBrowser.Common.Extensions
}
/// <summary>
- /// Reads all lines in the <see cref="StreamReader" />.
+ /// Reads all lines in the <see cref="TextReader" />.
/// </summary>
- /// <param name="reader">The <see cref="StreamReader" /> to read from.</param>
+ /// <param name="reader">The <see cref="TextReader" /> to read from.</param>
/// <returns>All lines in the stream.</returns>
- public static IEnumerable<string> ReadAllLines(this StreamReader reader)
+ public static IEnumerable<string> ReadAllLines(this TextReader reader)
{
string? line;
while ((line = reader.ReadLine()) != null)
@@ -47,5 +45,19 @@ namespace MediaBrowser.Common.Extensions
yield return line;
}
}
+
+ /// <summary>
+ /// Reads all lines in the <see cref="TextReader" />.
+ /// </summary>
+ /// <param name="reader">The <see cref="TextReader" /> to read from.</param>
+ /// <returns>All lines in the stream.</returns>
+ public static async IAsyncEnumerable<string> ReadAllLinesAsync(this TextReader reader)
+ {
+ string? line;
+ while ((line = await reader.ReadLineAsync().ConfigureAwait(false)) != null)
+ {
+ yield return line;
+ }
+ }
}
}
diff --git a/MediaBrowser.Common/IApplicationHost.cs b/MediaBrowser.Common/IApplicationHost.cs
index c3e4ed6db..46d93e494 100644
--- a/MediaBrowser.Common/IApplicationHost.cs
+++ b/MediaBrowser.Common/IApplicationHost.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections.Generic;
using System.Reflection;
diff --git a/MediaBrowser.Common/Json/Converters/JsonCommaDelimitedArrayConverter.cs b/MediaBrowser.Common/Json/Converters/JsonCommaDelimitedArrayConverter.cs
index 2ec702165..127a41a06 100644
--- a/MediaBrowser.Common/Json/Converters/JsonCommaDelimitedArrayConverter.cs
+++ b/MediaBrowser.Common/Json/Converters/JsonCommaDelimitedArrayConverter.cs
@@ -9,67 +9,16 @@ namespace MediaBrowser.Common.Json.Converters
/// Convert comma delimited string to array of type.
/// </summary>
/// <typeparam name="T">Type to convert to.</typeparam>
- public class JsonCommaDelimitedArrayConverter<T> : JsonConverter<T[]>
+ public sealed class JsonCommaDelimitedArrayConverter<T> : JsonDelimitedArrayConverter<T>
{
- private readonly TypeConverter _typeConverter;
-
/// <summary>
/// Initializes a new instance of the <see cref="JsonCommaDelimitedArrayConverter{T}"/> class.
/// </summary>
- public JsonCommaDelimitedArrayConverter()
+ public JsonCommaDelimitedArrayConverter() : base()
{
- _typeConverter = TypeDescriptor.GetConverter(typeof(T));
}
/// <inheritdoc />
- public override T[] Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
- {
- if (reader.TokenType == JsonTokenType.String)
- {
- var stringEntries = reader.GetString().Split(',', StringSplitOptions.RemoveEmptyEntries);
- if (stringEntries.Length == 0)
- {
- return Array.Empty<T>();
- }
-
- var parsedValues = new object[stringEntries.Length];
- var convertedCount = 0;
- for (var i = 0; i < stringEntries.Length; i++)
- {
- try
- {
- parsedValues[i] = _typeConverter.ConvertFrom(stringEntries[i].Trim());
- convertedCount++;
- }
- catch (FormatException)
- {
- // TODO log when upgraded to .Net6
- // https://github.com/dotnet/runtime/issues/42975
- // _logger.LogDebug(e, "Error converting value.");
- }
- }
-
- var typedValues = new T[convertedCount];
- var typedValueIndex = 0;
- for (var i = 0; i < stringEntries.Length; i++)
- {
- if (parsedValues[i] != null)
- {
- typedValues.SetValue(parsedValues[i], typedValueIndex);
- typedValueIndex++;
- }
- }
-
- return typedValues;
- }
-
- return JsonSerializer.Deserialize<T[]>(ref reader, options);
- }
-
- /// <inheritdoc />
- public override void Write(Utf8JsonWriter writer, T[] value, JsonSerializerOptions options)
- {
- throw new NotImplementedException();
- }
+ protected override char Delimiter => ',';
}
}
diff --git a/MediaBrowser.Common/Json/Converters/JsonCommaDelimitedArrayConverterFactory.cs b/MediaBrowser.Common/Json/Converters/JsonCommaDelimitedArrayConverterFactory.cs
index 24ed3ea19..de41348dd 100644
--- a/MediaBrowser.Common/Json/Converters/JsonCommaDelimitedArrayConverterFactory.cs
+++ b/MediaBrowser.Common/Json/Converters/JsonCommaDelimitedArrayConverterFactory.cs
@@ -19,10 +19,10 @@ namespace MediaBrowser.Common.Json.Converters
}
/// <inheritdoc />
- public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options)
+ public override JsonConverter? CreateConverter(Type typeToConvert, JsonSerializerOptions options)
{
var structType = typeToConvert.GetElementType() ?? typeToConvert.GenericTypeArguments[0];
- return (JsonConverter)Activator.CreateInstance(typeof(JsonCommaDelimitedArrayConverter<>).MakeGenericType(structType));
+ return (JsonConverter?)Activator.CreateInstance(typeof(JsonCommaDelimitedArrayConverter<>).MakeGenericType(structType));
}
}
}
diff --git a/MediaBrowser.Common/Json/Converters/JsonDelimitedArrayConverter.cs b/MediaBrowser.Common/Json/Converters/JsonDelimitedArrayConverter.cs
new file mode 100644
index 000000000..b691798c9
--- /dev/null
+++ b/MediaBrowser.Common/Json/Converters/JsonDelimitedArrayConverter.cs
@@ -0,0 +1,81 @@
+using System;
+using System.ComponentModel;
+using System.Text.Json;
+using System.Text.Json.Serialization;
+
+namespace MediaBrowser.Common.Json.Converters
+{
+ /// <summary>
+ /// Convert delimited string to array of type.
+ /// </summary>
+ /// <typeparam name="T">Type to convert to.</typeparam>
+ public abstract class JsonDelimitedArrayConverter<T> : JsonConverter<T[]?>
+ {
+ private readonly TypeConverter _typeConverter;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="JsonDelimitedArrayConverter{T}"/> class.
+ /// </summary>
+ protected JsonDelimitedArrayConverter()
+ {
+ _typeConverter = TypeDescriptor.GetConverter(typeof(T));
+ }
+
+ /// <summary>
+ /// Gets the array delimiter.
+ /// </summary>
+ protected virtual char Delimiter { get; }
+
+ /// <inheritdoc />
+ public override T[]? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+ {
+ if (reader.TokenType == JsonTokenType.String)
+ {
+ // GetString can't return null here because we already handled it above
+ var stringEntries = reader.GetString()?.Split(Delimiter, StringSplitOptions.RemoveEmptyEntries);
+ if (stringEntries == null || stringEntries.Length == 0)
+ {
+ return Array.Empty<T>();
+ }
+
+ var parsedValues = new object[stringEntries.Length];
+ var convertedCount = 0;
+ for (var i = 0; i < stringEntries.Length; i++)
+ {
+ try
+ {
+ parsedValues[i] = _typeConverter.ConvertFrom(stringEntries[i].Trim());
+ convertedCount++;
+ }
+ catch (FormatException)
+ {
+ // TODO log when upgraded to .Net6
+ // https://github.com/dotnet/runtime/issues/42975
+ // _logger.LogDebug(e, "Error converting value.");
+ }
+ }
+
+ var typedValues = new T[convertedCount];
+ var typedValueIndex = 0;
+ for (var i = 0; i < stringEntries.Length; i++)
+ {
+ if (parsedValues[i] != null)
+ {
+ typedValues.SetValue(parsedValues[i], typedValueIndex);
+ typedValueIndex++;
+ }
+ }
+
+ return typedValues;
+ }
+
+ return JsonSerializer.Deserialize<T[]>(ref reader, options);
+ }
+
+ /// <inheritdoc />
+ public override void Write(Utf8JsonWriter writer, T[]? value, JsonSerializerOptions options)
+ {
+ throw new NotImplementedException();
+ }
+ }
+}
diff --git a/MediaBrowser.Common/Json/Converters/JsonNullableStructConverterFactory.cs b/MediaBrowser.Common/Json/Converters/JsonNullableStructConverterFactory.cs
index d5b54e3ca..e2a3d798a 100644
--- a/MediaBrowser.Common/Json/Converters/JsonNullableStructConverterFactory.cs
+++ b/MediaBrowser.Common/Json/Converters/JsonNullableStructConverterFactory.cs
@@ -18,10 +18,10 @@ namespace MediaBrowser.Common.Json.Converters
}
/// <inheritdoc />
- public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options)
+ public override JsonConverter? CreateConverter(Type typeToConvert, JsonSerializerOptions options)
{
var structType = typeToConvert.GenericTypeArguments[0];
- return (JsonConverter)Activator.CreateInstance(typeof(JsonNullableStructConverter<>).MakeGenericType(structType));
+ return (JsonConverter?)Activator.CreateInstance(typeof(JsonNullableStructConverter<>).MakeGenericType(structType));
}
}
-} \ No newline at end of file
+}
diff --git a/MediaBrowser.Common/Json/Converters/JsonOmdbNotAvailableStringConverter.cs b/MediaBrowser.Common/Json/Converters/JsonOmdbNotAvailableStringConverter.cs
index 6a8790374..77cf46b70 100644
--- a/MediaBrowser.Common/Json/Converters/JsonOmdbNotAvailableStringConverter.cs
+++ b/MediaBrowser.Common/Json/Converters/JsonOmdbNotAvailableStringConverter.cs
@@ -7,15 +7,21 @@ namespace MediaBrowser.Common.Json.Converters
/// <summary>
/// Converts a string <c>N/A</c> to <c>string.Empty</c>.
/// </summary>
- public class JsonOmdbNotAvailableStringConverter : JsonConverter<string>
+ public class JsonOmdbNotAvailableStringConverter : JsonConverter<string?>
{
/// <inheritdoc />
- public override string Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+ public override string? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
+ if (reader.TokenType == JsonTokenType.Null)
+ {
+ return null;
+ }
+
if (reader.TokenType == JsonTokenType.String)
{
- var str = reader.GetString();
- if (str != null && str.Equals("N/A", StringComparison.OrdinalIgnoreCase))
+ // GetString can't return null here because we already handled it above
+ var str = reader.GetString()!;
+ if (str.Equals("N/A", StringComparison.OrdinalIgnoreCase))
{
return null;
}
@@ -23,11 +29,11 @@ namespace MediaBrowser.Common.Json.Converters
return str;
}
- return JsonSerializer.Deserialize<string>(ref reader, options);
+ return JsonSerializer.Deserialize<string?>(ref reader, options);
}
/// <inheritdoc />
- public override void Write(Utf8JsonWriter writer, string value, JsonSerializerOptions options)
+ public override void Write(Utf8JsonWriter writer, string? value, JsonSerializerOptions options)
{
writer.WriteStringValue(value);
}
diff --git a/MediaBrowser.Common/Json/Converters/JsonPipeDelimitedArrayConverter.cs b/MediaBrowser.Common/Json/Converters/JsonPipeDelimitedArrayConverter.cs
index c408a3be1..a8f6cfbec 100644
--- a/MediaBrowser.Common/Json/Converters/JsonPipeDelimitedArrayConverter.cs
+++ b/MediaBrowser.Common/Json/Converters/JsonPipeDelimitedArrayConverter.cs
@@ -9,67 +9,16 @@ namespace MediaBrowser.Common.Json.Converters
/// Convert Pipe delimited string to array of type.
/// </summary>
/// <typeparam name="T">Type to convert to.</typeparam>
- public class JsonPipeDelimitedArrayConverter<T> : JsonConverter<T[]>
+ public sealed class JsonPipeDelimitedArrayConverter<T> : JsonDelimitedArrayConverter<T>
{
- private readonly TypeConverter _typeConverter;
-
/// <summary>
/// Initializes a new instance of the <see cref="JsonPipeDelimitedArrayConverter{T}"/> class.
/// </summary>
- public JsonPipeDelimitedArrayConverter()
+ public JsonPipeDelimitedArrayConverter() : base()
{
- _typeConverter = TypeDescriptor.GetConverter(typeof(T));
}
/// <inheritdoc />
- public override T[] Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
- {
- if (reader.TokenType == JsonTokenType.String)
- {
- var stringEntries = reader.GetString()?.Split('|', StringSplitOptions.RemoveEmptyEntries);
- if (stringEntries == null || stringEntries.Length == 0)
- {
- return Array.Empty<T>();
- }
-
- var parsedValues = new object[stringEntries.Length];
- var convertedCount = 0;
- for (var i = 0; i < stringEntries.Length; i++)
- {
- try
- {
- parsedValues[i] = _typeConverter.ConvertFrom(stringEntries[i].Trim());
- convertedCount++;
- }
- catch (FormatException)
- {
- // TODO log when upgraded to .Net6
- // https://github.com/dotnet/runtime/issues/42975
- // _logger.LogDebug(e, "Error converting value.");
- }
- }
-
- var typedValues = new T[convertedCount];
- var typedValueIndex = 0;
- for (var i = 0; i < stringEntries.Length; i++)
- {
- if (parsedValues[i] != null)
- {
- typedValues.SetValue(parsedValues[i], typedValueIndex);
- typedValueIndex++;
- }
- }
-
- return typedValues;
- }
-
- return JsonSerializer.Deserialize<T[]>(ref reader, options);
- }
-
- /// <inheritdoc />
- public override void Write(Utf8JsonWriter writer, T[] value, JsonSerializerOptions options)
- {
- throw new NotImplementedException();
- }
+ protected override char Delimiter => '|';
}
}
diff --git a/MediaBrowser.Common/Json/Converters/JsonPipeDelimitedArrayConverterFactory.cs b/MediaBrowser.Common/Json/Converters/JsonPipeDelimitedArrayConverterFactory.cs
index 5e77223ef..1bebc49ec 100644
--- a/MediaBrowser.Common/Json/Converters/JsonPipeDelimitedArrayConverterFactory.cs
+++ b/MediaBrowser.Common/Json/Converters/JsonPipeDelimitedArrayConverterFactory.cs
@@ -19,10 +19,10 @@ namespace MediaBrowser.Common.Json.Converters
}
/// <inheritdoc />
- public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options)
+ public override JsonConverter? CreateConverter(Type typeToConvert, JsonSerializerOptions options)
{
var structType = typeToConvert.GetElementType() ?? typeToConvert.GenericTypeArguments[0];
- return (JsonConverter)Activator.CreateInstance(typeof(JsonPipeDelimitedArrayConverter<>).MakeGenericType(structType));
+ return (JsonConverter?)Activator.CreateInstance(typeof(JsonPipeDelimitedArrayConverter<>).MakeGenericType(structType));
}
}
}
diff --git a/MediaBrowser.Common/Json/Converters/JsonStringConverter.cs b/MediaBrowser.Common/Json/Converters/JsonStringConverter.cs
index 669b3cd07..6cd980e48 100644
--- a/MediaBrowser.Common/Json/Converters/JsonStringConverter.cs
+++ b/MediaBrowser.Common/Json/Converters/JsonStringConverter.cs
@@ -9,10 +9,10 @@ namespace MediaBrowser.Common.Json.Converters
/// <summary>
/// Converter to allow the serializer to read strings.
/// </summary>
- public class JsonStringConverter : JsonConverter<string>
+ public class JsonStringConverter : JsonConverter<string?>
{
/// <inheritdoc />
- public override string Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+ public override string? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return reader.TokenType switch
{
@@ -23,7 +23,7 @@ namespace MediaBrowser.Common.Json.Converters
}
/// <inheritdoc />
- public override void Write(Utf8JsonWriter writer, string value, JsonSerializerOptions options)
+ public override void Write(Utf8JsonWriter writer, string? value, JsonSerializerOptions options)
{
writer.WriteStringValue(value);
}
@@ -36,4 +36,4 @@ namespace MediaBrowser.Common.Json.Converters
return Encoding.UTF8.GetString(utf8Bytes);
}
}
-} \ No newline at end of file
+}
diff --git a/MediaBrowser.Common/Json/Converters/JsonVersionConverter.cs b/MediaBrowser.Common/Json/Converters/JsonVersionConverter.cs
index f69e868cc..81c093c54 100644
--- a/MediaBrowser.Common/Json/Converters/JsonVersionConverter.cs
+++ b/MediaBrowser.Common/Json/Converters/JsonVersionConverter.cs
@@ -14,7 +14,7 @@ namespace MediaBrowser.Common.Json.Converters
{
/// <inheritdoc />
public override Version Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
- => new Version(reader.GetString());
+ => new Version(reader.GetString()!); // Will throw ArgumentNullException on null
/// <inheritdoc />
public override void Write(Utf8JsonWriter writer, Version value, JsonSerializerOptions options)
diff --git a/MediaBrowser.Common/MediaBrowser.Common.csproj b/MediaBrowser.Common/MediaBrowser.Common.csproj
index 0d9f78704..0299a8456 100644
--- a/MediaBrowser.Common/MediaBrowser.Common.csproj
+++ b/MediaBrowser.Common/MediaBrowser.Common.csproj
@@ -33,6 +33,7 @@
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
+ <Nullable>enable</Nullable>
<AnalysisMode>AllEnabledByDefault</AnalysisMode>
<CodeAnalysisRuleSet>../jellyfin.ruleset</CodeAnalysisRuleSet>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
diff --git a/MediaBrowser.Common/Net/INetworkManager.cs b/MediaBrowser.Common/Net/INetworkManager.cs
index 185df5b77..b93939730 100644
--- a/MediaBrowser.Common/Net/INetworkManager.cs
+++ b/MediaBrowser.Common/Net/INetworkManager.cs
@@ -1,4 +1,3 @@
-#nullable enable
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
diff --git a/MediaBrowser.Common/Net/IPHost.cs b/MediaBrowser.Common/Net/IPHost.cs
index fb3ef9b12..5db8817ee 100644
--- a/MediaBrowser.Common/Net/IPHost.cs
+++ b/MediaBrowser.Common/Net/IPHost.cs
@@ -1,4 +1,3 @@
-#nullable enable
using System;
using System.Diagnostics;
using System.Linq;
@@ -400,10 +399,7 @@ namespace MediaBrowser.Common.Net
private bool ResolveHost()
{
// When was the last time we resolved?
- if (_lastResolved == null)
- {
- _lastResolved = DateTime.UtcNow;
- }
+ _lastResolved ??= DateTime.UtcNow;
// If we haven't resolved before, or our timer has run out...
if ((_addresses.Length == 0 && !Resolved) || (DateTime.UtcNow > _lastResolved.Value.AddMinutes(Timeout)))
diff --git a/MediaBrowser.Common/Net/IPNetAddress.cs b/MediaBrowser.Common/Net/IPNetAddress.cs
index 589aad4b0..f6e3971bf 100644
--- a/MediaBrowser.Common/Net/IPNetAddress.cs
+++ b/MediaBrowser.Common/Net/IPNetAddress.cs
@@ -1,4 +1,3 @@
-#nullable enable
using System;
using System.Net;
using System.Net.Sockets;
diff --git a/MediaBrowser.Common/Net/IPObject.cs b/MediaBrowser.Common/Net/IPObject.cs
index 3542dcd75..2612268fd 100644
--- a/MediaBrowser.Common/Net/IPObject.cs
+++ b/MediaBrowser.Common/Net/IPObject.cs
@@ -1,4 +1,3 @@
-#nullable enable
using System;
using System.Net;
using System.Net.Sockets;
diff --git a/MediaBrowser.Common/Plugins/BasePlugin.cs b/MediaBrowser.Common/Plugins/BasePlugin.cs
index ad5a7338d..8972089a8 100644
--- a/MediaBrowser.Common/Plugins/BasePlugin.cs
+++ b/MediaBrowser.Common/Plugins/BasePlugin.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.IO;
using System.Reflection;
diff --git a/MediaBrowser.Common/Plugins/BasePluginOfT.cs b/MediaBrowser.Common/Plugins/BasePluginOfT.cs
index 99c226f50..8a6d28e0f 100644
--- a/MediaBrowser.Common/Plugins/BasePluginOfT.cs
+++ b/MediaBrowser.Common/Plugins/BasePluginOfT.cs
@@ -1,4 +1,6 @@
+#nullable disable
#pragma warning disable SA1649 // File name should match first type name
+
using System;
using System.IO;
using System.Runtime.InteropServices;
@@ -105,10 +107,7 @@ namespace MediaBrowser.Common.Plugins
{
lock (_configurationSyncLock)
{
- if (_configuration == null)
- {
- _configuration = LoadConfiguration();
- }
+ _configuration ??= LoadConfiguration();
}
}
diff --git a/MediaBrowser.Common/Plugins/IPlugin.cs b/MediaBrowser.Common/Plugins/IPlugin.cs
index b2ba1179c..01e0a536d 100644
--- a/MediaBrowser.Common/Plugins/IPlugin.cs
+++ b/MediaBrowser.Common/Plugins/IPlugin.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using MediaBrowser.Model.Plugins;
diff --git a/MediaBrowser.Common/Plugins/IPluginManager.cs b/MediaBrowser.Common/Plugins/IPluginManager.cs
index 0e2e814cb..176bcbbd5 100644
--- a/MediaBrowser.Common/Plugins/IPluginManager.cs
+++ b/MediaBrowser.Common/Plugins/IPluginManager.cs
@@ -1,5 +1,3 @@
-#nullable enable
-
using System;
using System.Collections.Generic;
using System.Reflection;
diff --git a/MediaBrowser.Common/Plugins/LocalPlugin.cs b/MediaBrowser.Common/Plugins/LocalPlugin.cs
index 12a1ad1ec..4c8e2d504 100644
--- a/MediaBrowser.Common/Plugins/LocalPlugin.cs
+++ b/MediaBrowser.Common/Plugins/LocalPlugin.cs
@@ -1,4 +1,3 @@
-#nullable enable
using System;
using System.Collections.Generic;
using MediaBrowser.Model.Plugins;
diff --git a/MediaBrowser.Common/Plugins/PluginManifest.cs b/MediaBrowser.Common/Plugins/PluginManifest.cs
index 4c724f694..2910dbe14 100644
--- a/MediaBrowser.Common/Plugins/PluginManifest.cs
+++ b/MediaBrowser.Common/Plugins/PluginManifest.cs
@@ -1,5 +1,3 @@
-#nullable enable
-
using System;
using System.Text.Json.Serialization;
using MediaBrowser.Model.Plugins;
diff --git a/MediaBrowser.Common/Progress/ActionableProgress.cs b/MediaBrowser.Common/Progress/ActionableProgress.cs
index fe7cb1078..0ba46ea3b 100644
--- a/MediaBrowser.Common/Progress/ActionableProgress.cs
+++ b/MediaBrowser.Common/Progress/ActionableProgress.cs
@@ -14,9 +14,9 @@ namespace MediaBrowser.Common.Progress
/// <summary>
/// The _actions.
/// </summary>
- private Action<T> _action;
+ private Action<T>? _action;
- public event EventHandler<T> ProgressChanged;
+ public event EventHandler<T>? ProgressChanged;
/// <summary>
/// Registers the action.
diff --git a/MediaBrowser.Common/Progress/SimpleProgress.cs b/MediaBrowser.Common/Progress/SimpleProgress.cs
index 988d8ad34..7071f2bc3 100644
--- a/MediaBrowser.Common/Progress/SimpleProgress.cs
+++ b/MediaBrowser.Common/Progress/SimpleProgress.cs
@@ -7,7 +7,7 @@ namespace MediaBrowser.Common.Progress
{
public class SimpleProgress<T> : IProgress<T>
{
- public event EventHandler<T> ProgressChanged;
+ public event EventHandler<T>? ProgressChanged;
public void Report(T value)
{
diff --git a/MediaBrowser.Common/Providers/ProviderIdParsers.cs b/MediaBrowser.Common/Providers/ProviderIdParsers.cs
index 64c2e1976..33d09ed38 100644
--- a/MediaBrowser.Common/Providers/ProviderIdParsers.cs
+++ b/MediaBrowser.Common/Providers/ProviderIdParsers.cs
@@ -1,6 +1,4 @@
-#nullable enable
-
-using System;
+using System;
using System.Diagnostics.CodeAnalysis;
namespace MediaBrowser.Common.Providers
diff --git a/MediaBrowser.Common/Updates/IInstallationManager.cs b/MediaBrowser.Common/Updates/IInstallationManager.cs
index 0844c2d79..c2a28e0a2 100644
--- a/MediaBrowser.Common/Updates/IInstallationManager.cs
+++ b/MediaBrowser.Common/Updates/IInstallationManager.cs
@@ -1,5 +1,3 @@
-#nullable enable
-
using System;
using System.Collections.Generic;
using System.Threading;
diff --git a/MediaBrowser.Common/Updates/InstallationEventArgs.cs b/MediaBrowser.Common/Updates/InstallationEventArgs.cs
index adf336313..f4f759955 100644
--- a/MediaBrowser.Common/Updates/InstallationEventArgs.cs
+++ b/MediaBrowser.Common/Updates/InstallationEventArgs.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using MediaBrowser.Model.Updates;
diff --git a/MediaBrowser.Common/Updates/InstallationFailedEventArgs.cs b/MediaBrowser.Common/Updates/InstallationFailedEventArgs.cs
index 46f10c84f..d37146195 100644
--- a/MediaBrowser.Common/Updates/InstallationFailedEventArgs.cs
+++ b/MediaBrowser.Common/Updates/InstallationFailedEventArgs.cs
@@ -1,3 +1,4 @@
+#nullable disable
#pragma warning disable CS1591
using System;
diff --git a/MediaBrowser.Controller/Authentication/AuthenticationResult.cs b/MediaBrowser.Controller/Authentication/AuthenticationResult.cs
index 4249a9a66..635e4eb3d 100644
--- a/MediaBrowser.Controller/Authentication/AuthenticationResult.cs
+++ b/MediaBrowser.Controller/Authentication/AuthenticationResult.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using MediaBrowser.Controller.Session;
diff --git a/MediaBrowser.Controller/Authentication/IAuthenticationProvider.cs b/MediaBrowser.Controller/Authentication/IAuthenticationProvider.cs
index ecdffa2eb..a56d3c822 100644
--- a/MediaBrowser.Controller/Authentication/IAuthenticationProvider.cs
+++ b/MediaBrowser.Controller/Authentication/IAuthenticationProvider.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System.Threading.Tasks;
diff --git a/MediaBrowser.Controller/Authentication/IPasswordResetProvider.cs b/MediaBrowser.Controller/Authentication/IPasswordResetProvider.cs
index 6729b9115..8c9d1baf8 100644
--- a/MediaBrowser.Controller/Authentication/IPasswordResetProvider.cs
+++ b/MediaBrowser.Controller/Authentication/IPasswordResetProvider.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/MediaBrowser.Controller/BaseItemManager/BaseItemManager.cs b/MediaBrowser.Controller/BaseItemManager/BaseItemManager.cs
index a233c358e..68119cfed 100644
--- a/MediaBrowser.Controller/BaseItemManager/BaseItemManager.cs
+++ b/MediaBrowser.Controller/BaseItemManager/BaseItemManager.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Linq;
using System.Threading;
diff --git a/MediaBrowser.Controller/BaseItemManager/IBaseItemManager.cs b/MediaBrowser.Controller/BaseItemManager/IBaseItemManager.cs
index 8a8736427..b2b36c040 100644
--- a/MediaBrowser.Controller/BaseItemManager/IBaseItemManager.cs
+++ b/MediaBrowser.Controller/BaseItemManager/IBaseItemManager.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System.Threading;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Model.Configuration;
diff --git a/MediaBrowser.Controller/Channels/Channel.cs b/MediaBrowser.Controller/Channels/Channel.cs
index b2315bda4..26c64e0da 100644
--- a/MediaBrowser.Controller/Channels/Channel.cs
+++ b/MediaBrowser.Controller/Channels/Channel.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/MediaBrowser.Controller/Channels/ChannelItemInfo.cs b/MediaBrowser.Controller/Channels/ChannelItemInfo.cs
index 476992cbd..4d1e35f9e 100644
--- a/MediaBrowser.Controller/Channels/ChannelItemInfo.cs
+++ b/MediaBrowser.Controller/Channels/ChannelItemInfo.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
@@ -11,6 +13,19 @@ namespace MediaBrowser.Controller.Channels
{
public class ChannelItemInfo : IHasProviderIds
{
+ public ChannelItemInfo()
+ {
+ MediaSources = new List<MediaSourceInfo>();
+ TrailerTypes = new List<TrailerType>();
+ Genres = new List<string>();
+ Studios = new List<string>();
+ People = new List<PersonInfo>();
+ Tags = new List<string>();
+ ProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
+ Artists = new List<string>();
+ AlbumArtists = new List<string>();
+ }
+
public string Name { get; set; }
public string SeriesName { get; set; }
@@ -78,18 +93,5 @@ namespace MediaBrowser.Controller.Channels
public bool IsLiveStream { get; set; }
public string Etag { get; set; }
-
- public ChannelItemInfo()
- {
- MediaSources = new List<MediaSourceInfo>();
- TrailerTypes = new List<TrailerType>();
- Genres = new List<string>();
- Studios = new List<string>();
- People = new List<PersonInfo>();
- Tags = new List<string>();
- ProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
- Artists = new List<string>();
- AlbumArtists = new List<string>();
- }
}
}
diff --git a/MediaBrowser.Controller/Channels/ChannelItemResult.cs b/MediaBrowser.Controller/Channels/ChannelItemResult.cs
index cee7b2003..6b2077662 100644
--- a/MediaBrowser.Controller/Channels/ChannelItemResult.cs
+++ b/MediaBrowser.Controller/Channels/ChannelItemResult.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System.Collections.Generic;
@@ -6,13 +8,13 @@ namespace MediaBrowser.Controller.Channels
{
public class ChannelItemResult
{
- public List<ChannelItemInfo> Items { get; set; }
-
- public int? TotalRecordCount { get; set; }
-
public ChannelItemResult()
{
Items = new List<ChannelItemInfo>();
}
+
+ public List<ChannelItemInfo> Items { get; set; }
+
+ public int? TotalRecordCount { get; set; }
}
}
diff --git a/MediaBrowser.Controller/Channels/ChannelLatestMediaSearch.cs b/MediaBrowser.Controller/Channels/ChannelLatestMediaSearch.cs
new file mode 100644
index 000000000..6f0761e64
--- /dev/null
+++ b/MediaBrowser.Controller/Channels/ChannelLatestMediaSearch.cs
@@ -0,0 +1,11 @@
+#nullable disable
+
+#pragma warning disable CS1591
+
+namespace MediaBrowser.Controller.Channels
+{
+ public class ChannelLatestMediaSearch
+ {
+ public string UserId { get; set; }
+ }
+} \ No newline at end of file
diff --git a/MediaBrowser.Controller/Channels/ChannelSearchInfo.cs b/MediaBrowser.Controller/Channels/ChannelSearchInfo.cs
index 32469d4d7..990b025bc 100644
--- a/MediaBrowser.Controller/Channels/ChannelSearchInfo.cs
+++ b/MediaBrowser.Controller/Channels/ChannelSearchInfo.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
namespace MediaBrowser.Controller.Channels
@@ -8,9 +10,4 @@ namespace MediaBrowser.Controller.Channels
public string UserId { get; set; }
}
-
- public class ChannelLatestMediaSearch
- {
- public string UserId { get; set; }
- }
}
diff --git a/MediaBrowser.Controller/Channels/IChannel.cs b/MediaBrowser.Controller/Channels/IChannel.cs
index 2c0eadf95..01bf8d5c8 100644
--- a/MediaBrowser.Controller/Channels/IChannel.cs
+++ b/MediaBrowser.Controller/Channels/IChannel.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System.Collections.Generic;
diff --git a/MediaBrowser.Controller/Channels/IChannelManager.cs b/MediaBrowser.Controller/Channels/IChannelManager.cs
index ddae7dbd3..4c5626338 100644
--- a/MediaBrowser.Controller/Channels/IChannelManager.cs
+++ b/MediaBrowser.Controller/Channels/IChannelManager.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/MediaBrowser.Controller/Channels/IHasCacheKey.cs b/MediaBrowser.Controller/Channels/IHasCacheKey.cs
index bf895a0ec..9fae43033 100644
--- a/MediaBrowser.Controller/Channels/IHasCacheKey.cs
+++ b/MediaBrowser.Controller/Channels/IHasCacheKey.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
namespace MediaBrowser.Controller.Channels
diff --git a/MediaBrowser.Controller/Channels/ISearchableChannel.cs b/MediaBrowser.Controller/Channels/ISearchableChannel.cs
index b627ca1c2..b58446fc4 100644
--- a/MediaBrowser.Controller/Channels/ISearchableChannel.cs
+++ b/MediaBrowser.Controller/Channels/ISearchableChannel.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System.Collections.Generic;
diff --git a/MediaBrowser.Controller/Channels/InternalChannelFeatures.cs b/MediaBrowser.Controller/Channels/InternalChannelFeatures.cs
index 137f5d095..152c653dc 100644
--- a/MediaBrowser.Controller/Channels/InternalChannelFeatures.cs
+++ b/MediaBrowser.Controller/Channels/InternalChannelFeatures.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System.Collections.Generic;
diff --git a/MediaBrowser.Controller/Channels/InternalChannelItemQuery.cs b/MediaBrowser.Controller/Channels/InternalChannelItemQuery.cs
index 7e9bb28ed..0d837faca 100644
--- a/MediaBrowser.Controller/Channels/InternalChannelItemQuery.cs
+++ b/MediaBrowser.Controller/Channels/InternalChannelItemQuery.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/MediaBrowser.Controller/Collections/CollectionCreatedEventArgs.cs b/MediaBrowser.Controller/Collections/CollectionCreatedEventArgs.cs
new file mode 100644
index 000000000..82b3a4977
--- /dev/null
+++ b/MediaBrowser.Controller/Collections/CollectionCreatedEventArgs.cs
@@ -0,0 +1,24 @@
+#nullable disable
+
+#pragma warning disable CS1591
+
+using System;
+using MediaBrowser.Controller.Entities.Movies;
+
+namespace MediaBrowser.Controller.Collections
+{
+ public class CollectionCreatedEventArgs : EventArgs
+ {
+ /// <summary>
+ /// Gets or sets the collection.
+ /// </summary>
+ /// <value>The collection.</value>
+ public BoxSet Collection { get; set; }
+
+ /// <summary>
+ /// Gets or sets the options.
+ /// </summary>
+ /// <value>The options.</value>
+ public CollectionCreationOptions Options { get; set; }
+ }
+} \ No newline at end of file
diff --git a/MediaBrowser.Controller/Collections/CollectionCreationOptions.cs b/MediaBrowser.Controller/Collections/CollectionCreationOptions.cs
index f6037d05e..30f5f4efa 100644
--- a/MediaBrowser.Controller/Collections/CollectionCreationOptions.cs
+++ b/MediaBrowser.Controller/Collections/CollectionCreationOptions.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
@@ -23,8 +25,8 @@ namespace MediaBrowser.Controller.Collections
public Dictionary<string, string> ProviderIds { get; set; }
- public string[] ItemIdList { get; set; }
+ public IReadOnlyList<string> ItemIdList { get; set; }
- public Guid[] UserIds { get; set; }
+ public IReadOnlyList<Guid> UserIds { get; set; }
}
}
diff --git a/MediaBrowser.Controller/Collections/CollectionEvents.cs b/MediaBrowser.Controller/Collections/CollectionModifiedEventArgs.cs
index ce59b4ada..8155cf3db 100644
--- a/MediaBrowser.Controller/Collections/CollectionEvents.cs
+++ b/MediaBrowser.Controller/Collections/CollectionModifiedEventArgs.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
@@ -7,23 +9,14 @@ using MediaBrowser.Controller.Entities.Movies;
namespace MediaBrowser.Controller.Collections
{
- public class CollectionCreatedEventArgs : EventArgs
- {
- /// <summary>
- /// Gets or sets the collection.
- /// </summary>
- /// <value>The collection.</value>
- public BoxSet Collection { get; set; }
-
- /// <summary>
- /// Gets or sets the options.
- /// </summary>
- /// <value>The options.</value>
- public CollectionCreationOptions Options { get; set; }
- }
-
public class CollectionModifiedEventArgs : EventArgs
{
+ public CollectionModifiedEventArgs(BoxSet collection, IReadOnlyCollection<BaseItem> itemsChanged)
+ {
+ Collection = collection;
+ ItemsChanged = itemsChanged;
+ }
+
/// <summary>
/// Gets or sets the collection.
/// </summary>
@@ -34,6 +27,6 @@ namespace MediaBrowser.Controller.Collections
/// Gets or sets the items changed.
/// </summary>
/// <value>The items changed.</value>
- public List<BaseItem> ItemsChanged { get; set; }
+ public IReadOnlyCollection<BaseItem> ItemsChanged { get; set; }
}
}
diff --git a/MediaBrowser.Controller/Collections/ICollectionManager.cs b/MediaBrowser.Controller/Collections/ICollectionManager.cs
index a6991e2ea..46bc37e7f 100644
--- a/MediaBrowser.Controller/Collections/ICollectionManager.cs
+++ b/MediaBrowser.Controller/Collections/ICollectionManager.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/MediaBrowser.Controller/Configuration/IServerConfigurationManager.cs b/MediaBrowser.Controller/Configuration/IServerConfigurationManager.cs
index 43ad04dba..44e2c45dd 100644
--- a/MediaBrowser.Controller/Configuration/IServerConfigurationManager.cs
+++ b/MediaBrowser.Controller/Configuration/IServerConfigurationManager.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using MediaBrowser.Common.Configuration;
using MediaBrowser.Model.Configuration;
diff --git a/MediaBrowser.Controller/Devices/IDeviceManager.cs b/MediaBrowser.Controller/Devices/IDeviceManager.cs
index 8f0872dba..ef17c8fb3 100644
--- a/MediaBrowser.Controller/Devices/IDeviceManager.cs
+++ b/MediaBrowser.Controller/Devices/IDeviceManager.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/MediaBrowser.Controller/Dlna/IDlnaManager.cs b/MediaBrowser.Controller/Dlna/IDlnaManager.cs
index dc2d5a356..b51dc255c 100644
--- a/MediaBrowser.Controller/Dlna/IDlnaManager.cs
+++ b/MediaBrowser.Controller/Dlna/IDlnaManager.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System.Collections.Generic;
diff --git a/MediaBrowser.Controller/Drawing/IImageEncoder.cs b/MediaBrowser.Controller/Drawing/IImageEncoder.cs
index 770c6dc2d..800f7a8bb 100644
--- a/MediaBrowser.Controller/Drawing/IImageEncoder.cs
+++ b/MediaBrowser.Controller/Drawing/IImageEncoder.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
#nullable enable
diff --git a/MediaBrowser.Controller/Drawing/IImageProcessor.cs b/MediaBrowser.Controller/Drawing/IImageProcessor.cs
index 142cebd0c..9bfead8b3 100644
--- a/MediaBrowser.Controller/Drawing/IImageProcessor.cs
+++ b/MediaBrowser.Controller/Drawing/IImageProcessor.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
#nullable enable
diff --git a/MediaBrowser.Controller/Drawing/ImageCollageOptions.cs b/MediaBrowser.Controller/Drawing/ImageCollageOptions.cs
index fe0465d0d..e9c88ffb5 100644
--- a/MediaBrowser.Controller/Drawing/ImageCollageOptions.cs
+++ b/MediaBrowser.Controller/Drawing/ImageCollageOptions.cs
@@ -1,3 +1,7 @@
+#nullable disable
+
+using System.Collections.Generic;
+
#pragma warning disable CS1591
namespace MediaBrowser.Controller.Drawing
@@ -8,7 +12,7 @@ namespace MediaBrowser.Controller.Drawing
/// Gets or sets the input paths.
/// </summary>
/// <value>The input paths.</value>
- public string[] InputPaths { get; set; }
+ public IReadOnlyList<string> InputPaths { get; set; }
/// <summary>
/// Gets or sets the output path.
diff --git a/MediaBrowser.Controller/Drawing/ImageHelper.cs b/MediaBrowser.Controller/Drawing/ImageHelper.cs
index 596fcbc8c..204175ed5 100644
--- a/MediaBrowser.Controller/Drawing/ImageHelper.cs
+++ b/MediaBrowser.Controller/Drawing/ImageHelper.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
#nullable enable
diff --git a/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs b/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs
index 230a0af60..11e663301 100644
--- a/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs
+++ b/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/MediaBrowser.Controller/Drawing/ImageProcessorExtensions.cs b/MediaBrowser.Controller/Drawing/ImageProcessorExtensions.cs
index d3a2b4dbf..b036425ab 100644
--- a/MediaBrowser.Controller/Drawing/ImageProcessorExtensions.cs
+++ b/MediaBrowser.Controller/Drawing/ImageProcessorExtensions.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using MediaBrowser.Controller.Entities;
diff --git a/MediaBrowser.Controller/Drawing/ImageStream.cs b/MediaBrowser.Controller/Drawing/ImageStream.cs
index 46f58ec15..5ee781ffa 100644
--- a/MediaBrowser.Controller/Drawing/ImageStream.cs
+++ b/MediaBrowser.Controller/Drawing/ImageStream.cs
@@ -12,7 +12,7 @@ namespace MediaBrowser.Controller.Drawing
/// Gets or sets the stream.
/// </summary>
/// <value>The stream.</value>
- public Stream Stream { get; set; }
+ public Stream? Stream { get; set; }
/// <summary>
/// Gets or sets the format.
@@ -22,9 +22,15 @@ namespace MediaBrowser.Controller.Drawing
public void Dispose()
{
- if (Stream != null)
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ protected virtual void Dispose(bool disposing)
+ {
+ if (disposing)
{
- Stream.Dispose();
+ Stream?.Dispose();
}
}
}
diff --git a/MediaBrowser.Controller/Dto/DtoOptions.cs b/MediaBrowser.Controller/Dto/DtoOptions.cs
index 356783750..ecc833154 100644
--- a/MediaBrowser.Controller/Dto/DtoOptions.cs
+++ b/MediaBrowser.Controller/Dto/DtoOptions.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
@@ -16,37 +18,17 @@ namespace MediaBrowser.Controller.Dto
ItemFields.RefreshState
};
- public IReadOnlyList<ItemFields> Fields { get; set; }
-
- public IReadOnlyList<ImageType> ImageTypes { get; set; }
-
- public int ImageTypeLimit { get; set; }
-
- public bool EnableImages { get; set; }
-
- public bool AddProgramRecordingInfo { get; set; }
-
- public bool EnableUserData { get; set; }
+ private static readonly ImageType[] AllImageTypes = Enum.GetValues<ImageType>();
- public bool AddCurrentProgram { get; set; }
+ private static readonly ItemFields[] AllItemFields = Enum.GetValues<ItemFields>()
+ .Except(DefaultExcludedFields)
+ .ToArray();
public DtoOptions()
: this(true)
{
}
- private static readonly ImageType[] AllImageTypes = Enum.GetNames(typeof(ImageType))
- .Select(i => (ImageType)Enum.Parse(typeof(ImageType), i, true))
- .ToArray();
-
- private static readonly ItemFields[] AllItemFields = Enum.GetNames(typeof(ItemFields))
- .Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true))
- .Except(DefaultExcludedFields)
- .ToArray();
-
- public bool ContainsField(ItemFields field)
- => Fields.Contains(field);
-
public DtoOptions(bool allFields)
{
ImageTypeLimit = int.MaxValue;
@@ -58,6 +40,23 @@ namespace MediaBrowser.Controller.Dto
ImageTypes = AllImageTypes;
}
+ public IReadOnlyList<ItemFields> Fields { get; set; }
+
+ public IReadOnlyList<ImageType> ImageTypes { get; set; }
+
+ public int ImageTypeLimit { get; set; }
+
+ public bool EnableImages { get; set; }
+
+ public bool AddProgramRecordingInfo { get; set; }
+
+ public bool EnableUserData { get; set; }
+
+ public bool AddCurrentProgram { get; set; }
+
+ public bool ContainsField(ItemFields field)
+ => Fields.Contains(field);
+
public int GetImageLimit(ImageType type)
{
if (EnableImages && ImageTypes.Contains(type))
diff --git a/MediaBrowser.Controller/Dto/IDtoService.cs b/MediaBrowser.Controller/Dto/IDtoService.cs
index 988557f42..7f4bbead0 100644
--- a/MediaBrowser.Controller/Dto/IDtoService.cs
+++ b/MediaBrowser.Controller/Dto/IDtoService.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System.Collections.Generic;
using Jellyfin.Data.Entities;
using MediaBrowser.Controller.Entities;
diff --git a/MediaBrowser.Controller/Entities/AggregateFolder.cs b/MediaBrowser.Controller/Entities/AggregateFolder.cs
index 6ebea5f44..e365bfda1 100644
--- a/MediaBrowser.Controller/Entities/AggregateFolder.cs
+++ b/MediaBrowser.Controller/Entities/AggregateFolder.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
@@ -84,6 +86,7 @@ namespace MediaBrowser.Controller.Entities
}
private bool _requiresRefresh;
+
public override bool RequiresRefresh()
{
var changed = base.RequiresRefresh() || _requiresRefresh;
@@ -120,8 +123,7 @@ namespace MediaBrowser.Controller.Entities
var args = new ItemResolveArgs(ConfigurationManager.ApplicationPaths, directoryService)
{
- FileInfo = FileSystem.GetDirectoryInfo(path),
- Path = path
+ FileInfo = FileSystem.GetDirectoryInfo(path)
};
// Gather child folder and files
diff --git a/MediaBrowser.Controller/Entities/Audio/Audio.cs b/MediaBrowser.Controller/Entities/Audio/Audio.cs
index 8220464b3..4c2b7cb7c 100644
--- a/MediaBrowser.Controller/Entities/Audio/Audio.cs
+++ b/MediaBrowser.Controller/Entities/Audio/Audio.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/MediaBrowser.Controller/Entities/Audio/IHasAlbumArtist.cs b/MediaBrowser.Controller/Entities/Audio/IHasAlbumArtist.cs
index 20fad4cb0..1625c748a 100644
--- a/MediaBrowser.Controller/Entities/Audio/IHasAlbumArtist.cs
+++ b/MediaBrowser.Controller/Entities/Audio/IHasAlbumArtist.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System.Collections.Generic;
diff --git a/MediaBrowser.Controller/Entities/Audio/IHasMusicGenres.cs b/MediaBrowser.Controller/Entities/Audio/IHasMusicGenres.cs
index ac4dd1688..db60c3071 100644
--- a/MediaBrowser.Controller/Entities/Audio/IHasMusicGenres.cs
+++ b/MediaBrowser.Controller/Entities/Audio/IHasMusicGenres.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
namespace MediaBrowser.Controller.Entities.Audio
diff --git a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs
index 9a33ad9d7..610bce4f5 100644
--- a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs
+++ b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs
index 8a9bb12c7..b07c3eed1 100644
--- a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs
+++ b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
@@ -112,7 +114,7 @@ namespace MediaBrowser.Controller.Entities.Audio
}
/// <summary>
- /// Returns the folder containing the item.
+ /// Gets the folder containing the item.
/// If the item is a folder, it returns the folder itself.
/// </summary>
/// <value>The containing folder path.</value>
diff --git a/MediaBrowser.Controller/Entities/Audio/MusicGenre.cs b/MediaBrowser.Controller/Entities/Audio/MusicGenre.cs
index f0c076108..b07d47ffd 100644
--- a/MediaBrowser.Controller/Entities/Audio/MusicGenre.cs
+++ b/MediaBrowser.Controller/Entities/Audio/MusicGenre.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/MediaBrowser.Controller/Entities/AudioBook.cs b/MediaBrowser.Controller/Entities/AudioBook.cs
index f4bd851e1..405284622 100644
--- a/MediaBrowser.Controller/Entities/AudioBook.cs
+++ b/MediaBrowser.Controller/Entities/AudioBook.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs
index 53d45261e..238c98982 100644
--- a/MediaBrowser.Controller/Entities/BaseItem.cs
+++ b/MediaBrowser.Controller/Entities/BaseItem.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
@@ -106,15 +108,10 @@ namespace MediaBrowser.Controller.Entities
{
get
{
- if (_themeSongIds == null)
- {
- _themeSongIds = GetExtras()
- .Where(extra => extra.ExtraType == Model.Entities.ExtraType.ThemeSong)
- .Select(song => song.Id)
- .ToArray();
- }
-
- return _themeSongIds;
+ return _themeSongIds ??= GetExtras()
+ .Where(extra => extra.ExtraType == Model.Entities.ExtraType.ThemeSong)
+ .Select(song => song.Id)
+ .ToArray();
}
private set
@@ -128,15 +125,10 @@ namespace MediaBrowser.Controller.Entities
{
get
{
- if (_themeVideoIds == null)
- {
- _themeVideoIds = GetExtras()
- .Where(extra => extra.ExtraType == Model.Entities.ExtraType.ThemeVideo)
- .Select(song => song.Id)
- .ToArray();
- }
-
- return _themeVideoIds;
+ return _themeVideoIds ??= GetExtras()
+ .Where(extra => extra.ExtraType == Model.Entities.ExtraType.ThemeVideo)
+ .Select(song => song.Id)
+ .ToArray();
}
private set
@@ -347,9 +339,9 @@ namespace MediaBrowser.Controller.Entities
get
{
// if (IsOffline)
- //{
+ // {
// return LocationType.Offline;
- //}
+ // }
var path = Path;
if (string.IsNullOrEmpty(path))
@@ -2324,7 +2316,7 @@ namespace MediaBrowser.Controller.Entities
.Where(i => i.IsLocalFile)
.Select(i => System.IO.Path.GetDirectoryName(i.Path))
.Distinct(StringComparer.OrdinalIgnoreCase)
- .SelectMany(i => directoryService.GetFilePaths(i))
+ .SelectMany(directoryService.GetFilePaths)
.ToList();
var deletedImages = ImageInfos
@@ -2777,11 +2769,11 @@ namespace MediaBrowser.Controller.Entities
// var parentId = Id;
// if (!video.IsOwnedItem || video.ParentId != parentId)
- //{
+ // {
// video.IsOwnedItem = true;
// video.ParentId = parentId;
// newOptions.ForceSave = true;
- //}
+ // }
if (video == null)
{
diff --git a/MediaBrowser.Controller/Entities/BaseItemExtensions.cs b/MediaBrowser.Controller/Entities/BaseItemExtensions.cs
index 157ed8332..c39b18891 100644
--- a/MediaBrowser.Controller/Entities/BaseItemExtensions.cs
+++ b/MediaBrowser.Controller/Entities/BaseItemExtensions.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#nullable enable
#pragma warning disable CS1591
diff --git a/MediaBrowser.Controller/Entities/BasePluginFolder.cs b/MediaBrowser.Controller/Entities/BasePluginFolder.cs
index ef5a5a734..1bd25042f 100644
--- a/MediaBrowser.Controller/Entities/BasePluginFolder.cs
+++ b/MediaBrowser.Controller/Entities/BasePluginFolder.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System.Text.Json.Serialization;
diff --git a/MediaBrowser.Controller/Entities/Book.cs b/MediaBrowser.Controller/Entities/Book.cs
index 55945283c..d75beb06d 100644
--- a/MediaBrowser.Controller/Entities/Book.cs
+++ b/MediaBrowser.Controller/Entities/Book.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
@@ -10,6 +12,11 @@ namespace MediaBrowser.Controller.Entities
{
public class Book : BaseItem, IHasLookupInfo<BookInfo>, IHasSeries
{
+ public Book()
+ {
+ this.RunTimeTicks = TimeSpan.TicksPerSecond;
+ }
+
[JsonIgnore]
public override string MediaType => Model.Entities.MediaType.Book;
@@ -26,11 +33,6 @@ namespace MediaBrowser.Controller.Entities
[JsonIgnore]
public Guid SeriesId { get; set; }
- public Book()
- {
- this.RunTimeTicks = TimeSpan.TicksPerSecond;
- }
-
public string FindSeriesSortName()
{
return SeriesName;
diff --git a/MediaBrowser.Controller/Entities/CollectionFolder.cs b/MediaBrowser.Controller/Entities/CollectionFolder.cs
index 76b6d39a9..a86da29ce 100644
--- a/MediaBrowser.Controller/Entities/CollectionFolder.cs
+++ b/MediaBrowser.Controller/Entities/CollectionFolder.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
@@ -61,7 +63,6 @@ namespace MediaBrowser.Controller.Entities
try
{
var result = XmlSerializer.DeserializeFromFile(typeof(LibraryOptions), GetLibraryOptionsPath(path)) as LibraryOptions;
-
if (result == null)
{
return new LibraryOptions();
@@ -271,7 +272,6 @@ namespace MediaBrowser.Controller.Entities
var args = new ItemResolveArgs(ConfigurationManager.ApplicationPaths, directoryService)
{
FileInfo = FileSystem.GetDirectoryInfo(path),
- Path = path,
Parent = GetParent() as Folder,
CollectionType = CollectionType
};
@@ -355,9 +355,7 @@ namespace MediaBrowser.Controller.Entities
if (result.Count == 0)
{
- var folder = LibraryManager.FindByPath(path, true) as Folder;
-
- if (folder != null)
+ if (LibraryManager.FindByPath(path, true) is Folder folder)
{
result.Add(folder);
}
diff --git a/MediaBrowser.Controller/Entities/Extensions.cs b/MediaBrowser.Controller/Entities/Extensions.cs
index 3a34c668c..244cc00be 100644
--- a/MediaBrowser.Controller/Entities/Extensions.cs
+++ b/MediaBrowser.Controller/Entities/Extensions.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Linq;
using MediaBrowser.Common.Extensions;
diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs
index d45f8758c..a59f5c6e4 100644
--- a/MediaBrowser.Controller/Entities/Folder.cs
+++ b/MediaBrowser.Controller/Entities/Folder.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
@@ -1768,20 +1770,15 @@ namespace MediaBrowser.Controller.Entities
{
EnableImages = false
}
- });
-
- double unplayedCount = unplayedQueryResult.TotalRecordCount;
+ }).TotalRecordCount;
- dto.UnplayedItemCount = unplayedQueryResult.TotalRecordCount;
+ dto.UnplayedItemCount = unplayedQueryResult;
- if (itemDto != null && itemDto.RecursiveItemCount.HasValue)
+ if (itemDto?.RecursiveItemCount > 0)
{
- if (itemDto.RecursiveItemCount.Value > 0)
- {
- var unplayedPercentage = (unplayedCount / itemDto.RecursiveItemCount.Value) * 100;
- dto.PlayedPercentage = 100 - unplayedPercentage;
- dto.Played = dto.PlayedPercentage.Value >= 100;
- }
+ var unplayedPercentage = ((double)unplayedQueryResult / itemDto.RecursiveItemCount.Value) * 100;
+ dto.PlayedPercentage = 100 - unplayedPercentage;
+ dto.Played = dto.PlayedPercentage.Value >= 100;
}
else
{
diff --git a/MediaBrowser.Controller/Entities/Genre.cs b/MediaBrowser.Controller/Entities/Genre.cs
index 74a170204..310c0c9ec 100644
--- a/MediaBrowser.Controller/Entities/Genre.cs
+++ b/MediaBrowser.Controller/Entities/Genre.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
@@ -33,7 +35,7 @@ namespace MediaBrowser.Controller.Entities
}
/// <summary>
- /// Returns the folder containing the item.
+ /// Gets the folder containing the item.
/// If the item is a folder, it returns the folder itself.
/// </summary>
/// <value>The containing folder path.</value>
diff --git a/MediaBrowser.Controller/Entities/ICollectionFolder.cs b/MediaBrowser.Controller/Entities/ICollectionFolder.cs
index b84a9fa6f..2304570fd 100644
--- a/MediaBrowser.Controller/Entities/ICollectionFolder.cs
+++ b/MediaBrowser.Controller/Entities/ICollectionFolder.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/MediaBrowser.Controller/Entities/IHasAspectRatio.cs b/MediaBrowser.Controller/Entities/IHasAspectRatio.cs
index d7d007668..3aeb7468f 100644
--- a/MediaBrowser.Controller/Entities/IHasAspectRatio.cs
+++ b/MediaBrowser.Controller/Entities/IHasAspectRatio.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
namespace MediaBrowser.Controller.Entities
{
/// <summary>
diff --git a/MediaBrowser.Controller/Entities/IHasDisplayOrder.cs b/MediaBrowser.Controller/Entities/IHasDisplayOrder.cs
index 13226b234..14459624e 100644
--- a/MediaBrowser.Controller/Entities/IHasDisplayOrder.cs
+++ b/MediaBrowser.Controller/Entities/IHasDisplayOrder.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
namespace MediaBrowser.Controller.Entities
{
/// <summary>
diff --git a/MediaBrowser.Controller/Entities/IHasMediaSources.cs b/MediaBrowser.Controller/Entities/IHasMediaSources.cs
index 0f612262a..98c3b3edf 100644
--- a/MediaBrowser.Controller/Entities/IHasMediaSources.cs
+++ b/MediaBrowser.Controller/Entities/IHasMediaSources.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/MediaBrowser.Controller/Entities/IHasProgramAttributes.cs b/MediaBrowser.Controller/Entities/IHasProgramAttributes.cs
index f747b5149..f80f7c304 100644
--- a/MediaBrowser.Controller/Entities/IHasProgramAttributes.cs
+++ b/MediaBrowser.Controller/Entities/IHasProgramAttributes.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using MediaBrowser.Model.LiveTv;
diff --git a/MediaBrowser.Controller/Entities/IHasSeries.cs b/MediaBrowser.Controller/Entities/IHasSeries.cs
index 5444f1f52..64d769d5b 100644
--- a/MediaBrowser.Controller/Entities/IHasSeries.cs
+++ b/MediaBrowser.Controller/Entities/IHasSeries.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/MediaBrowser.Controller/Entities/IHasSpecialFeatures.cs b/MediaBrowser.Controller/Entities/IHasSpecialFeatures.cs
index 6a350212b..f317a02ff 100644
--- a/MediaBrowser.Controller/Entities/IHasSpecialFeatures.cs
+++ b/MediaBrowser.Controller/Entities/IHasSpecialFeatures.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/MediaBrowser.Controller/Entities/IHasTrailers.cs b/MediaBrowser.Controller/Entities/IHasTrailers.cs
index d1f6f2b7e..2bd9ded33 100644
--- a/MediaBrowser.Controller/Entities/IHasTrailers.cs
+++ b/MediaBrowser.Controller/Entities/IHasTrailers.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs
index 270217356..c06021029 100644
--- a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs
+++ b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/MediaBrowser.Controller/Entities/InternalPeopleQuery.cs b/MediaBrowser.Controller/Entities/InternalPeopleQuery.cs
index 5b96a5af6..3e1d89274 100644
--- a/MediaBrowser.Controller/Entities/InternalPeopleQuery.cs
+++ b/MediaBrowser.Controller/Entities/InternalPeopleQuery.cs
@@ -1,12 +1,26 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
+using System.Collections.Generic;
using Jellyfin.Data.Entities;
namespace MediaBrowser.Controller.Entities
{
public class InternalPeopleQuery
{
+ public InternalPeopleQuery()
+ : this(Array.Empty<string>(), Array.Empty<string>())
+ {
+ }
+
+ public InternalPeopleQuery(IReadOnlyList<string> personTypes, IReadOnlyList<string> excludePersonTypes)
+ {
+ PersonTypes = personTypes;
+ ExcludePersonTypes = excludePersonTypes;
+ }
+
/// <summary>
/// Gets or sets the maximum number of items the query should return.
/// </summary>
@@ -14,9 +28,9 @@ namespace MediaBrowser.Controller.Entities
public Guid ItemId { get; set; }
- public string[] PersonTypes { get; set; }
+ public IReadOnlyList<string> PersonTypes { get; }
- public string[] ExcludePersonTypes { get; set; }
+ public IReadOnlyList<string> ExcludePersonTypes { get; }
public int? MaxListOrder { get; set; }
@@ -27,11 +41,5 @@ namespace MediaBrowser.Controller.Entities
public User User { get; set; }
public bool? IsFavorite { get; set; }
-
- public InternalPeopleQuery()
- {
- PersonTypes = Array.Empty<string>();
- ExcludePersonTypes = Array.Empty<string>();
- }
}
}
diff --git a/MediaBrowser.Controller/Entities/ItemImageInfo.cs b/MediaBrowser.Controller/Entities/ItemImageInfo.cs
index 570d8eec0..ea8555dbf 100644
--- a/MediaBrowser.Controller/Entities/ItemImageInfo.cs
+++ b/MediaBrowser.Controller/Entities/ItemImageInfo.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/MediaBrowser.Controller/Entities/LinkedChild.cs b/MediaBrowser.Controller/Entities/LinkedChild.cs
index 8e0f721e7..fd5fef3dc 100644
--- a/MediaBrowser.Controller/Entities/LinkedChild.cs
+++ b/MediaBrowser.Controller/Entities/LinkedChild.cs
@@ -1,15 +1,20 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
-using System.Collections.Generic;
using System.Globalization;
using System.Text.Json.Serialization;
-using MediaBrowser.Model.IO;
namespace MediaBrowser.Controller.Entities
{
public class LinkedChild
{
+ public LinkedChild()
+ {
+ Id = Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture);
+ }
+
public string Path { get; set; }
public LinkedChildType Type { get; set; }
@@ -20,7 +25,7 @@ namespace MediaBrowser.Controller.Entities
public string Id { get; set; }
/// <summary>
- /// Serves as a cache.
+ /// Gets or sets the linked item id.
/// </summary>
public Guid? ItemId { get; set; }
@@ -39,41 +44,5 @@ namespace MediaBrowser.Controller.Entities
return child;
}
-
- public LinkedChild()
- {
- Id = Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture);
- }
- }
-
- public enum LinkedChildType
- {
- Manual = 0,
- Shortcut = 1
- }
-
- public class LinkedChildComparer : IEqualityComparer<LinkedChild>
- {
- private readonly IFileSystem _fileSystem;
-
- public LinkedChildComparer(IFileSystem fileSystem)
- {
- _fileSystem = fileSystem;
- }
-
- public bool Equals(LinkedChild x, LinkedChild y)
- {
- if (x.Type == y.Type)
- {
- return _fileSystem.AreEqual(x.Path, y.Path);
- }
-
- return false;
- }
-
- public int GetHashCode(LinkedChild obj)
- {
- return ((obj.Path ?? string.Empty) + (obj.LibraryItemId ?? string.Empty) + obj.Type).GetHashCode();
- }
}
}
diff --git a/MediaBrowser.Controller/Entities/LinkedChildComparer.cs b/MediaBrowser.Controller/Entities/LinkedChildComparer.cs
new file mode 100644
index 000000000..66fc44b8a
--- /dev/null
+++ b/MediaBrowser.Controller/Entities/LinkedChildComparer.cs
@@ -0,0 +1,34 @@
+#nullable disable
+
+#pragma warning disable CS1591
+
+using System.Collections.Generic;
+using MediaBrowser.Model.IO;
+
+namespace MediaBrowser.Controller.Entities
+{
+ public class LinkedChildComparer : IEqualityComparer<LinkedChild>
+ {
+ private readonly IFileSystem _fileSystem;
+
+ public LinkedChildComparer(IFileSystem fileSystem)
+ {
+ _fileSystem = fileSystem;
+ }
+
+ public bool Equals(LinkedChild x, LinkedChild y)
+ {
+ if (x.Type == y.Type)
+ {
+ return _fileSystem.AreEqual(x.Path, y.Path);
+ }
+
+ return false;
+ }
+
+ public int GetHashCode(LinkedChild obj)
+ {
+ return ((obj.Path ?? string.Empty) + (obj.LibraryItemId ?? string.Empty) + obj.Type).GetHashCode();
+ }
+ }
+} \ No newline at end of file
diff --git a/MediaBrowser.Controller/Entities/LinkedChildType.cs b/MediaBrowser.Controller/Entities/LinkedChildType.cs
new file mode 100644
index 000000000..9ddb7b620
--- /dev/null
+++ b/MediaBrowser.Controller/Entities/LinkedChildType.cs
@@ -0,0 +1,18 @@
+namespace MediaBrowser.Controller.Entities
+{
+ /// <summary>
+ /// The linked child type.
+ /// </summary>
+ public enum LinkedChildType
+ {
+ /// <summary>
+ /// Manually linked child.
+ /// </summary>
+ Manual = 0,
+
+ /// <summary>
+ /// Shortcut linked child.
+ /// </summary>
+ Shortcut = 1
+ }
+} \ No newline at end of file
diff --git a/MediaBrowser.Controller/Entities/Movies/BoxSet.cs b/MediaBrowser.Controller/Entities/Movies/BoxSet.cs
index 05e4229ca..74e84288d 100644
--- a/MediaBrowser.Controller/Entities/Movies/BoxSet.cs
+++ b/MediaBrowser.Controller/Entities/Movies/BoxSet.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
@@ -217,8 +219,7 @@ namespace MediaBrowser.Controller.Entities.Movies
private IEnumerable<BaseItem> FlattenItems(BaseItem item, List<Guid> expandedFolders)
{
- var boxset = item as BoxSet;
- if (boxset != null)
+ if (item is BoxSet boxset)
{
if (!expandedFolders.Contains(item.Id))
{
diff --git a/MediaBrowser.Controller/Entities/Movies/Movie.cs b/MediaBrowser.Controller/Entities/Movies/Movie.cs
index 8b67aaccc..64d60c2e9 100644
--- a/MediaBrowser.Controller/Entities/Movies/Movie.cs
+++ b/MediaBrowser.Controller/Entities/Movies/Movie.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/MediaBrowser.Controller/Entities/MusicVideo.cs b/MediaBrowser.Controller/Entities/MusicVideo.cs
index b278a0142..4e622ba01 100644
--- a/MediaBrowser.Controller/Entities/MusicVideo.cs
+++ b/MediaBrowser.Controller/Entities/MusicVideo.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
@@ -11,15 +13,15 @@ namespace MediaBrowser.Controller.Entities
{
public class MusicVideo : Video, IHasArtist, IHasMusicGenres, IHasLookupInfo<MusicVideoInfo>
{
- /// <inheritdoc />
- [JsonIgnore]
- public IReadOnlyList<string> Artists { get; set; }
-
public MusicVideo()
{
Artists = Array.Empty<string>();
}
+ /// <inheritdoc />
+ [JsonIgnore]
+ public IReadOnlyList<string> Artists { get; set; }
+
public override UnratedItem GetBlockUnratedType()
{
return UnratedItem.Music;
diff --git a/MediaBrowser.Controller/Entities/PeopleHelper.cs b/MediaBrowser.Controller/Entities/PeopleHelper.cs
index 1f3758a73..687ce1ec8 100644
--- a/MediaBrowser.Controller/Entities/PeopleHelper.cs
+++ b/MediaBrowser.Controller/Entities/PeopleHelper.cs
@@ -100,23 +100,5 @@ namespace MediaBrowser.Controller.Entities
existing.SetProviderId(id.Key, id.Value);
}
}
-
- public static bool ContainsPerson(List<PersonInfo> people, string name)
- {
- if (string.IsNullOrEmpty(name))
- {
- throw new ArgumentNullException(nameof(name));
- }
-
- foreach (var i in people)
- {
- if (string.Equals(i.Name, name, StringComparison.OrdinalIgnoreCase))
- {
- return true;
- }
- }
-
- return false;
- }
}
}
diff --git a/MediaBrowser.Controller/Entities/Person.cs b/MediaBrowser.Controller/Entities/Person.cs
index c4fcb0267..d9ff55362 100644
--- a/MediaBrowser.Controller/Entities/Person.cs
+++ b/MediaBrowser.Controller/Entities/Person.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/MediaBrowser.Controller/Entities/PersonInfo.cs b/MediaBrowser.Controller/Entities/PersonInfo.cs
index 4ff9b0955..fb79323f8 100644
--- a/MediaBrowser.Controller/Entities/PersonInfo.cs
+++ b/MediaBrowser.Controller/Entities/PersonInfo.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/MediaBrowser.Controller/Entities/Photo.cs b/MediaBrowser.Controller/Entities/Photo.cs
index 2fc66176f..3312a0e3e 100644
--- a/MediaBrowser.Controller/Entities/Photo.cs
+++ b/MediaBrowser.Controller/Entities/Photo.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System.Text.Json.Serialization;
@@ -24,8 +26,7 @@ namespace MediaBrowser.Controller.Entities
var parents = GetParents();
foreach (var parent in parents)
{
- var photoAlbum = parent as PhotoAlbum;
- if (photoAlbum != null)
+ if (parent is PhotoAlbum photoAlbum)
{
return photoAlbum;
}
diff --git a/MediaBrowser.Controller/Entities/Share.cs b/MediaBrowser.Controller/Entities/Share.cs
index 50f1655f3..7e4ec1830 100644
--- a/MediaBrowser.Controller/Entities/Share.cs
+++ b/MediaBrowser.Controller/Entities/Share.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
namespace MediaBrowser.Controller.Entities
diff --git a/MediaBrowser.Controller/Entities/Studio.cs b/MediaBrowser.Controller/Entities/Studio.cs
index 9018ddb75..ae1d10447 100644
--- a/MediaBrowser.Controller/Entities/Studio.cs
+++ b/MediaBrowser.Controller/Entities/Studio.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/MediaBrowser.Controller/Entities/TV/Episode.cs b/MediaBrowser.Controller/Entities/TV/Episode.cs
index 70663ef47..2724bd9b3 100644
--- a/MediaBrowser.Controller/Entities/TV/Episode.cs
+++ b/MediaBrowser.Controller/Entities/TV/Episode.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/MediaBrowser.Controller/Entities/TV/Season.cs b/MediaBrowser.Controller/Entities/TV/Season.cs
index 5b8168d3d..ad3e0fe8d 100644
--- a/MediaBrowser.Controller/Entities/TV/Season.cs
+++ b/MediaBrowser.Controller/Entities/TV/Season.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/MediaBrowser.Controller/Entities/TV/Series.cs b/MediaBrowser.Controller/Entities/TV/Series.cs
index 9f9a2ad50..ded825abc 100644
--- a/MediaBrowser.Controller/Entities/TV/Series.cs
+++ b/MediaBrowser.Controller/Entities/TV/Series.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
@@ -316,20 +318,13 @@ namespace MediaBrowser.Controller.Entities.TV
cancellationToken.ThrowIfCancellationRequested();
- var skipItem = false;
-
- var episode = item as Episode;
-
- if (episode != null
+ bool skipItem = item is Episode episode
&& refreshOptions.MetadataRefreshMode != MetadataRefreshMode.FullRefresh
&& !refreshOptions.ReplaceAllMetadata
&& episode.IsMissingEpisode
&& episode.LocationType == LocationType.Virtual
&& episode.PremiereDate.HasValue
- && (DateTime.UtcNow - episode.PremiereDate.Value).TotalDays > 30)
- {
- skipItem = true;
- }
+ && (DateTime.UtcNow - episode.PremiereDate.Value).TotalDays > 30;
if (!skipItem)
{
diff --git a/MediaBrowser.Controller/Entities/Trailer.cs b/MediaBrowser.Controller/Entities/Trailer.cs
index 9ae8ad708..b086b5906 100644
--- a/MediaBrowser.Controller/Entities/Trailer.cs
+++ b/MediaBrowser.Controller/Entities/Trailer.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/MediaBrowser.Controller/Entities/UserItemData.cs b/MediaBrowser.Controller/Entities/UserItemData.cs
index db63c42e4..f60359c01 100644
--- a/MediaBrowser.Controller/Entities/UserItemData.cs
+++ b/MediaBrowser.Controller/Entities/UserItemData.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/MediaBrowser.Controller/Entities/UserRootFolder.cs b/MediaBrowser.Controller/Entities/UserRootFolder.cs
index 7f7224ae0..e492740ed 100644
--- a/MediaBrowser.Controller/Entities/UserRootFolder.cs
+++ b/MediaBrowser.Controller/Entities/UserRootFolder.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/MediaBrowser.Controller/Entities/UserView.cs b/MediaBrowser.Controller/Entities/UserView.cs
index b1da4d64c..0dfde2766 100644
--- a/MediaBrowser.Controller/Entities/UserView.cs
+++ b/MediaBrowser.Controller/Entities/UserView.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
@@ -75,10 +77,7 @@ namespace MediaBrowser.Controller.Entities
public override List<BaseItem> GetChildren(User user, bool includeLinkedChildren, InternalItemsQuery query)
{
- if (query == null)
- {
- query = new InternalItemsQuery(user);
- }
+ query ??= new InternalItemsQuery(user);
query.EnableTotalRecordCount = false;
var result = GetItemList(query);
diff --git a/MediaBrowser.Controller/Entities/UserViewBuilder.cs b/MediaBrowser.Controller/Entities/UserViewBuilder.cs
index 78a64d8c9..15a4573c2 100644
--- a/MediaBrowser.Controller/Entities/UserViewBuilder.cs
+++ b/MediaBrowser.Controller/Entities/UserViewBuilder.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/MediaBrowser.Controller/Entities/Video.cs b/MediaBrowser.Controller/Entities/Video.cs
index 6320b01b8..723027a88 100644
--- a/MediaBrowser.Controller/Entities/Video.cs
+++ b/MediaBrowser.Controller/Entities/Video.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/MediaBrowser.Controller/Entities/Year.cs b/MediaBrowser.Controller/Entities/Year.cs
index b2e4d307a..4d84a151a 100644
--- a/MediaBrowser.Controller/Entities/Year.cs
+++ b/MediaBrowser.Controller/Entities/Year.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/MediaBrowser.Controller/Events/IEventConsumer.cs b/MediaBrowser.Controller/Events/IEventConsumer.cs
index 5c4ab5d8d..93005134a 100644
--- a/MediaBrowser.Controller/Events/IEventConsumer.cs
+++ b/MediaBrowser.Controller/Events/IEventConsumer.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
using System.Threading.Tasks;
namespace MediaBrowser.Controller.Events
diff --git a/MediaBrowser.Controller/Events/IEventManager.cs b/MediaBrowser.Controller/Events/IEventManager.cs
index a1f40b3a6..074e3f1fe 100644
--- a/MediaBrowser.Controller/Events/IEventManager.cs
+++ b/MediaBrowser.Controller/Events/IEventManager.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
using System.Threading.Tasks;
namespace MediaBrowser.Controller.Events
diff --git a/MediaBrowser.Controller/Events/Session/SessionEndedEventArgs.cs b/MediaBrowser.Controller/Events/Session/SessionEndedEventArgs.cs
index 46d7e5a17..3a331ad00 100644
--- a/MediaBrowser.Controller/Events/Session/SessionEndedEventArgs.cs
+++ b/MediaBrowser.Controller/Events/Session/SessionEndedEventArgs.cs
@@ -1,4 +1,4 @@
-using Jellyfin.Data.Events;
+using Jellyfin.Data.Events;
using MediaBrowser.Controller.Session;
namespace MediaBrowser.Controller.Events.Session
diff --git a/MediaBrowser.Controller/Events/Session/SessionStartedEventArgs.cs b/MediaBrowser.Controller/Events/Session/SessionStartedEventArgs.cs
index aab19cc46..deeaaf55d 100644
--- a/MediaBrowser.Controller/Events/Session/SessionStartedEventArgs.cs
+++ b/MediaBrowser.Controller/Events/Session/SessionStartedEventArgs.cs
@@ -1,4 +1,4 @@
-using Jellyfin.Data.Events;
+using Jellyfin.Data.Events;
using MediaBrowser.Controller.Session;
namespace MediaBrowser.Controller.Events.Session
diff --git a/MediaBrowser.Controller/Events/Updates/PluginInstallationCancelledEventArgs.cs b/MediaBrowser.Controller/Events/Updates/PluginInstallationCancelledEventArgs.cs
index b06046c05..0dd8b0dbf 100644
--- a/MediaBrowser.Controller/Events/Updates/PluginInstallationCancelledEventArgs.cs
+++ b/MediaBrowser.Controller/Events/Updates/PluginInstallationCancelledEventArgs.cs
@@ -1,4 +1,4 @@
-using Jellyfin.Data.Events;
+using Jellyfin.Data.Events;
using MediaBrowser.Model.Updates;
namespace MediaBrowser.Controller.Events.Updates
diff --git a/MediaBrowser.Controller/Events/Updates/PluginInstalledEventArgs.cs b/MediaBrowser.Controller/Events/Updates/PluginInstalledEventArgs.cs
index dfadc9f61..c1d503a7e 100644
--- a/MediaBrowser.Controller/Events/Updates/PluginInstalledEventArgs.cs
+++ b/MediaBrowser.Controller/Events/Updates/PluginInstalledEventArgs.cs
@@ -1,4 +1,4 @@
-using Jellyfin.Data.Events;
+using Jellyfin.Data.Events;
using MediaBrowser.Model.Updates;
namespace MediaBrowser.Controller.Events.Updates
diff --git a/MediaBrowser.Controller/Events/Updates/PluginInstallingEventArgs.cs b/MediaBrowser.Controller/Events/Updates/PluginInstallingEventArgs.cs
index 045a60027..7a9866834 100644
--- a/MediaBrowser.Controller/Events/Updates/PluginInstallingEventArgs.cs
+++ b/MediaBrowser.Controller/Events/Updates/PluginInstallingEventArgs.cs
@@ -1,4 +1,4 @@
-using Jellyfin.Data.Events;
+using Jellyfin.Data.Events;
using MediaBrowser.Model.Updates;
namespace MediaBrowser.Controller.Events.Updates
diff --git a/MediaBrowser.Controller/Events/Updates/PluginUpdatedEventArgs.cs b/MediaBrowser.Controller/Events/Updates/PluginUpdatedEventArgs.cs
index 661ca066a..b078e06dc 100644
--- a/MediaBrowser.Controller/Events/Updates/PluginUpdatedEventArgs.cs
+++ b/MediaBrowser.Controller/Events/Updates/PluginUpdatedEventArgs.cs
@@ -1,4 +1,4 @@
-using Jellyfin.Data.Events;
+using Jellyfin.Data.Events;
using MediaBrowser.Model.Updates;
namespace MediaBrowser.Controller.Events.Updates
diff --git a/MediaBrowser.Controller/Extensions/StringExtensions.cs b/MediaBrowser.Controller/Extensions/StringExtensions.cs
index 182c8ef65..8441a3171 100644
--- a/MediaBrowser.Controller/Extensions/StringExtensions.cs
+++ b/MediaBrowser.Controller/Extensions/StringExtensions.cs
@@ -1,4 +1,3 @@
-#nullable enable
#pragma warning disable CS1591
using System;
diff --git a/MediaBrowser.Controller/IDisplayPreferencesManager.cs b/MediaBrowser.Controller/IDisplayPreferencesManager.cs
index be1d974a4..1678d5067 100644
--- a/MediaBrowser.Controller/IDisplayPreferencesManager.cs
+++ b/MediaBrowser.Controller/IDisplayPreferencesManager.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections.Generic;
using Jellyfin.Data.Entities;
diff --git a/MediaBrowser.Controller/IServerApplicationHost.cs b/MediaBrowser.Controller/IServerApplicationHost.cs
index 6a65a8e47..094923842 100644
--- a/MediaBrowser.Controller/IServerApplicationHost.cs
+++ b/MediaBrowser.Controller/IServerApplicationHost.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/MediaBrowser.Controller/IServerApplicationPaths.cs b/MediaBrowser.Controller/IServerApplicationPaths.cs
index be57d6bca..1890dbb36 100644
--- a/MediaBrowser.Controller/IServerApplicationPaths.cs
+++ b/MediaBrowser.Controller/IServerApplicationPaths.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using MediaBrowser.Common.Configuration;
diff --git a/MediaBrowser.Controller/Library/DeleteOptions.cs b/MediaBrowser.Controller/Library/DeleteOptions.cs
index b7417efcb..408e70284 100644
--- a/MediaBrowser.Controller/Library/DeleteOptions.cs
+++ b/MediaBrowser.Controller/Library/DeleteOptions.cs
@@ -4,13 +4,13 @@ namespace MediaBrowser.Controller.Library
{
public class DeleteOptions
{
- public bool DeleteFileLocation { get; set; }
-
- public bool DeleteFromExternalProvider { get; set; }
-
public DeleteOptions()
{
DeleteFromExternalProvider = true;
}
+
+ public bool DeleteFileLocation { get; set; }
+
+ public bool DeleteFromExternalProvider { get; set; }
}
}
diff --git a/MediaBrowser.Controller/Library/IIntroProvider.cs b/MediaBrowser.Controller/Library/IIntroProvider.cs
index d45493d40..a74d1b9f0 100644
--- a/MediaBrowser.Controller/Library/IIntroProvider.cs
+++ b/MediaBrowser.Controller/Library/IIntroProvider.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System.Collections.Generic;
using System.Threading.Tasks;
using MediaBrowser.Controller.Entities;
@@ -10,6 +12,12 @@ namespace MediaBrowser.Controller.Library
public interface IIntroProvider
{
/// <summary>
+ /// Gets the name.
+ /// </summary>
+ /// <value>The name.</value>
+ string Name { get; }
+
+ /// <summary>
/// Gets the intros.
/// </summary>
/// <param name="item">The item.</param>
@@ -22,11 +30,5 @@ namespace MediaBrowser.Controller.Library
/// </summary>
/// <returns>IEnumerable{System.String}.</returns>
IEnumerable<string> GetAllIntroFiles();
-
- /// <summary>
- /// Gets the name.
- /// </summary>
- /// <value>The name.</value>
- string Name { get; }
}
}
diff --git a/MediaBrowser.Controller/Library/ILibraryManager.cs b/MediaBrowser.Controller/Library/ILibraryManager.cs
index 6d9b568da..782e15398 100644
--- a/MediaBrowser.Controller/Library/ILibraryManager.cs
+++ b/MediaBrowser.Controller/Library/ILibraryManager.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/MediaBrowser.Controller/Library/ILiveStream.cs b/MediaBrowser.Controller/Library/ILiveStream.cs
index ff25be657..85d866de5 100644
--- a/MediaBrowser.Controller/Library/ILiveStream.cs
+++ b/MediaBrowser.Controller/Library/ILiveStream.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System.Threading;
diff --git a/MediaBrowser.Controller/Library/IMediaSourceManager.cs b/MediaBrowser.Controller/Library/IMediaSourceManager.cs
index 21c6ef2af..d3d85a056 100644
--- a/MediaBrowser.Controller/Library/IMediaSourceManager.cs
+++ b/MediaBrowser.Controller/Library/IMediaSourceManager.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/MediaBrowser.Controller/Library/IMetadataSaver.cs b/MediaBrowser.Controller/Library/IMetadataSaver.cs
index 027cc5b40..5fbfad881 100644
--- a/MediaBrowser.Controller/Library/IMetadataSaver.cs
+++ b/MediaBrowser.Controller/Library/IMetadataSaver.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System.Threading;
using MediaBrowser.Controller.Entities;
diff --git a/MediaBrowser.Controller/Library/IMusicManager.cs b/MediaBrowser.Controller/Library/IMusicManager.cs
index d12f008e7..5329841bf 100644
--- a/MediaBrowser.Controller/Library/IMusicManager.cs
+++ b/MediaBrowser.Controller/Library/IMusicManager.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System.Collections.Generic;
diff --git a/MediaBrowser.Controller/Library/IUserDataManager.cs b/MediaBrowser.Controller/Library/IUserDataManager.cs
index c6a83e4dc..58499e853 100644
--- a/MediaBrowser.Controller/Library/IUserDataManager.cs
+++ b/MediaBrowser.Controller/Library/IUserDataManager.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/MediaBrowser.Controller/Library/IUserManager.cs b/MediaBrowser.Controller/Library/IUserManager.cs
index 6e267834b..c95b0ea32 100644
--- a/MediaBrowser.Controller/Library/IUserManager.cs
+++ b/MediaBrowser.Controller/Library/IUserManager.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/MediaBrowser.Controller/Library/IUserViewManager.cs b/MediaBrowser.Controller/Library/IUserViewManager.cs
index 8d541e8b6..46004e42f 100644
--- a/MediaBrowser.Controller/Library/IUserViewManager.cs
+++ b/MediaBrowser.Controller/Library/IUserViewManager.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/MediaBrowser.Controller/Library/IntroInfo.cs b/MediaBrowser.Controller/Library/IntroInfo.cs
index 283cc631c..90786786b 100644
--- a/MediaBrowser.Controller/Library/IntroInfo.cs
+++ b/MediaBrowser.Controller/Library/IntroInfo.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/MediaBrowser.Controller/Library/ItemChangeEventArgs.cs b/MediaBrowser.Controller/Library/ItemChangeEventArgs.cs
index 1798a4fad..a37dc7af1 100644
--- a/MediaBrowser.Controller/Library/ItemChangeEventArgs.cs
+++ b/MediaBrowser.Controller/Library/ItemChangeEventArgs.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using MediaBrowser.Controller.Entities;
diff --git a/MediaBrowser.Controller/Library/ItemResolveArgs.cs b/MediaBrowser.Controller/Library/ItemResolveArgs.cs
index 12a311dc3..0e2d8fb02 100644
--- a/MediaBrowser.Controller/Library/ItemResolveArgs.cs
+++ b/MediaBrowser.Controller/Library/ItemResolveArgs.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
@@ -14,14 +16,14 @@ namespace MediaBrowser.Controller.Library
/// These are arguments relating to the file system that are collected once and then referred to
/// whenever needed. Primarily for entity resolution.
/// </summary>
- public class ItemResolveArgs : EventArgs
+ public class ItemResolveArgs
{
/// <summary>
/// The _app paths.
/// </summary>
private readonly IServerApplicationPaths _appPaths;
- public IDirectoryService DirectoryService { get; private set; }
+ private LibraryOptions _libraryOptions;
/// <summary>
/// Initializes a new instance of the <see cref="ItemResolveArgs" /> class.
@@ -34,17 +36,18 @@ namespace MediaBrowser.Controller.Library
DirectoryService = directoryService;
}
+ public IDirectoryService DirectoryService { get; }
+
/// <summary>
/// Gets the file system children.
/// </summary>
/// <value>The file system children.</value>
public FileSystemMetadata[] FileSystemChildren { get; set; }
- public LibraryOptions LibraryOptions { get; set; }
-
- public LibraryOptions GetLibraryOptions()
+ public LibraryOptions LibraryOptions
{
- return LibraryOptions ?? (LibraryOptions = Parent == null ? new LibraryOptions() : BaseItem.LibraryManager.GetLibraryOptions(Parent));
+ get => _libraryOptions ??= Parent == null ? new LibraryOptions() : BaseItem.LibraryManager.GetLibraryOptions(Parent);
+ set => _libraryOptions = value;
}
/// <summary>
@@ -60,10 +63,10 @@ namespace MediaBrowser.Controller.Library
public FileSystemMetadata FileInfo { get; set; }
/// <summary>
- /// Gets or sets the path.
+ /// Gets the path.
/// </summary>
/// <value>The path.</value>
- public string Path { get; set; }
+ public string Path => FileInfo.FullName;
/// <summary>
/// Gets a value indicating whether this instance is directory.
@@ -139,7 +142,7 @@ namespace MediaBrowser.Controller.Library
/// Adds the additional location.
/// </summary>
/// <param name="path">The path.</param>
- /// <exception cref="ArgumentNullException"></exception>
+ /// <exception cref="ArgumentNullException"><paramref name="path"/> is <c>null</c> or empty.</exception>
public void AddAdditionalLocation(string path)
{
if (string.IsNullOrEmpty(path))
@@ -147,11 +150,7 @@ namespace MediaBrowser.Controller.Library
throw new ArgumentException("The path was empty or null.", nameof(path));
}
- if (AdditionalLocations == null)
- {
- AdditionalLocations = new List<string>();
- }
-
+ AdditionalLocations ??= new List<string>();
AdditionalLocations.Add(path);
}
@@ -175,7 +174,7 @@ namespace MediaBrowser.Controller.Library
/// </summary>
/// <param name="name">The name.</param>
/// <returns>FileSystemInfo.</returns>
- /// <exception cref="ArgumentNullException"></exception>
+ /// <exception cref="ArgumentNullException"><paramref name="name"/> is <c>null</c> or empty.</exception>
public FileSystemMetadata GetFileSystemEntryByName(string name)
{
if (string.IsNullOrEmpty(name))
diff --git a/MediaBrowser.Controller/Library/LibraryManagerExtensions.cs b/MediaBrowser.Controller/Library/LibraryManagerExtensions.cs
index 9581603f0..7bc8fa5ab 100644
--- a/MediaBrowser.Controller/Library/LibraryManagerExtensions.cs
+++ b/MediaBrowser.Controller/Library/LibraryManagerExtensions.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/MediaBrowser.Controller/Library/MetadataConfigurationExtensions.cs b/MediaBrowser.Controller/Library/MetadataConfigurationExtensions.cs
index 884f9e773..41cfcae16 100644
--- a/MediaBrowser.Controller/Library/MetadataConfigurationExtensions.cs
+++ b/MediaBrowser.Controller/Library/MetadataConfigurationExtensions.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using MediaBrowser.Common.Configuration;
diff --git a/MediaBrowser.Controller/Library/NameExtensions.cs b/MediaBrowser.Controller/Library/NameExtensions.cs
index 6e79dc8dd..29bfeca09 100644
--- a/MediaBrowser.Controller/Library/NameExtensions.cs
+++ b/MediaBrowser.Controller/Library/NameExtensions.cs
@@ -1,4 +1,3 @@
-#nullable enable
#pragma warning disable CS1591
using System;
diff --git a/MediaBrowser.Controller/Library/PlaybackProgressEventArgs.cs b/MediaBrowser.Controller/Library/PlaybackProgressEventArgs.cs
index a2be3a42a..609336ec4 100644
--- a/MediaBrowser.Controller/Library/PlaybackProgressEventArgs.cs
+++ b/MediaBrowser.Controller/Library/PlaybackProgressEventArgs.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/MediaBrowser.Controller/Library/PlaybackStartEventArgs.cs b/MediaBrowser.Controller/Library/PlaybackStartEventArgs.cs
index ac372bceb..2138fef58 100644
--- a/MediaBrowser.Controller/Library/PlaybackStartEventArgs.cs
+++ b/MediaBrowser.Controller/Library/PlaybackStartEventArgs.cs
@@ -1,4 +1,4 @@
-namespace MediaBrowser.Controller.Library
+namespace MediaBrowser.Controller.Library
{
/// <summary>
/// An event that occurs when playback is started.
diff --git a/MediaBrowser.Controller/Library/Profiler.cs b/MediaBrowser.Controller/Library/Profiler.cs
index 5efdc6a48..583fd73c3 100644
--- a/MediaBrowser.Controller/Library/Profiler.cs
+++ b/MediaBrowser.Controller/Library/Profiler.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Diagnostics;
using System.Globalization;
@@ -13,12 +15,12 @@ namespace MediaBrowser.Controller.Library
/// <summary>
/// The name.
/// </summary>
- readonly string _name;
+ private readonly string _name;
/// <summary>
/// The stopwatch.
/// </summary>
- readonly Stopwatch _stopwatch;
+ private readonly Stopwatch _stopwatch;
/// <summary>
/// The _logger.
diff --git a/MediaBrowser.Controller/Library/SearchHintInfo.cs b/MediaBrowser.Controller/Library/SearchHintInfo.cs
index 897c2b7f4..de7806adc 100644
--- a/MediaBrowser.Controller/Library/SearchHintInfo.cs
+++ b/MediaBrowser.Controller/Library/SearchHintInfo.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using MediaBrowser.Controller.Entities;
namespace MediaBrowser.Controller.Library
diff --git a/MediaBrowser.Controller/Library/TVUtils.cs b/MediaBrowser.Controller/Library/TVUtils.cs
index a3aa6019e..968338dc6 100644
--- a/MediaBrowser.Controller/Library/TVUtils.cs
+++ b/MediaBrowser.Controller/Library/TVUtils.cs
@@ -1,4 +1,5 @@
using System;
+using System.Diagnostics.CodeAnalysis;
namespace MediaBrowser.Controller.Library
{
@@ -12,7 +13,8 @@ namespace MediaBrowser.Controller.Library
/// </summary>
/// <param name="day">The day.</param>
/// <returns>List{DayOfWeek}.</returns>
- public static DayOfWeek[] GetAirDays(string day)
+ [return: NotNullIfNotNull("day")]
+ public static DayOfWeek[]? GetAirDays(string? day)
{
if (!string.IsNullOrEmpty(day))
{
diff --git a/MediaBrowser.Controller/Library/UserDataSaveEventArgs.cs b/MediaBrowser.Controller/Library/UserDataSaveEventArgs.cs
index cd9109753..bfe433c97 100644
--- a/MediaBrowser.Controller/Library/UserDataSaveEventArgs.cs
+++ b/MediaBrowser.Controller/Library/UserDataSaveEventArgs.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/MediaBrowser.Controller/LiveTv/ActiveRecordingInfo.cs b/MediaBrowser.Controller/LiveTv/ActiveRecordingInfo.cs
new file mode 100644
index 000000000..463061e68
--- /dev/null
+++ b/MediaBrowser.Controller/LiveTv/ActiveRecordingInfo.cs
@@ -0,0 +1,19 @@
+#nullable disable
+
+#pragma warning disable CS1591
+
+using System.Threading;
+
+namespace MediaBrowser.Controller.LiveTv
+{
+ public class ActiveRecordingInfo
+ {
+ public string Id { get; set; }
+
+ public string Path { get; set; }
+
+ public TimerInfo Timer { get; set; }
+
+ public CancellationTokenSource CancellationTokenSource { get; set; }
+ }
+} \ No newline at end of file
diff --git a/MediaBrowser.Controller/LiveTv/ChannelInfo.cs b/MediaBrowser.Controller/LiveTv/ChannelInfo.cs
index 166c4d77c..699c15f93 100644
--- a/MediaBrowser.Controller/LiveTv/ChannelInfo.cs
+++ b/MediaBrowser.Controller/LiveTv/ChannelInfo.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using MediaBrowser.Model.LiveTv;
@@ -22,7 +24,7 @@ namespace MediaBrowser.Controller.LiveTv
public string Number { get; set; }
/// <summary>
- /// Get or sets the Id.
+ /// Gets or sets the Id.
/// </summary>
/// <value>The id of the channel.</value>
public string Id { get; set; }
@@ -52,13 +54,13 @@ namespace MediaBrowser.Controller.LiveTv
public string ChannelGroup { get; set; }
/// <summary>
- /// Supply the image path if it can be accessed directly from the file system.
+ /// Gets or sets the the image path if it can be accessed directly from the file system.
/// </summary>
/// <value>The image path.</value>
public string ImagePath { get; set; }
/// <summary>
- /// Supply the image url if it can be downloaded.
+ /// Gets or sets the image url if it can be downloaded.
/// </summary>
/// <value>The image URL.</value>
public string ImageUrl { get; set; }
diff --git a/MediaBrowser.Controller/LiveTv/IListingsProvider.cs b/MediaBrowser.Controller/LiveTv/IListingsProvider.cs
index 038ff2eae..2bd4b20e8 100644
--- a/MediaBrowser.Controller/LiveTv/IListingsProvider.cs
+++ b/MediaBrowser.Controller/LiveTv/IListingsProvider.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs
index 54495c1c4..f4dc18e11 100644
--- a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs
+++ b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
@@ -266,16 +268,21 @@ namespace MediaBrowser.Controller.LiveTv
void AddChannelInfo(IReadOnlyCollection<(BaseItemDto, LiveTvChannel)> items, DtoOptions options, User user);
Task<List<ChannelInfo>> GetChannelsForListingsProvider(string id, CancellationToken cancellationToken);
+
Task<List<ChannelInfo>> GetChannelsFromListingsProviderData(string id, CancellationToken cancellationToken);
IListingsProvider[] ListingProviders { get; }
List<NameIdPair> GetTunerHostTypes();
+
Task<List<TunerHostInfo>> DiscoverTuners(bool newDevicesOnly, CancellationToken cancellationToken);
event EventHandler<GenericEventArgs<TimerEventInfo>> SeriesTimerCancelled;
+
event EventHandler<GenericEventArgs<TimerEventInfo>> TimerCancelled;
+
event EventHandler<GenericEventArgs<TimerEventInfo>> TimerCreated;
+
event EventHandler<GenericEventArgs<TimerEventInfo>> SeriesTimerCreated;
string GetEmbyTvActiveRecordingPath(string id);
@@ -286,15 +293,4 @@ namespace MediaBrowser.Controller.LiveTv
List<BaseItem> GetRecordingFolders(User user);
}
-
- public class ActiveRecordingInfo
- {
- public string Id { get; set; }
-
- public string Path { get; set; }
-
- public TimerInfo Timer { get; set; }
-
- public CancellationTokenSource CancellationTokenSource { get; set; }
- }
}
diff --git a/MediaBrowser.Controller/LiveTv/ILiveTvService.cs b/MediaBrowser.Controller/LiveTv/ILiveTvService.cs
index 3ca1d165e..897f263f3 100644
--- a/MediaBrowser.Controller/LiveTv/ILiveTvService.cs
+++ b/MediaBrowser.Controller/LiveTv/ILiveTvService.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/MediaBrowser.Controller/LiveTv/ITunerHost.cs b/MediaBrowser.Controller/LiveTv/ITunerHost.cs
index abca8f239..7dced9f5e 100644
--- a/MediaBrowser.Controller/LiveTv/ITunerHost.cs
+++ b/MediaBrowser.Controller/LiveTv/ITunerHost.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System.Collections.Generic;
diff --git a/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs b/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs
index ec933caf3..51e56f4b5 100644
--- a/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs
+++ b/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs b/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs
index 43af495dd..a66bec11c 100644
--- a/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs
+++ b/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
@@ -99,7 +101,7 @@ namespace MediaBrowser.Controller.LiveTv
public bool IsMovie { get; set; }
/// <summary>
- /// Gets or sets a value indicating whether this instance is sports.
+ /// Gets a value indicating whether this instance is sports.
/// </summary>
/// <value><c>true</c> if this instance is sports; otherwise, <c>false</c>.</value>
[JsonIgnore]
@@ -113,35 +115,35 @@ namespace MediaBrowser.Controller.LiveTv
public bool IsSeries { get; set; }
/// <summary>
- /// Gets or sets a value indicating whether this instance is live.
+ /// Gets a value indicating whether this instance is live.
/// </summary>
/// <value><c>true</c> if this instance is live; otherwise, <c>false</c>.</value>
[JsonIgnore]
public bool IsLive => Tags.Contains("Live", StringComparer.OrdinalIgnoreCase);
/// <summary>
- /// Gets or sets a value indicating whether this instance is news.
+ /// Gets a value indicating whether this instance is news.
/// </summary>
/// <value><c>true</c> if this instance is news; otherwise, <c>false</c>.</value>
[JsonIgnore]
public bool IsNews => Tags.Contains("News", StringComparer.OrdinalIgnoreCase);
/// <summary>
- /// Gets or sets a value indicating whether this instance is kids.
+ /// Gets a value indicating whether this instance is kids.
/// </summary>
/// <value><c>true</c> if this instance is kids; otherwise, <c>false</c>.</value>
[JsonIgnore]
public bool IsKids => Tags.Contains("Kids", StringComparer.OrdinalIgnoreCase);
/// <summary>
- /// Gets or sets a value indicating whether this instance is premiere.
+ /// Gets a value indicating whether this instance is premiere.
/// </summary>
/// <value><c>true</c> if this instance is premiere; otherwise, <c>false</c>.</value>
[JsonIgnore]
public bool IsPremiere => Tags.Contains("Premiere", StringComparer.OrdinalIgnoreCase);
/// <summary>
- /// Returns the folder containing the item.
+ /// Gets the folder containing the item.
/// If the item is a folder, it returns the folder itself.
/// </summary>
/// <value>The containing folder path.</value>
diff --git a/MediaBrowser.Controller/LiveTv/LiveTvServiceStatusInfo.cs b/MediaBrowser.Controller/LiveTv/LiveTvServiceStatusInfo.cs
index b62974904..eb3babc18 100644
--- a/MediaBrowser.Controller/LiveTv/LiveTvServiceStatusInfo.cs
+++ b/MediaBrowser.Controller/LiveTv/LiveTvServiceStatusInfo.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System.Collections.Generic;
diff --git a/MediaBrowser.Controller/LiveTv/LiveTvTunerInfo.cs b/MediaBrowser.Controller/LiveTv/LiveTvTunerInfo.cs
index 739978e7c..aa5eb59d1 100644
--- a/MediaBrowser.Controller/LiveTv/LiveTvTunerInfo.cs
+++ b/MediaBrowser.Controller/LiveTv/LiveTvTunerInfo.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System.Collections.Generic;
diff --git a/MediaBrowser.Controller/LiveTv/ProgramInfo.cs b/MediaBrowser.Controller/LiveTv/ProgramInfo.cs
index f9f559ee9..3c3ac2471 100644
--- a/MediaBrowser.Controller/LiveTv/ProgramInfo.cs
+++ b/MediaBrowser.Controller/LiveTv/ProgramInfo.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
@@ -8,8 +10,16 @@ namespace MediaBrowser.Controller.LiveTv
{
public class ProgramInfo
{
+ public ProgramInfo()
+ {
+ Genres = new List<string>();
+
+ ProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
+ SeriesProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
+ }
+
/// <summary>
- /// Id of the program.
+ /// Gets or sets the id of the program.
/// </summary>
public string Id { get; set; }
@@ -20,7 +30,7 @@ namespace MediaBrowser.Controller.LiveTv
public string ChannelId { get; set; }
/// <summary>
- /// Name of the program.
+ /// Gets or sets the name of the program.
/// </summary>
public string Name { get; set; }
@@ -43,17 +53,17 @@ namespace MediaBrowser.Controller.LiveTv
public string ShortOverview { get; set; }
/// <summary>
- /// The start date of the program, in UTC.
+ /// Gets or sets the start date of the program, in UTC.
/// </summary>
public DateTime StartDate { get; set; }
/// <summary>
- /// The end date of the program, in UTC.
+ /// Gets or sets the end date of the program, in UTC.
/// </summary>
public DateTime EndDate { get; set; }
/// <summary>
- /// Genre of the program.
+ /// Gets or sets the genre of the program.
/// </summary>
public List<string> Genres { get; set; }
@@ -69,6 +79,9 @@ namespace MediaBrowser.Controller.LiveTv
/// <value><c>true</c> if this instance is hd; otherwise, <c>false</c>.</value>
public bool? IsHD { get; set; }
+ /// <summary>
+ /// Gets or sets a value indicating whether this instance is 3d.
+ /// </summary>
public bool? Is3D { get; set; }
/// <summary>
@@ -98,13 +111,13 @@ namespace MediaBrowser.Controller.LiveTv
public string EpisodeTitle { get; set; }
/// <summary>
- /// Supply the image path if it can be accessed directly from the file system.
+ /// Gets or sets the image path if it can be accessed directly from the file system.
/// </summary>
/// <value>The image path.</value>
public string ImagePath { get; set; }
/// <summary>
- /// Supply the image url if it can be downloaded.
+ /// Gets or sets the image url if it can be downloaded.
/// </summary>
/// <value>The image URL.</value>
public string ImageUrl { get; set; }
@@ -210,13 +223,5 @@ namespace MediaBrowser.Controller.LiveTv
public Dictionary<string, string> ProviderIds { get; set; }
public Dictionary<string, string> SeriesProviderIds { get; set; }
-
- public ProgramInfo()
- {
- Genres = new List<string>();
-
- ProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
- SeriesProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
- }
}
}
diff --git a/MediaBrowser.Controller/LiveTv/RecordingInfo.cs b/MediaBrowser.Controller/LiveTv/RecordingInfo.cs
index 69190694f..1dcf7a58f 100644
--- a/MediaBrowser.Controller/LiveTv/RecordingInfo.cs
+++ b/MediaBrowser.Controller/LiveTv/RecordingInfo.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
@@ -8,8 +10,13 @@ namespace MediaBrowser.Controller.LiveTv
{
public class RecordingInfo
{
+ public RecordingInfo()
+ {
+ Genres = new List<string>();
+ }
+
/// <summary>
- /// Id of the recording.
+ /// Gets or sets the id of the recording.
/// </summary>
public string Id { get; set; }
@@ -26,7 +33,7 @@ namespace MediaBrowser.Controller.LiveTv
public string TimerId { get; set; }
/// <summary>
- /// ChannelId of the recording.
+ /// Gets or sets the channelId of the recording.
/// </summary>
public string ChannelId { get; set; }
@@ -37,7 +44,7 @@ namespace MediaBrowser.Controller.LiveTv
public ChannelType ChannelType { get; set; }
/// <summary>
- /// Name of the recording.
+ /// Gets or sets the name of the recording.
/// </summary>
public string Name { get; set; }
@@ -60,12 +67,12 @@ namespace MediaBrowser.Controller.LiveTv
public string Overview { get; set; }
/// <summary>
- /// The start date of the recording, in UTC.
+ /// Gets or sets the start date of the recording, in UTC.
/// </summary>
public DateTime StartDate { get; set; }
/// <summary>
- /// The end date of the recording, in UTC.
+ /// Gets or sets the end date of the recording, in UTC.
/// </summary>
public DateTime EndDate { get; set; }
@@ -82,7 +89,7 @@ namespace MediaBrowser.Controller.LiveTv
public RecordingStatus Status { get; set; }
/// <summary>
- /// Genre of the program.
+ /// Gets or sets the genre of the program.
/// </summary>
public List<string> Genres { get; set; }
@@ -171,13 +178,13 @@ namespace MediaBrowser.Controller.LiveTv
public float? CommunityRating { get; set; }
/// <summary>
- /// Supply the image path if it can be accessed directly from the file system.
+ /// Gets or sets the image path if it can be accessed directly from the file system.
/// </summary>
/// <value>The image path.</value>
public string ImagePath { get; set; }
/// <summary>
- /// Supply the image url if it can be downloaded.
+ /// Gets or sets the image url if it can be downloaded.
/// </summary>
/// <value>The image URL.</value>
public string ImageUrl { get; set; }
@@ -199,10 +206,5 @@ namespace MediaBrowser.Controller.LiveTv
/// </summary>
/// <value>The date last updated.</value>
public DateTime DateLastUpdated { get; set; }
-
- public RecordingInfo()
- {
- Genres = new List<string>();
- }
}
}
diff --git a/MediaBrowser.Controller/LiveTv/RecordingStatusChangedEventArgs.cs b/MediaBrowser.Controller/LiveTv/RecordingStatusChangedEventArgs.cs
index 847c0ea8c..0b943c939 100644
--- a/MediaBrowser.Controller/LiveTv/RecordingStatusChangedEventArgs.cs
+++ b/MediaBrowser.Controller/LiveTv/RecordingStatusChangedEventArgs.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/MediaBrowser.Controller/LiveTv/SeriesTimerInfo.cs b/MediaBrowser.Controller/LiveTv/SeriesTimerInfo.cs
index 1343ecd98..d6811fe14 100644
--- a/MediaBrowser.Controller/LiveTv/SeriesTimerInfo.cs
+++ b/MediaBrowser.Controller/LiveTv/SeriesTimerInfo.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
@@ -8,13 +10,20 @@ namespace MediaBrowser.Controller.LiveTv
{
public class SeriesTimerInfo
{
+ public SeriesTimerInfo()
+ {
+ Days = new List<DayOfWeek>();
+ SkipEpisodesInLibrary = true;
+ KeepUntil = KeepUntil.UntilDeleted;
+ }
+
/// <summary>
- /// Id of the recording.
+ /// Gets or sets the id of the recording.
/// </summary>
public string Id { get; set; }
/// <summary>
- /// ChannelId of the recording.
+ /// Gets or sets the channelId of the recording.
/// </summary>
public string ChannelId { get; set; }
@@ -25,24 +34,27 @@ namespace MediaBrowser.Controller.LiveTv
public string ProgramId { get; set; }
/// <summary>
- /// Name of the recording.
+ /// Gets or sets the name of the recording.
/// </summary>
public string Name { get; set; }
+ /// <summary>
+ /// Gets or sets the service name.
+ /// </summary>
public string ServiceName { get; set; }
/// <summary>
- /// Description of the recording.
+ /// Gets or sets the description of the recording.
/// </summary>
public string Overview { get; set; }
/// <summary>
- /// The start date of the recording, in UTC.
+ /// Gets or sets the start date of the recording, in UTC.
/// </summary>
public DateTime StartDate { get; set; }
/// <summary>
- /// The end date of the recording, in UTC.
+ /// Gets or sets the end date of the recording, in UTC.
/// </summary>
public DateTime EndDate { get; set; }
@@ -111,12 +123,5 @@ namespace MediaBrowser.Controller.LiveTv
/// </summary>
/// <value>The series identifier.</value>
public string SeriesId { get; set; }
-
- public SeriesTimerInfo()
- {
- Days = new List<DayOfWeek>();
- SkipEpisodesInLibrary = true;
- KeepUntil = KeepUntil.UntilDeleted;
- }
}
}
diff --git a/MediaBrowser.Controller/LiveTv/TimerEventInfo.cs b/MediaBrowser.Controller/LiveTv/TimerEventInfo.cs
index 1b8f41db6..728387c56 100644
--- a/MediaBrowser.Controller/LiveTv/TimerEventInfo.cs
+++ b/MediaBrowser.Controller/LiveTv/TimerEventInfo.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#nullable enable
#pragma warning disable CS1591
diff --git a/MediaBrowser.Controller/LiveTv/TimerInfo.cs b/MediaBrowser.Controller/LiveTv/TimerInfo.cs
index aa5170617..e54dc967c 100644
--- a/MediaBrowser.Controller/LiveTv/TimerInfo.cs
+++ b/MediaBrowser.Controller/LiveTv/TimerInfo.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/MediaBrowser.Controller/LiveTv/TunerChannelMapping.cs b/MediaBrowser.Controller/LiveTv/TunerChannelMapping.cs
index 2759b314f..1c1a4417d 100644
--- a/MediaBrowser.Controller/LiveTv/TunerChannelMapping.cs
+++ b/MediaBrowser.Controller/LiveTv/TunerChannelMapping.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
namespace MediaBrowser.Controller.LiveTv
diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj
index 8c68b47dd..3f3a505ea 100644
--- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj
+++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj
@@ -16,7 +16,7 @@
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="5.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="5.0.0" />
- <PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All"/>
+ <PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All" />
<PackageReference Include="System.Threading.Tasks.Dataflow" Version="5.0.0" />
</ItemGroup>
@@ -34,6 +34,7 @@
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<TreatWarningsAsErrors Condition=" '$(Configuration)' == 'Release' ">true</TreatWarningsAsErrors>
+ <Nullable>enable</Nullable>
<AnalysisMode Condition=" '$(Configuration)' == 'Debug' ">AllEnabledByDefault</AnalysisMode>
<CodeAnalysisRuleSet>../jellyfin.ruleset</CodeAnalysisRuleSet>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
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;
diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs b/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs
index d47a689f4..1e13382b7 100644
--- a/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs
+++ b/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs b/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs
index 1f3abe8f4..88de5b292 100644
--- a/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs
+++ b/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/MediaBrowser.Controller/MediaEncoding/IAttachmentExtractor.cs b/MediaBrowser.Controller/MediaEncoding/IAttachmentExtractor.cs
index fbc827534..c38e7ec3b 100644
--- a/MediaBrowser.Controller/MediaEncoding/IAttachmentExtractor.cs
+++ b/MediaBrowser.Controller/MediaEncoding/IAttachmentExtractor.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System.IO;
diff --git a/MediaBrowser.Controller/MediaEncoding/IEncodingManager.cs b/MediaBrowser.Controller/MediaEncoding/IEncodingManager.cs
index 15a2580af..773547872 100644
--- a/MediaBrowser.Controller/MediaEncoding/IEncodingManager.cs
+++ b/MediaBrowser.Controller/MediaEncoding/IEncodingManager.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System.Collections.Generic;
diff --git a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs
index 05dd1a69b..d3260280a 100644
--- a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs
+++ b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/MediaBrowser.Controller/MediaEncoding/ISubtitleEncoder.cs b/MediaBrowser.Controller/MediaEncoding/ISubtitleEncoder.cs
index 6ebf7f159..3fb2c47e1 100644
--- a/MediaBrowser.Controller/MediaEncoding/ISubtitleEncoder.cs
+++ b/MediaBrowser.Controller/MediaEncoding/ISubtitleEncoder.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System.IO;
diff --git a/MediaBrowser.Controller/MediaEncoding/ImageEncodingOptions.cs b/MediaBrowser.Controller/MediaEncoding/ImageEncodingOptions.cs
index e7b4c8c15..044ba6d33 100644
--- a/MediaBrowser.Controller/MediaEncoding/ImageEncodingOptions.cs
+++ b/MediaBrowser.Controller/MediaEncoding/ImageEncodingOptions.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
namespace MediaBrowser.Controller.MediaEncoding
diff --git a/MediaBrowser.Controller/MediaEncoding/JobLogger.cs b/MediaBrowser.Controller/MediaEncoding/JobLogger.cs
index 227c5f258..aa5e2c403 100644
--- a/MediaBrowser.Controller/MediaEncoding/JobLogger.cs
+++ b/MediaBrowser.Controller/MediaEncoding/JobLogger.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/MediaBrowser.Controller/MediaEncoding/MediaEncoderHelpers.cs b/MediaBrowser.Controller/MediaEncoding/MediaEncoderHelpers.cs
index 89e01c08b..841e7b287 100644
--- a/MediaBrowser.Controller/MediaEncoding/MediaEncoderHelpers.cs
+++ b/MediaBrowser.Controller/MediaEncoding/MediaEncoderHelpers.cs
@@ -1,6 +1,5 @@
#pragma warning disable CS1591
-
namespace MediaBrowser.Controller.MediaEncoding
{
/// <summary>
diff --git a/MediaBrowser.Controller/MediaEncoding/MediaInfoRequest.cs b/MediaBrowser.Controller/MediaEncoding/MediaInfoRequest.cs
index 2cb04bdc4..1dd8bcf31 100644
--- a/MediaBrowser.Controller/MediaEncoding/MediaInfoRequest.cs
+++ b/MediaBrowser.Controller/MediaEncoding/MediaInfoRequest.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using MediaBrowser.Model.Dlna;
diff --git a/MediaBrowser.Controller/Net/AuthorizationInfo.cs b/MediaBrowser.Controller/Net/AuthorizationInfo.cs
index 93573e08e..2452b25ab 100644
--- a/MediaBrowser.Controller/Net/AuthorizationInfo.cs
+++ b/MediaBrowser.Controller/Net/AuthorizationInfo.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using Jellyfin.Data.Entities;
diff --git a/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs b/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs
index 163a9c8f8..855467e8e 100644
--- a/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs
+++ b/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/MediaBrowser.Controller/Net/IAuthService.cs b/MediaBrowser.Controller/Net/IAuthService.cs
index 04b2e13e8..d15c6d318 100644
--- a/MediaBrowser.Controller/Net/IAuthService.cs
+++ b/MediaBrowser.Controller/Net/IAuthService.cs
@@ -1,5 +1,3 @@
-#nullable enable
-
using Microsoft.AspNetCore.Http;
namespace MediaBrowser.Controller.Net
diff --git a/MediaBrowser.Controller/Net/IWebSocketConnection.cs b/MediaBrowser.Controller/Net/IWebSocketConnection.cs
index e87f3bca6..e50cd9781 100644
--- a/MediaBrowser.Controller/Net/IWebSocketConnection.cs
+++ b/MediaBrowser.Controller/Net/IWebSocketConnection.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
#nullable enable
@@ -32,7 +34,7 @@ namespace MediaBrowser.Controller.Net
DateTime LastKeepAliveDate { get; set; }
/// <summary>
- /// Gets or sets the query string.
+ /// Gets the query string.
/// </summary>
/// <value>The query string.</value>
IQueryCollection QueryString { get; }
diff --git a/MediaBrowser.Controller/Net/SecurityException.cs b/MediaBrowser.Controller/Net/SecurityException.cs
index c6347133a..f0d0b45a0 100644
--- a/MediaBrowser.Controller/Net/SecurityException.cs
+++ b/MediaBrowser.Controller/Net/SecurityException.cs
@@ -1,5 +1,3 @@
-#nullable enable
-
using System;
namespace MediaBrowser.Controller.Net
diff --git a/MediaBrowser.Controller/Net/WebSocketMessageInfo.cs b/MediaBrowser.Controller/Net/WebSocketMessageInfo.cs
index be0b3ddc3..6f7ebf156 100644
--- a/MediaBrowser.Controller/Net/WebSocketMessageInfo.cs
+++ b/MediaBrowser.Controller/Net/WebSocketMessageInfo.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using MediaBrowser.Model.Net;
namespace MediaBrowser.Controller.Net
diff --git a/MediaBrowser.Controller/Notifications/INotificationManager.cs b/MediaBrowser.Controller/Notifications/INotificationManager.cs
index 08d9bc12a..7caba1097 100644
--- a/MediaBrowser.Controller/Notifications/INotificationManager.cs
+++ b/MediaBrowser.Controller/Notifications/INotificationManager.cs
@@ -19,7 +19,7 @@ namespace MediaBrowser.Controller.Notifications
/// <returns>Task.</returns>
Task SendNotification(NotificationRequest request, CancellationToken cancellationToken);
- Task SendNotification(NotificationRequest request, BaseItem relatedItem, CancellationToken cancellationToken);
+ Task SendNotification(NotificationRequest request, BaseItem? relatedItem, CancellationToken cancellationToken);
/// <summary>
/// Adds the parts.
diff --git a/MediaBrowser.Controller/Notifications/INotificationService.cs b/MediaBrowser.Controller/Notifications/INotificationService.cs
index fa947220a..535c08795 100644
--- a/MediaBrowser.Controller/Notifications/INotificationService.cs
+++ b/MediaBrowser.Controller/Notifications/INotificationService.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System.Threading;
diff --git a/MediaBrowser.Controller/Notifications/UserNotification.cs b/MediaBrowser.Controller/Notifications/UserNotification.cs
index d768abfe7..4be0e09ae 100644
--- a/MediaBrowser.Controller/Notifications/UserNotification.cs
+++ b/MediaBrowser.Controller/Notifications/UserNotification.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/MediaBrowser.Controller/Persistence/IItemRepository.cs b/MediaBrowser.Controller/Persistence/IItemRepository.cs
index 45c6805f0..56fb36af2 100644
--- a/MediaBrowser.Controller/Persistence/IItemRepository.cs
+++ b/MediaBrowser.Controller/Persistence/IItemRepository.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
@@ -153,8 +155,7 @@ namespace MediaBrowser.Controller.Persistence
/// <summary>
/// Updates the inherited values.
/// </summary>
- /// <param name="cancellationToken">The cancellation token.</param>
- void UpdateInheritedValues(CancellationToken cancellationToken);
+ void UpdateInheritedValues();
int GetCount(InternalItemsQuery query);
diff --git a/MediaBrowser.Controller/Persistence/IUserDataRepository.cs b/MediaBrowser.Controller/Persistence/IUserDataRepository.cs
index 81ba513ce..6f5f02123 100644
--- a/MediaBrowser.Controller/Persistence/IUserDataRepository.cs
+++ b/MediaBrowser.Controller/Persistence/IUserDataRepository.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System.Collections.Generic;
using System.Threading;
using MediaBrowser.Controller.Entities;
diff --git a/MediaBrowser.Controller/Playlists/Playlist.cs b/MediaBrowser.Controller/Playlists/Playlist.cs
index c9c168c4c..a80c11643 100644
--- a/MediaBrowser.Controller/Playlists/Playlist.cs
+++ b/MediaBrowser.Controller/Playlists/Playlist.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
@@ -126,10 +128,7 @@ namespace MediaBrowser.Controller.Playlists
private List<BaseItem> GetPlayableItems(User user, InternalItemsQuery query)
{
- if (query == null)
- {
- query = new InternalItemsQuery(user);
- }
+ query ??= new InternalItemsQuery(user);
query.IsFolder = false;
diff --git a/MediaBrowser.Controller/Plugins/ILocalizablePlugin.cs b/MediaBrowser.Controller/Plugins/ILocalizablePlugin.cs
deleted file mode 100644
index bf15fe040..000000000
--- a/MediaBrowser.Controller/Plugins/ILocalizablePlugin.cs
+++ /dev/null
@@ -1,22 +0,0 @@
-#pragma warning disable CS1591
-
-using System.IO;
-using System.Reflection;
-
-namespace MediaBrowser.Controller.Plugins
-{
- public interface ILocalizablePlugin
- {
- Stream GetDictionary(string culture);
- }
-
- public static class LocalizablePluginHelper
- {
- public static Stream GetDictionary(Assembly assembly, string manifestPrefix, string culture)
- {
- // Find all dictionaries using GetManifestResourceNames, start start with the prefix
- // Return the one for the culture if exists, otherwise return the default
- return null;
- }
- }
-}
diff --git a/MediaBrowser.Controller/Providers/AlbumInfo.cs b/MediaBrowser.Controller/Providers/AlbumInfo.cs
index 276bcf125..c7fad5974 100644
--- a/MediaBrowser.Controller/Providers/AlbumInfo.cs
+++ b/MediaBrowser.Controller/Providers/AlbumInfo.cs
@@ -7,6 +7,13 @@ namespace MediaBrowser.Controller.Providers
{
public class AlbumInfo : ItemLookupInfo
{
+ public AlbumInfo()
+ {
+ ArtistProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
+ SongInfos = new List<SongInfo>();
+ AlbumArtists = Array.Empty<string>();
+ }
+
/// <summary>
/// Gets or sets the album artist.
/// </summary>
@@ -20,12 +27,5 @@ namespace MediaBrowser.Controller.Providers
public Dictionary<string, string> ArtistProviderIds { get; set; }
public List<SongInfo> SongInfos { get; set; }
-
- public AlbumInfo()
- {
- ArtistProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
- SongInfos = new List<SongInfo>();
- AlbumArtists = Array.Empty<string>();
- }
}
}
diff --git a/MediaBrowser.Controller/Providers/ArtistInfo.cs b/MediaBrowser.Controller/Providers/ArtistInfo.cs
index adf885baa..e9181f476 100644
--- a/MediaBrowser.Controller/Providers/ArtistInfo.cs
+++ b/MediaBrowser.Controller/Providers/ArtistInfo.cs
@@ -6,11 +6,11 @@ namespace MediaBrowser.Controller.Providers
{
public class ArtistInfo : ItemLookupInfo
{
- public List<SongInfo> SongInfos { get; set; }
-
public ArtistInfo()
{
SongInfos = new List<SongInfo>();
}
+
+ public List<SongInfo> SongInfos { get; set; }
}
}
diff --git a/MediaBrowser.Controller/Providers/BookInfo.cs b/MediaBrowser.Controller/Providers/BookInfo.cs
index cce0a25fc..3055c5d87 100644
--- a/MediaBrowser.Controller/Providers/BookInfo.cs
+++ b/MediaBrowser.Controller/Providers/BookInfo.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
namespace MediaBrowser.Controller.Providers
diff --git a/MediaBrowser.Controller/Providers/DirectoryService.cs b/MediaBrowser.Controller/Providers/DirectoryService.cs
index 5c92069b4..291a26883 100644
--- a/MediaBrowser.Controller/Providers/DirectoryService.cs
+++ b/MediaBrowser.Controller/Providers/DirectoryService.cs
@@ -43,18 +43,17 @@ namespace MediaBrowser.Controller.Providers
return list;
}
- public FileSystemMetadata GetFile(string path)
+ public FileSystemMetadata? GetFile(string path)
{
- var result = _fileCache.GetOrAdd(path, p =>
+ if (!_fileCache.TryGetValue(path, out var result))
{
- var file = _fileSystem.GetFileInfo(p);
- return file != null && file.Exists ? file : null;
- });
-
- if (result == null)
- {
- // lets not store null results in the cache
- _fileCache.TryRemove(path, out _);
+ var file = _fileSystem.GetFileInfo(path);
+ var res = file != null && file.Exists ? file : null;
+ if (res != null)
+ {
+ result = res;
+ _fileCache.TryAdd(path, result);
+ }
}
return result;
diff --git a/MediaBrowser.Controller/Providers/DynamicImageResponse.cs b/MediaBrowser.Controller/Providers/DynamicImageResponse.cs
index 006174be8..66fddb0e3 100644
--- a/MediaBrowser.Controller/Providers/DynamicImageResponse.cs
+++ b/MediaBrowser.Controller/Providers/DynamicImageResponse.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/MediaBrowser.Controller/Providers/EpisodeInfo.cs b/MediaBrowser.Controller/Providers/EpisodeInfo.cs
index a4c8dab7e..0c932fa87 100644
--- a/MediaBrowser.Controller/Providers/EpisodeInfo.cs
+++ b/MediaBrowser.Controller/Providers/EpisodeInfo.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
@@ -7,6 +9,11 @@ namespace MediaBrowser.Controller.Providers
{
public class EpisodeInfo : ItemLookupInfo
{
+ public EpisodeInfo()
+ {
+ SeriesProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
+ }
+
public Dictionary<string, string> SeriesProviderIds { get; set; }
public int? IndexNumberEnd { get; set; }
@@ -14,10 +21,5 @@ namespace MediaBrowser.Controller.Providers
public bool IsMissingEpisode { get; set; }
public string SeriesDisplayOrder { get; set; }
-
- public EpisodeInfo()
- {
- SeriesProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
- }
}
}
diff --git a/MediaBrowser.Controller/Providers/IDirectoryService.cs b/MediaBrowser.Controller/Providers/IDirectoryService.cs
index f06481c7a..9cee06a4c 100644
--- a/MediaBrowser.Controller/Providers/IDirectoryService.cs
+++ b/MediaBrowser.Controller/Providers/IDirectoryService.cs
@@ -11,7 +11,7 @@ namespace MediaBrowser.Controller.Providers
List<FileSystemMetadata> GetFiles(string path);
- FileSystemMetadata GetFile(string path);
+ FileSystemMetadata? GetFile(string path);
IReadOnlyList<string> GetFilePaths(string path);
diff --git a/MediaBrowser.Controller/Providers/IExternalId.cs b/MediaBrowser.Controller/Providers/IExternalId.cs
index 5e38446bc..e2dbef2bc 100644
--- a/MediaBrowser.Controller/Providers/IExternalId.cs
+++ b/MediaBrowser.Controller/Providers/IExternalId.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Providers;
diff --git a/MediaBrowser.Controller/Providers/IMetadataService.cs b/MediaBrowser.Controller/Providers/IMetadataService.cs
index 5f3d4274e..05fbb18ee 100644
--- a/MediaBrowser.Controller/Providers/IMetadataService.cs
+++ b/MediaBrowser.Controller/Providers/IMetadataService.cs
@@ -11,6 +11,12 @@ namespace MediaBrowser.Controller.Providers
public interface IMetadataService
{
/// <summary>
+ /// Gets the order.
+ /// </summary>
+ /// <value>The order.</value>
+ int Order { get; }
+
+ /// <summary>
/// Determines whether this instance can refresh the specified item.
/// </summary>
/// <param name="item">The item.</param>
@@ -27,11 +33,5 @@ namespace MediaBrowser.Controller.Providers
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
Task<ItemUpdateType> RefreshMetadata(BaseItem item, MetadataRefreshOptions refreshOptions, CancellationToken cancellationToken);
-
- /// <summary>
- /// Gets the order.
- /// </summary>
- /// <value>The order.</value>
- int Order { get; }
}
}
diff --git a/MediaBrowser.Controller/Providers/IProviderManager.cs b/MediaBrowser.Controller/Providers/IProviderManager.cs
index 7bc56c82a..684bd9e68 100644
--- a/MediaBrowser.Controller/Providers/IProviderManager.cs
+++ b/MediaBrowser.Controller/Providers/IProviderManager.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
@@ -189,11 +191,4 @@ namespace MediaBrowser.Controller.Providers
double? GetRefreshProgress(Guid id);
}
-
- public enum RefreshPriority
- {
- High = 0,
- Normal = 1,
- Low = 2
- }
}
diff --git a/MediaBrowser.Controller/Providers/ImageRefreshOptions.cs b/MediaBrowser.Controller/Providers/ImageRefreshOptions.cs
index 9fc379f04..81a22affb 100644
--- a/MediaBrowser.Controller/Providers/ImageRefreshOptions.cs
+++ b/MediaBrowser.Controller/Providers/ImageRefreshOptions.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/MediaBrowser.Controller/Providers/ItemInfo.cs b/MediaBrowser.Controller/Providers/ItemInfo.cs
index b50def043..b8dd416a2 100644
--- a/MediaBrowser.Controller/Providers/ItemInfo.cs
+++ b/MediaBrowser.Controller/Providers/ItemInfo.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
@@ -14,8 +16,7 @@ namespace MediaBrowser.Controller.Providers
ContainingFolderPath = item.ContainingFolderPath;
IsInMixedFolder = item.IsInMixedFolder;
- var video = item as Video;
- if (video != null)
+ if (item is Video video)
{
VideoType = video.VideoType;
IsPlaceHolder = video.IsPlaceHolder;
diff --git a/MediaBrowser.Controller/Providers/ItemLookupInfo.cs b/MediaBrowser.Controller/Providers/ItemLookupInfo.cs
index b777cc1d3..e6f49c26a 100644
--- a/MediaBrowser.Controller/Providers/ItemLookupInfo.cs
+++ b/MediaBrowser.Controller/Providers/ItemLookupInfo.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
@@ -8,6 +10,12 @@ namespace MediaBrowser.Controller.Providers
{
public class ItemLookupInfo : IHasProviderIds
{
+ public ItemLookupInfo()
+ {
+ IsAutomated = true;
+ ProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
+ }
+
/// <summary>
/// Gets or sets the name.
/// </summary>
@@ -51,11 +59,5 @@ namespace MediaBrowser.Controller.Providers
public DateTime? PremiereDate { get; set; }
public bool IsAutomated { get; set; }
-
- public ItemLookupInfo()
- {
- IsAutomated = true;
- ProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
- }
}
}
diff --git a/MediaBrowser.Controller/Providers/LocalImageInfo.cs b/MediaBrowser.Controller/Providers/LocalImageInfo.cs
index 41801862f..a8e70e6d0 100644
--- a/MediaBrowser.Controller/Providers/LocalImageInfo.cs
+++ b/MediaBrowser.Controller/Providers/LocalImageInfo.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using MediaBrowser.Model.Entities;
diff --git a/MediaBrowser.Controller/Providers/MetadataRefreshOptions.cs b/MediaBrowser.Controller/Providers/MetadataRefreshOptions.cs
index b92b83701..115250466 100644
--- a/MediaBrowser.Controller/Providers/MetadataRefreshOptions.cs
+++ b/MediaBrowser.Controller/Providers/MetadataRefreshOptions.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
@@ -9,21 +11,6 @@ namespace MediaBrowser.Controller.Providers
{
public class MetadataRefreshOptions : ImageRefreshOptions
{
- /// <summary>
- /// When paired with MetadataRefreshMode=FullRefresh, all existing data will be overwritten with new data from the providers.
- /// </summary>
- public bool ReplaceAllMetadata { get; set; }
-
- public MetadataRefreshMode MetadataRefreshMode { get; set; }
-
- public RemoteSearchResult SearchResult { get; set; }
-
- public string[] RefreshPaths { get; set; }
-
- public bool ForceSave { get; set; }
-
- public bool EnableRemoteContentProbe { get; set; }
-
public MetadataRefreshOptions(IDirectoryService directoryService)
: base(directoryService)
{
@@ -45,15 +32,28 @@ namespace MediaBrowser.Controller.Providers
if (copy.RefreshPaths != null && copy.RefreshPaths.Length > 0)
{
- if (RefreshPaths == null)
- {
- RefreshPaths = Array.Empty<string>();
- }
+ RefreshPaths ??= Array.Empty<string>();
RefreshPaths = copy.RefreshPaths.ToArray();
}
}
+ /// <summary>
+ /// Gets or sets a value indicating whether all existing data should be overwritten with new data from providers
+ /// when paired with MetadataRefreshMode=FullRefresh
+ /// </summary>
+ public bool ReplaceAllMetadata { get; set; }
+
+ public MetadataRefreshMode MetadataRefreshMode { get; set; }
+
+ public RemoteSearchResult SearchResult { get; set; }
+
+ public string[] RefreshPaths { get; set; }
+
+ public bool ForceSave { get; set; }
+
+ public bool EnableRemoteContentProbe { get; set; }
+
public bool RefreshItem(BaseItem item)
{
if (RefreshPaths != null && RefreshPaths.Length > 0)
diff --git a/MediaBrowser.Controller/Providers/MetadataResult.cs b/MediaBrowser.Controller/Providers/MetadataResult.cs
index 864cb3050..8b0967a6e 100644
--- a/MediaBrowser.Controller/Providers/MetadataResult.cs
+++ b/MediaBrowser.Controller/Providers/MetadataResult.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
@@ -37,10 +39,7 @@ namespace MediaBrowser.Controller.Providers
public void AddPerson(PersonInfo p)
{
- if (People == null)
- {
- People = new List<PersonInfo>();
- }
+ People ??= new List<PersonInfo>();
PeopleHelper.AddPerson(People, p);
}
@@ -54,16 +53,15 @@ namespace MediaBrowser.Controller.Providers
{
People = new List<PersonInfo>();
}
-
- People.Clear();
+ else
+ {
+ People.Clear();
+ }
}
public UserItemData GetOrAddUserData(string userId)
{
- if (UserDataList == null)
- {
- UserDataList = new List<UserItemData>();
- }
+ UserDataList ??= new List<UserItemData>();
UserItemData userData = null;
diff --git a/MediaBrowser.Controller/Providers/MusicVideoInfo.cs b/MediaBrowser.Controller/Providers/MusicVideoInfo.cs
index 0b927f6eb..322320abd 100644
--- a/MediaBrowser.Controller/Providers/MusicVideoInfo.cs
+++ b/MediaBrowser.Controller/Providers/MusicVideoInfo.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System.Collections.Generic;
diff --git a/MediaBrowser.Controller/Providers/RefreshPriority.cs b/MediaBrowser.Controller/Providers/RefreshPriority.cs
new file mode 100644
index 000000000..3619f679d
--- /dev/null
+++ b/MediaBrowser.Controller/Providers/RefreshPriority.cs
@@ -0,0 +1,23 @@
+namespace MediaBrowser.Controller.Providers
+{
+ /// <summary>
+ /// Provider refresh priority.
+ /// </summary>
+ public enum RefreshPriority
+ {
+ /// <summary>
+ /// High priority.
+ /// </summary>
+ High = 0,
+
+ /// <summary>
+ /// Normal priority.
+ /// </summary>
+ Normal = 1,
+
+ /// <summary>
+ /// Low priority.
+ /// </summary>
+ Low = 2
+ }
+} \ No newline at end of file
diff --git a/MediaBrowser.Controller/Providers/RemoteSearchQuery.cs b/MediaBrowser.Controller/Providers/RemoteSearchQuery.cs
index 9653bc1c4..d4df5fa0d 100644
--- a/MediaBrowser.Controller/Providers/RemoteSearchQuery.cs
+++ b/MediaBrowser.Controller/Providers/RemoteSearchQuery.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
@@ -12,7 +14,7 @@ namespace MediaBrowser.Controller.Providers
public Guid ItemId { get; set; }
/// <summary>
- /// Will only search within the given provider when set.
+ /// Gets or sets the provider name to search within if set.
/// </summary>
public string SearchProviderName { get; set; }
diff --git a/MediaBrowser.Controller/Providers/SeasonInfo.cs b/MediaBrowser.Controller/Providers/SeasonInfo.cs
index 2a4c1f03c..7e39bc37a 100644
--- a/MediaBrowser.Controller/Providers/SeasonInfo.cs
+++ b/MediaBrowser.Controller/Providers/SeasonInfo.cs
@@ -7,11 +7,11 @@ namespace MediaBrowser.Controller.Providers
{
public class SeasonInfo : ItemLookupInfo
{
- public Dictionary<string, string> SeriesProviderIds { get; set; }
-
public SeasonInfo()
{
SeriesProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
}
+
+ public Dictionary<string, string> SeriesProviderIds { get; set; }
}
}
diff --git a/MediaBrowser.Controller/Providers/SongInfo.cs b/MediaBrowser.Controller/Providers/SongInfo.cs
index 58f76dca9..c90717a2e 100644
--- a/MediaBrowser.Controller/Providers/SongInfo.cs
+++ b/MediaBrowser.Controller/Providers/SongInfo.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/MediaBrowser.Controller/QuickConnect/IQuickConnect.cs b/MediaBrowser.Controller/QuickConnect/IQuickConnect.cs
index 959a2d771..c4e709c24 100644
--- a/MediaBrowser.Controller/QuickConnect/IQuickConnect.cs
+++ b/MediaBrowser.Controller/QuickConnect/IQuickConnect.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using MediaBrowser.Model.QuickConnect;
diff --git a/MediaBrowser.Controller/Resolvers/BaseItemResolver.cs b/MediaBrowser.Controller/Resolvers/BaseItemResolver.cs
index 25128a5cd..e77593a03 100644
--- a/MediaBrowser.Controller/Resolvers/BaseItemResolver.cs
+++ b/MediaBrowser.Controller/Resolvers/BaseItemResolver.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
@@ -11,6 +13,12 @@ namespace MediaBrowser.Controller.Resolvers
where T : BaseItem, new()
{
/// <summary>
+ /// Gets the priority.
+ /// </summary>
+ /// <value>The priority.</value>
+ public virtual ResolverPriority Priority => ResolverPriority.First;
+
+ /// <summary>
/// Resolves the specified args.
/// </summary>
/// <param name="args">The args.</param>
@@ -21,12 +29,6 @@ namespace MediaBrowser.Controller.Resolvers
}
/// <summary>
- /// Gets the priority.
- /// </summary>
- /// <value>The priority.</value>
- public virtual ResolverPriority Priority => ResolverPriority.First;
-
- /// <summary>
/// Sets initial values on the newly resolved item.
/// </summary>
/// <param name="item">The item.</param>
diff --git a/MediaBrowser.Controller/Resolvers/IResolverIgnoreRule.cs b/MediaBrowser.Controller/Resolvers/IResolverIgnoreRule.cs
index bb80e6025..a07b3e898 100644
--- a/MediaBrowser.Controller/Resolvers/IResolverIgnoreRule.cs
+++ b/MediaBrowser.Controller/Resolvers/IResolverIgnoreRule.cs
@@ -4,7 +4,7 @@ using MediaBrowser.Model.IO;
namespace MediaBrowser.Controller.Resolvers
{
/// <summary>
- /// Provides a base "rule" that anyone can use to have paths ignored by the resolver
+ /// Provides a base "rule" that anyone can use to have paths ignored by the resolver.
/// </summary>
public interface IResolverIgnoreRule
{
diff --git a/MediaBrowser.Controller/Security/AuthenticationInfo.cs b/MediaBrowser.Controller/Security/AuthenticationInfo.cs
index efac9273e..b4b242f1b 100644
--- a/MediaBrowser.Controller/Security/AuthenticationInfo.cs
+++ b/MediaBrowser.Controller/Security/AuthenticationInfo.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/MediaBrowser.Controller/Security/AuthenticationInfoQuery.cs b/MediaBrowser.Controller/Security/AuthenticationInfoQuery.cs
index c5f3da0b1..3af6a525c 100644
--- a/MediaBrowser.Controller/Security/AuthenticationInfoQuery.cs
+++ b/MediaBrowser.Controller/Security/AuthenticationInfoQuery.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/MediaBrowser.Controller/Security/IAuthenticationRepository.cs b/MediaBrowser.Controller/Security/IAuthenticationRepository.cs
index 883b74165..1dd69ccd8 100644
--- a/MediaBrowser.Controller/Security/IAuthenticationRepository.cs
+++ b/MediaBrowser.Controller/Security/IAuthenticationRepository.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using MediaBrowser.Model.Devices;
diff --git a/MediaBrowser.Controller/Session/AuthenticationRequest.cs b/MediaBrowser.Controller/Session/AuthenticationRequest.cs
index 8c3ac58f2..647c75e66 100644
--- a/MediaBrowser.Controller/Session/AuthenticationRequest.cs
+++ b/MediaBrowser.Controller/Session/AuthenticationRequest.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/MediaBrowser.Controller/Session/ISessionController.cs b/MediaBrowser.Controller/Session/ISessionController.cs
index bc4ccd44c..6bc39d6f4 100644
--- a/MediaBrowser.Controller/Session/ISessionController.cs
+++ b/MediaBrowser.Controller/Session/ISessionController.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/MediaBrowser.Controller/Session/ISessionManager.cs b/MediaBrowser.Controller/Session/ISessionManager.cs
index 6c06dcad5..4c3cf5ffe 100644
--- a/MediaBrowser.Controller/Session/ISessionManager.cs
+++ b/MediaBrowser.Controller/Session/ISessionManager.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
@@ -344,21 +346,19 @@ namespace MediaBrowser.Controller.Session
/// Logouts the specified access token.
/// </summary>
/// <param name="accessToken">The access token.</param>
- /// <returns>Task.</returns>
void Logout(string accessToken);
+
void Logout(AuthenticationInfo accessToken);
/// <summary>
/// Revokes the user tokens.
/// </summary>
- /// <returns>Task.</returns>
void RevokeUserTokens(Guid userId, string currentAccessToken);
/// <summary>
/// Revokes the token.
/// </summary>
/// <param name="id">The identifier.</param>
- /// <returns>Task.</returns>
void RevokeToken(string id);
void CloseIfNeeded(SessionInfo session);
diff --git a/MediaBrowser.Controller/Session/SessionEventArgs.cs b/MediaBrowser.Controller/Session/SessionEventArgs.cs
index 097e32eae..269fe7dc4 100644
--- a/MediaBrowser.Controller/Session/SessionEventArgs.cs
+++ b/MediaBrowser.Controller/Session/SessionEventArgs.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/MediaBrowser.Controller/Session/SessionInfo.cs b/MediaBrowser.Controller/Session/SessionInfo.cs
index d09852870..6134c0cf3 100644
--- a/MediaBrowser.Controller/Session/SessionInfo.cs
+++ b/MediaBrowser.Controller/Session/SessionInfo.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
@@ -52,7 +54,7 @@ namespace MediaBrowser.Controller.Session
public string RemoteEndPoint { get; set; }
/// <summary>
- /// Gets or sets the playable media types.
+ /// Gets the playable media types.
/// </summary>
/// <value>The playable media types.</value>
public IReadOnlyList<string> PlayableMediaTypes
@@ -228,7 +230,7 @@ namespace MediaBrowser.Controller.Session
public string UserPrimaryImageTag { get; set; }
/// <summary>
- /// Gets or sets the supported commands.
+ /// Gets the supported commands.
/// </summary>
/// <value>The supported commands.</value>
public IReadOnlyList<GeneralCommandType> SupportedCommands
diff --git a/MediaBrowser.Controller/Sorting/AlphanumComparator.cs b/MediaBrowser.Controller/Sorting/AlphanumComparator.cs
index 70cb9eebe..4d9b98889 100644
--- a/MediaBrowser.Controller/Sorting/AlphanumComparator.cs
+++ b/MediaBrowser.Controller/Sorting/AlphanumComparator.cs
@@ -1,7 +1,5 @@
#pragma warning disable CS1591
-#nullable enable
-
using System;
using System.Collections.Generic;
diff --git a/MediaBrowser.Controller/Sorting/IUserBaseItemComparer.cs b/MediaBrowser.Controller/Sorting/IUserBaseItemComparer.cs
index 6d03d97ae..bd47db39a 100644
--- a/MediaBrowser.Controller/Sorting/IUserBaseItemComparer.cs
+++ b/MediaBrowser.Controller/Sorting/IUserBaseItemComparer.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using MediaBrowser.Controller.Library;
namespace MediaBrowser.Controller.Sorting
diff --git a/MediaBrowser.Controller/Sorting/SortExtensions.cs b/MediaBrowser.Controller/Sorting/SortExtensions.cs
index 88467814c..aa6ec513f 100644
--- a/MediaBrowser.Controller/Sorting/SortExtensions.cs
+++ b/MediaBrowser.Controller/Sorting/SortExtensions.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/MediaBrowser.Controller/Subtitles/ISubtitleManager.cs b/MediaBrowser.Controller/Subtitles/ISubtitleManager.cs
index 6d63286ef..9e661cbe4 100644
--- a/MediaBrowser.Controller/Subtitles/ISubtitleManager.cs
+++ b/MediaBrowser.Controller/Subtitles/ISubtitleManager.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/MediaBrowser.Controller/Subtitles/ISubtitleProvider.cs b/MediaBrowser.Controller/Subtitles/ISubtitleProvider.cs
index a633262de..326348d58 100644
--- a/MediaBrowser.Controller/Subtitles/ISubtitleProvider.cs
+++ b/MediaBrowser.Controller/Subtitles/ISubtitleProvider.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System.Collections.Generic;
diff --git a/MediaBrowser.Controller/Subtitles/SubtitleDownloadFailureEventArgs.cs b/MediaBrowser.Controller/Subtitles/SubtitleDownloadFailureEventArgs.cs
index ce8141219..c782f5796 100644
--- a/MediaBrowser.Controller/Subtitles/SubtitleDownloadFailureEventArgs.cs
+++ b/MediaBrowser.Controller/Subtitles/SubtitleDownloadFailureEventArgs.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using MediaBrowser.Controller.Entities;
diff --git a/MediaBrowser.Controller/Subtitles/SubtitleResponse.cs b/MediaBrowser.Controller/Subtitles/SubtitleResponse.cs
index a86b05778..85b3e6fbd 100644
--- a/MediaBrowser.Controller/Subtitles/SubtitleResponse.cs
+++ b/MediaBrowser.Controller/Subtitles/SubtitleResponse.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System.IO;
diff --git a/MediaBrowser.Controller/Subtitles/SubtitleSearchRequest.cs b/MediaBrowser.Controller/Subtitles/SubtitleSearchRequest.cs
index 7d3c20e8f..0f7c47e76 100644
--- a/MediaBrowser.Controller/Subtitles/SubtitleSearchRequest.cs
+++ b/MediaBrowser.Controller/Subtitles/SubtitleSearchRequest.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/MediaBrowser.Controller/Sync/IHasDynamicAccess.cs b/MediaBrowser.Controller/Sync/IHasDynamicAccess.cs
index e7395b136..3d3e44da0 100644
--- a/MediaBrowser.Controller/Sync/IHasDynamicAccess.cs
+++ b/MediaBrowser.Controller/Sync/IHasDynamicAccess.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System.Threading;
diff --git a/MediaBrowser.Controller/Sync/IServerSyncProvider.cs b/MediaBrowser.Controller/Sync/IServerSyncProvider.cs
index c97fd7044..3891ac0a6 100644
--- a/MediaBrowser.Controller/Sync/IServerSyncProvider.cs
+++ b/MediaBrowser.Controller/Sync/IServerSyncProvider.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/MediaBrowser.Controller/Sync/ISyncProvider.cs b/MediaBrowser.Controller/Sync/ISyncProvider.cs
index 950cc73e8..ea20014c7 100644
--- a/MediaBrowser.Controller/Sync/ISyncProvider.cs
+++ b/MediaBrowser.Controller/Sync/ISyncProvider.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System.Collections.Generic;
diff --git a/MediaBrowser.Controller/Sync/SyncedFileInfo.cs b/MediaBrowser.Controller/Sync/SyncedFileInfo.cs
index a626738fb..7eac52299 100644
--- a/MediaBrowser.Controller/Sync/SyncedFileInfo.cs
+++ b/MediaBrowser.Controller/Sync/SyncedFileInfo.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System.Collections.Generic;
diff --git a/MediaBrowser.Controller/SyncPlay/GroupMember.cs b/MediaBrowser.Controller/SyncPlay/GroupMember.cs
index 5fb982e85..7e7e759a5 100644
--- a/MediaBrowser.Controller/SyncPlay/GroupMember.cs
+++ b/MediaBrowser.Controller/SyncPlay/GroupMember.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using MediaBrowser.Controller.Session;
namespace MediaBrowser.Controller.SyncPlay
diff --git a/MediaBrowser.Controller/SyncPlay/GroupStates/AbstractGroupState.cs b/MediaBrowser.Controller/SyncPlay/GroupStates/AbstractGroupState.cs
index e3de22db3..91a13fb28 100644
--- a/MediaBrowser.Controller/SyncPlay/GroupStates/AbstractGroupState.cs
+++ b/MediaBrowser.Controller/SyncPlay/GroupStates/AbstractGroupState.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System.Threading;
using MediaBrowser.Controller.Session;
using MediaBrowser.Controller.SyncPlay.PlaybackRequests;
diff --git a/MediaBrowser.Controller/SyncPlay/GroupStates/IdleGroupState.cs b/MediaBrowser.Controller/SyncPlay/GroupStates/IdleGroupState.cs
index 12ce6c8f8..6b5a7cdf9 100644
--- a/MediaBrowser.Controller/SyncPlay/GroupStates/IdleGroupState.cs
+++ b/MediaBrowser.Controller/SyncPlay/GroupStates/IdleGroupState.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System.Threading;
using MediaBrowser.Controller.Session;
using MediaBrowser.Controller.SyncPlay.PlaybackRequests;
diff --git a/MediaBrowser.Controller/SyncPlay/GroupStates/PausedGroupState.cs b/MediaBrowser.Controller/SyncPlay/GroupStates/PausedGroupState.cs
index fba8ba9e2..b9786ddb0 100644
--- a/MediaBrowser.Controller/SyncPlay/GroupStates/PausedGroupState.cs
+++ b/MediaBrowser.Controller/SyncPlay/GroupStates/PausedGroupState.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Threading;
using MediaBrowser.Controller.Session;
diff --git a/MediaBrowser.Controller/SyncPlay/GroupStates/PlayingGroupState.cs b/MediaBrowser.Controller/SyncPlay/GroupStates/PlayingGroupState.cs
index 9797b247c..cb1cadf0b 100644
--- a/MediaBrowser.Controller/SyncPlay/GroupStates/PlayingGroupState.cs
+++ b/MediaBrowser.Controller/SyncPlay/GroupStates/PlayingGroupState.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Threading;
using MediaBrowser.Controller.Session;
diff --git a/MediaBrowser.Controller/SyncPlay/GroupStates/WaitingGroupState.cs b/MediaBrowser.Controller/SyncPlay/GroupStates/WaitingGroupState.cs
index 507573653..a0c38b309 100644
--- a/MediaBrowser.Controller/SyncPlay/GroupStates/WaitingGroupState.cs
+++ b/MediaBrowser.Controller/SyncPlay/GroupStates/WaitingGroupState.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Threading;
using MediaBrowser.Controller.Session;
diff --git a/MediaBrowser.Controller/SyncPlay/IGroupPlaybackRequest.cs b/MediaBrowser.Controller/SyncPlay/IGroupPlaybackRequest.cs
index 201f29952..9045063ee 100644
--- a/MediaBrowser.Controller/SyncPlay/IGroupPlaybackRequest.cs
+++ b/MediaBrowser.Controller/SyncPlay/IGroupPlaybackRequest.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System.Threading;
using MediaBrowser.Controller.Session;
using MediaBrowser.Model.SyncPlay;
diff --git a/MediaBrowser.Controller/SyncPlay/IGroupState.cs b/MediaBrowser.Controller/SyncPlay/IGroupState.cs
index 95ee09985..0666a62a8 100644
--- a/MediaBrowser.Controller/SyncPlay/IGroupState.cs
+++ b/MediaBrowser.Controller/SyncPlay/IGroupState.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System.Threading;
using MediaBrowser.Controller.Session;
using MediaBrowser.Controller.SyncPlay.PlaybackRequests;
diff --git a/MediaBrowser.Controller/SyncPlay/IGroupStateContext.cs b/MediaBrowser.Controller/SyncPlay/IGroupStateContext.cs
index aa263638a..de26c7d9e 100644
--- a/MediaBrowser.Controller/SyncPlay/IGroupStateContext.cs
+++ b/MediaBrowser.Controller/SyncPlay/IGroupStateContext.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections.Generic;
using System.Threading;
diff --git a/MediaBrowser.Controller/SyncPlay/ISyncPlayManager.cs b/MediaBrowser.Controller/SyncPlay/ISyncPlayManager.cs
index 1c954828c..a6999a12c 100644
--- a/MediaBrowser.Controller/SyncPlay/ISyncPlayManager.cs
+++ b/MediaBrowser.Controller/SyncPlay/ISyncPlayManager.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections.Generic;
using System.Threading;
diff --git a/MediaBrowser.Controller/SyncPlay/PlaybackRequests/AbstractPlaybackRequest.cs b/MediaBrowser.Controller/SyncPlay/PlaybackRequests/AbstractPlaybackRequest.cs
index 4090f65b9..ef496c103 100644
--- a/MediaBrowser.Controller/SyncPlay/PlaybackRequests/AbstractPlaybackRequest.cs
+++ b/MediaBrowser.Controller/SyncPlay/PlaybackRequests/AbstractPlaybackRequest.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System.Threading;
using MediaBrowser.Controller.Session;
using MediaBrowser.Model.SyncPlay;
diff --git a/MediaBrowser.Controller/SyncPlay/PlaybackRequests/BufferGroupRequest.cs b/MediaBrowser.Controller/SyncPlay/PlaybackRequests/BufferGroupRequest.cs
index 11cc99fcd..d188114c3 100644
--- a/MediaBrowser.Controller/SyncPlay/PlaybackRequests/BufferGroupRequest.cs
+++ b/MediaBrowser.Controller/SyncPlay/PlaybackRequests/BufferGroupRequest.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Threading;
using MediaBrowser.Controller.Session;
diff --git a/MediaBrowser.Controller/SyncPlay/PlaybackRequests/IgnoreWaitGroupRequest.cs b/MediaBrowser.Controller/SyncPlay/PlaybackRequests/IgnoreWaitGroupRequest.cs
index 64ef791ed..464c81dfd 100644
--- a/MediaBrowser.Controller/SyncPlay/PlaybackRequests/IgnoreWaitGroupRequest.cs
+++ b/MediaBrowser.Controller/SyncPlay/PlaybackRequests/IgnoreWaitGroupRequest.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System.Threading;
using MediaBrowser.Controller.Session;
using MediaBrowser.Model.SyncPlay;
diff --git a/MediaBrowser.Controller/SyncPlay/PlaybackRequests/MovePlaylistItemGroupRequest.cs b/MediaBrowser.Controller/SyncPlay/PlaybackRequests/MovePlaylistItemGroupRequest.cs
index 9cd8da566..be314e807 100644
--- a/MediaBrowser.Controller/SyncPlay/PlaybackRequests/MovePlaylistItemGroupRequest.cs
+++ b/MediaBrowser.Controller/SyncPlay/PlaybackRequests/MovePlaylistItemGroupRequest.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Threading;
using MediaBrowser.Controller.Session;
diff --git a/MediaBrowser.Controller/SyncPlay/PlaybackRequests/NextItemGroupRequest.cs b/MediaBrowser.Controller/SyncPlay/PlaybackRequests/NextItemGroupRequest.cs
index e0ae0deb7..679076239 100644
--- a/MediaBrowser.Controller/SyncPlay/PlaybackRequests/NextItemGroupRequest.cs
+++ b/MediaBrowser.Controller/SyncPlay/PlaybackRequests/NextItemGroupRequest.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Threading;
using MediaBrowser.Controller.Session;
diff --git a/MediaBrowser.Controller/SyncPlay/PlaybackRequests/PauseGroupRequest.cs b/MediaBrowser.Controller/SyncPlay/PlaybackRequests/PauseGroupRequest.cs
index 2869b35f7..7ee18a366 100644
--- a/MediaBrowser.Controller/SyncPlay/PlaybackRequests/PauseGroupRequest.cs
+++ b/MediaBrowser.Controller/SyncPlay/PlaybackRequests/PauseGroupRequest.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System.Threading;
using MediaBrowser.Controller.Session;
using MediaBrowser.Model.SyncPlay;
diff --git a/MediaBrowser.Controller/SyncPlay/PlaybackRequests/PingGroupRequest.cs b/MediaBrowser.Controller/SyncPlay/PlaybackRequests/PingGroupRequest.cs
index 8ef3b2030..beab655c5 100644
--- a/MediaBrowser.Controller/SyncPlay/PlaybackRequests/PingGroupRequest.cs
+++ b/MediaBrowser.Controller/SyncPlay/PlaybackRequests/PingGroupRequest.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System.Threading;
using MediaBrowser.Controller.Session;
using MediaBrowser.Model.SyncPlay;
diff --git a/MediaBrowser.Controller/SyncPlay/PlaybackRequests/PlayGroupRequest.cs b/MediaBrowser.Controller/SyncPlay/PlaybackRequests/PlayGroupRequest.cs
index 16f9b4087..05ff262c1 100644
--- a/MediaBrowser.Controller/SyncPlay/PlaybackRequests/PlayGroupRequest.cs
+++ b/MediaBrowser.Controller/SyncPlay/PlaybackRequests/PlayGroupRequest.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections.Generic;
using System.Threading;
diff --git a/MediaBrowser.Controller/SyncPlay/PlaybackRequests/PreviousItemGroupRequest.cs b/MediaBrowser.Controller/SyncPlay/PlaybackRequests/PreviousItemGroupRequest.cs
index 166ee0800..3e34b6ce4 100644
--- a/MediaBrowser.Controller/SyncPlay/PlaybackRequests/PreviousItemGroupRequest.cs
+++ b/MediaBrowser.Controller/SyncPlay/PlaybackRequests/PreviousItemGroupRequest.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Threading;
using MediaBrowser.Controller.Session;
diff --git a/MediaBrowser.Controller/SyncPlay/PlaybackRequests/QueueGroupRequest.cs b/MediaBrowser.Controller/SyncPlay/PlaybackRequests/QueueGroupRequest.cs
index d4af63b6d..0f91476de 100644
--- a/MediaBrowser.Controller/SyncPlay/PlaybackRequests/QueueGroupRequest.cs
+++ b/MediaBrowser.Controller/SyncPlay/PlaybackRequests/QueueGroupRequest.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections.Generic;
using System.Threading;
diff --git a/MediaBrowser.Controller/SyncPlay/PlaybackRequests/ReadyGroupRequest.cs b/MediaBrowser.Controller/SyncPlay/PlaybackRequests/ReadyGroupRequest.cs
index 74f01cbea..b1f0bd360 100644
--- a/MediaBrowser.Controller/SyncPlay/PlaybackRequests/ReadyGroupRequest.cs
+++ b/MediaBrowser.Controller/SyncPlay/PlaybackRequests/ReadyGroupRequest.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Threading;
using MediaBrowser.Controller.Session;
diff --git a/MediaBrowser.Controller/SyncPlay/PlaybackRequests/RemoveFromPlaylistGroupRequest.cs b/MediaBrowser.Controller/SyncPlay/PlaybackRequests/RemoveFromPlaylistGroupRequest.cs
index 47c06c222..689145293 100644
--- a/MediaBrowser.Controller/SyncPlay/PlaybackRequests/RemoveFromPlaylistGroupRequest.cs
+++ b/MediaBrowser.Controller/SyncPlay/PlaybackRequests/RemoveFromPlaylistGroupRequest.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections.Generic;
using System.Threading;
diff --git a/MediaBrowser.Controller/SyncPlay/PlaybackRequests/SeekGroupRequest.cs b/MediaBrowser.Controller/SyncPlay/PlaybackRequests/SeekGroupRequest.cs
index ecaa689ae..196113374 100644
--- a/MediaBrowser.Controller/SyncPlay/PlaybackRequests/SeekGroupRequest.cs
+++ b/MediaBrowser.Controller/SyncPlay/PlaybackRequests/SeekGroupRequest.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System.Threading;
using MediaBrowser.Controller.Session;
using MediaBrowser.Model.SyncPlay;
diff --git a/MediaBrowser.Controller/SyncPlay/PlaybackRequests/SetPlaylistItemGroupRequest.cs b/MediaBrowser.Controller/SyncPlay/PlaybackRequests/SetPlaylistItemGroupRequest.cs
index c3451703e..44df127a6 100644
--- a/MediaBrowser.Controller/SyncPlay/PlaybackRequests/SetPlaylistItemGroupRequest.cs
+++ b/MediaBrowser.Controller/SyncPlay/PlaybackRequests/SetPlaylistItemGroupRequest.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Threading;
using MediaBrowser.Controller.Session;
diff --git a/MediaBrowser.Controller/SyncPlay/PlaybackRequests/SetRepeatModeGroupRequest.cs b/MediaBrowser.Controller/SyncPlay/PlaybackRequests/SetRepeatModeGroupRequest.cs
index 51011672e..d250eab56 100644
--- a/MediaBrowser.Controller/SyncPlay/PlaybackRequests/SetRepeatModeGroupRequest.cs
+++ b/MediaBrowser.Controller/SyncPlay/PlaybackRequests/SetRepeatModeGroupRequest.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System.Threading;
using MediaBrowser.Controller.Session;
using MediaBrowser.Model.SyncPlay;
diff --git a/MediaBrowser.Controller/SyncPlay/PlaybackRequests/SetShuffleModeGroupRequest.cs b/MediaBrowser.Controller/SyncPlay/PlaybackRequests/SetShuffleModeGroupRequest.cs
index d7b2504b4..5034e992e 100644
--- a/MediaBrowser.Controller/SyncPlay/PlaybackRequests/SetShuffleModeGroupRequest.cs
+++ b/MediaBrowser.Controller/SyncPlay/PlaybackRequests/SetShuffleModeGroupRequest.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System.Threading;
using MediaBrowser.Controller.Session;
using MediaBrowser.Model.SyncPlay;
diff --git a/MediaBrowser.Controller/SyncPlay/Queue/PlayQueueManager.cs b/MediaBrowser.Controller/SyncPlay/Queue/PlayQueueManager.cs
index fdec29417..b8ae9f3ff 100644
--- a/MediaBrowser.Controller/SyncPlay/Queue/PlayQueueManager.cs
+++ b/MediaBrowser.Controller/SyncPlay/Queue/PlayQueueManager.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections.Generic;
using System.Linq;
diff --git a/MediaBrowser.LocalMetadata/BaseXmlProvider.cs b/MediaBrowser.LocalMetadata/BaseXmlProvider.cs
index b036a2cc8..9f8e921b4 100644
--- a/MediaBrowser.LocalMetadata/BaseXmlProvider.cs
+++ b/MediaBrowser.LocalMetadata/BaseXmlProvider.cs
@@ -91,7 +91,7 @@ namespace MediaBrowser.LocalMetadata
/// <param name="info">Item inf.</param>
/// <param name="directoryService">Instance of the <see cref="IDirectoryService"/> interface.</param>
/// <returns>The file system metadata.</returns>
- protected abstract FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService);
+ protected abstract FileSystemMetadata? GetXmlFile(ItemInfo info, IDirectoryService directoryService);
/// <inheritdoc />
public bool HasChanged(BaseItem item, IDirectoryService directoryService)
diff --git a/MediaBrowser.LocalMetadata/Images/EpisodeLocalImageProvider.cs b/MediaBrowser.LocalMetadata/Images/EpisodeLocalImageProvider.cs
index 2d3b2d889..bc62ca4d5 100644
--- a/MediaBrowser.LocalMetadata/Images/EpisodeLocalImageProvider.cs
+++ b/MediaBrowser.LocalMetadata/Images/EpisodeLocalImageProvider.cs
@@ -42,6 +42,10 @@ namespace MediaBrowser.LocalMetadata.Images
public IEnumerable<LocalImageInfo> GetImages(BaseItem item, IDirectoryService directoryService)
{
var parentPath = Path.GetDirectoryName(item.Path);
+ if (parentPath == null)
+ {
+ return Enumerable.Empty<LocalImageInfo>();
+ }
var parentPathFiles = directoryService.GetFiles(parentPath);
diff --git a/MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs b/MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs
index 5f620634f..32e5ac761 100644
--- a/MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs
+++ b/MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs
@@ -468,8 +468,7 @@ namespace MediaBrowser.LocalMetadata.Parsers
{
var val = reader.ReadElementContentAsString();
- var hasDisplayOrder = item as IHasDisplayOrder;
- if (hasDisplayOrder != null)
+ if (item is IHasDisplayOrder hasDisplayOrder)
{
if (!string.IsNullOrWhiteSpace(val))
{
diff --git a/MediaBrowser.LocalMetadata/Providers/BoxSetXmlProvider.cs b/MediaBrowser.LocalMetadata/Providers/BoxSetXmlProvider.cs
index cc705a9df..ea123bbf2 100644
--- a/MediaBrowser.LocalMetadata/Providers/BoxSetXmlProvider.cs
+++ b/MediaBrowser.LocalMetadata/Providers/BoxSetXmlProvider.cs
@@ -36,7 +36,7 @@ namespace MediaBrowser.LocalMetadata.Providers
}
/// <inheritdoc />
- protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService)
+ protected override FileSystemMetadata? GetXmlFile(ItemInfo info, IDirectoryService directoryService)
{
return directoryService.GetFile(Path.Combine(info.Path, "collection.xml"));
}
diff --git a/MediaBrowser.LocalMetadata/Providers/PlaylistXmlProvider.cs b/MediaBrowser.LocalMetadata/Providers/PlaylistXmlProvider.cs
index 36f3048ad..899035652 100644
--- a/MediaBrowser.LocalMetadata/Providers/PlaylistXmlProvider.cs
+++ b/MediaBrowser.LocalMetadata/Providers/PlaylistXmlProvider.cs
@@ -39,7 +39,7 @@ namespace MediaBrowser.LocalMetadata.Providers
}
/// <inheritdoc />
- protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService)
+ protected override FileSystemMetadata? GetXmlFile(ItemInfo info, IDirectoryService directoryService)
{
return directoryService.GetFile(PlaylistXmlSaver.GetSavePath(info.Path));
}
diff --git a/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs b/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs
index dfbce5f49..98ed3dcf7 100644
--- a/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs
+++ b/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs
@@ -296,8 +296,7 @@ namespace MediaBrowser.LocalMetadata.Savers
writer.WriteEndElement();
}
- var hasDisplayOrder = item as IHasDisplayOrder;
- if (hasDisplayOrder != null && !string.IsNullOrEmpty(hasDisplayOrder.DisplayOrder))
+ if (item is IHasDisplayOrder hasDisplayOrder && !string.IsNullOrEmpty(hasDisplayOrder.DisplayOrder))
{
writer.WriteElementString("DisplayOrder", hasDisplayOrder.DisplayOrder);
}
@@ -312,8 +311,7 @@ namespace MediaBrowser.LocalMetadata.Savers
writer.WriteElementString("ProductionYear", item.ProductionYear.Value.ToString(_usCulture));
}
- var hasAspectRatio = item as IHasAspectRatio;
- if (hasAspectRatio != null)
+ if (item is IHasAspectRatio hasAspectRatio)
{
if (!string.IsNullOrEmpty(hasAspectRatio.AspectRatio))
{
diff --git a/MediaBrowser.MediaEncoding/BdInfo/BdInfoExaminer.cs b/MediaBrowser.MediaEncoding/BdInfo/BdInfoExaminer.cs
index 9108d9649..6ebaa4fff 100644
--- a/MediaBrowser.MediaEncoding/BdInfo/BdInfoExaminer.cs
+++ b/MediaBrowser.MediaEncoding/BdInfo/BdInfoExaminer.cs
@@ -61,33 +61,25 @@ namespace MediaBrowser.MediaEncoding.BdInfo
foreach (var stream in playlist.SortedStreams)
{
- var videoStream = stream as TSVideoStream;
-
- if (videoStream != null)
+ if (stream is TSVideoStream videoStream)
{
AddVideoStream(mediaStreams, videoStream);
continue;
}
- var audioStream = stream as TSAudioStream;
-
- if (audioStream != null)
+ if (stream is TSAudioStream audioStream)
{
AddAudioStream(mediaStreams, audioStream);
continue;
}
- var textStream = stream as TSTextStream;
-
- if (textStream != null)
+ if (stream is TSTextStream textStream)
{
AddSubtitleStream(mediaStreams, textStream);
continue;
}
- var graphicsStream = stream as TSGraphicsStream;
-
- if (graphicsStream != null)
+ if (stream is TSGraphicsStream graphicsStream)
{
AddSubtitleStream(mediaStreams, graphicsStream);
}
diff --git a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs
index a87104cd6..884ec0a29 100644
--- a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs
+++ b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs
@@ -29,7 +29,7 @@ namespace MediaBrowser.MediaEncoding.Probing
private readonly ILogger _logger;
private readonly ILocalizationManager _localization;
- private List<string> _splitWhiteList = null;
+ private string[] _splitWhiteList;
public ProbeResultNormalizer(ILogger logger, ILocalizationManager localization)
{
@@ -37,6 +37,8 @@ namespace MediaBrowser.MediaEncoding.Probing
_localization = localization;
}
+ private IReadOnlyList<string> SplitWhitelist => _splitWhiteList ??= new string[] { "AC/DC" };
+
public MediaInfo GetMediaInfo(InternalMediaInfoResult data, VideoType? videoType, bool isAudio, string path, MediaProtocol protocol)
{
var info = new MediaInfo
@@ -57,7 +59,7 @@ namespace MediaBrowser.MediaEncoding.Probing
.Where(i => i.Type != MediaStreamType.Subtitle || !string.IsNullOrWhiteSpace(i.Codec))
.ToList();
- info.MediaAttachments = internalStreams.Select(s => GetMediaAttachment(s))
+ info.MediaAttachments = internalStreams.Select(GetMediaAttachment)
.Where(i => i != null)
.ToList();
@@ -1187,43 +1189,28 @@ namespace MediaBrowser.MediaEncoding.Probing
FetchStudios(audio, tags, "label");
// These support mulitple values, but for now we only store the first.
- var mb = GetMultipleMusicBrainzId(FFProbeHelpers.GetDictionaryValue(tags, "MusicBrainz Album Artist Id"));
- if (mb == null)
- {
- mb = GetMultipleMusicBrainzId(FFProbeHelpers.GetDictionaryValue(tags, "MUSICBRAINZ_ALBUMARTISTID"));
- }
+ var mb = GetMultipleMusicBrainzId(FFProbeHelpers.GetDictionaryValue(tags, "MusicBrainz Album Artist Id"))
+ ?? GetMultipleMusicBrainzId(FFProbeHelpers.GetDictionaryValue(tags, "MUSICBRAINZ_ALBUMARTISTID"));
audio.SetProviderId(MetadataProvider.MusicBrainzAlbumArtist, mb);
- mb = GetMultipleMusicBrainzId(FFProbeHelpers.GetDictionaryValue(tags, "MusicBrainz Artist Id"));
- if (mb == null)
- {
- mb = GetMultipleMusicBrainzId(FFProbeHelpers.GetDictionaryValue(tags, "MUSICBRAINZ_ARTISTID"));
- }
+ mb = GetMultipleMusicBrainzId(FFProbeHelpers.GetDictionaryValue(tags, "MusicBrainz Artist Id"))
+ ?? GetMultipleMusicBrainzId(FFProbeHelpers.GetDictionaryValue(tags, "MUSICBRAINZ_ARTISTID"));
audio.SetProviderId(MetadataProvider.MusicBrainzArtist, mb);
- mb = GetMultipleMusicBrainzId(FFProbeHelpers.GetDictionaryValue(tags, "MusicBrainz Album Id"));
- if (mb == null)
- {
- mb = GetMultipleMusicBrainzId(FFProbeHelpers.GetDictionaryValue(tags, "MUSICBRAINZ_ALBUMID"));
- }
+ mb = GetMultipleMusicBrainzId(FFProbeHelpers.GetDictionaryValue(tags, "MusicBrainz Album Id"))
+ ?? GetMultipleMusicBrainzId(FFProbeHelpers.GetDictionaryValue(tags, "MUSICBRAINZ_ALBUMID"));
audio.SetProviderId(MetadataProvider.MusicBrainzAlbum, mb);
- mb = GetMultipleMusicBrainzId(FFProbeHelpers.GetDictionaryValue(tags, "MusicBrainz Release Group Id"));
- if (mb == null)
- {
- mb = GetMultipleMusicBrainzId(FFProbeHelpers.GetDictionaryValue(tags, "MUSICBRAINZ_RELEASEGROUPID"));
- }
+ mb = GetMultipleMusicBrainzId(FFProbeHelpers.GetDictionaryValue(tags, "MusicBrainz Release Group Id"))
+ ?? GetMultipleMusicBrainzId(FFProbeHelpers.GetDictionaryValue(tags, "MUSICBRAINZ_RELEASEGROUPID"));
audio.SetProviderId(MetadataProvider.MusicBrainzReleaseGroup, mb);
- mb = GetMultipleMusicBrainzId(FFProbeHelpers.GetDictionaryValue(tags, "MusicBrainz Release Track Id"));
- if (mb == null)
- {
- mb = GetMultipleMusicBrainzId(FFProbeHelpers.GetDictionaryValue(tags, "MUSICBRAINZ_RELEASETRACKID"));
- }
+ mb = GetMultipleMusicBrainzId(FFProbeHelpers.GetDictionaryValue(tags, "MusicBrainz Release Track Id"))
+ ?? GetMultipleMusicBrainzId(FFProbeHelpers.GetDictionaryValue(tags, "MUSICBRAINZ_RELEASETRACKID"));
audio.SetProviderId(MetadataProvider.MusicBrainzTrack, mb);
}
@@ -1269,7 +1256,7 @@ namespace MediaBrowser.MediaEncoding.Probing
var artistsFound = new List<string>();
- foreach (var whitelistArtist in GetSplitWhitelist())
+ foreach (var whitelistArtist in SplitWhitelist)
{
var originalVal = val;
val = val.Replace(whitelistArtist, "|", StringComparison.OrdinalIgnoreCase);
@@ -1288,19 +1275,6 @@ namespace MediaBrowser.MediaEncoding.Probing
return artistsFound;
}
- private IEnumerable<string> GetSplitWhitelist()
- {
- if (_splitWhiteList == null)
- {
- _splitWhiteList = new List<string>
- {
- "AC/DC"
- };
- }
-
- return _splitWhiteList;
- }
-
/// <summary>
/// Gets the studios from the tags collection.
/// </summary>
diff --git a/MediaBrowser.Model/Dlna/ContainerProfile.cs b/MediaBrowser.Model/Dlna/ContainerProfile.cs
index d83c8f2f3..740966088 100644
--- a/MediaBrowser.Model/Dlna/ContainerProfile.cs
+++ b/MediaBrowser.Model/Dlna/ContainerProfile.cs
@@ -1,4 +1,3 @@
-#nullable disable
#pragma warning disable CS1591
using System;
@@ -9,25 +8,15 @@ namespace MediaBrowser.Model.Dlna
{
public class ContainerProfile
{
- public ContainerProfile()
- {
- Conditions = Array.Empty<ProfileCondition>();
- }
-
[XmlAttribute("type")]
public DlnaProfileType Type { get; set; }
- public ProfileCondition[] Conditions { get; set; }
+ public ProfileCondition[]? Conditions { get; set; } = Array.Empty<ProfileCondition>();
[XmlAttribute("container")]
- public string Container { get; set; }
-
- public string[] GetContainers()
- {
- return SplitValue(Container);
- }
+ public string Container { get; set; } = string.Empty;
- public static string[] SplitValue(string value)
+ public static string[] SplitValue(string? value)
{
if (string.IsNullOrEmpty(value))
{
@@ -37,14 +26,14 @@ namespace MediaBrowser.Model.Dlna
return value.Split(',', StringSplitOptions.RemoveEmptyEntries);
}
- public bool ContainsContainer(string container)
+ public bool ContainsContainer(string? container)
{
- var containers = GetContainers();
+ var containers = SplitValue(Container);
return ContainsContainer(containers, container);
}
- public static bool ContainsContainer(string profileContainers, string inputContainer)
+ public static bool ContainsContainer(string? profileContainers, string? inputContainer)
{
var isNegativeList = false;
if (profileContainers != null && profileContainers.StartsWith('-'))
@@ -56,46 +45,30 @@ namespace MediaBrowser.Model.Dlna
return ContainsContainer(SplitValue(profileContainers), isNegativeList, inputContainer);
}
- public static bool ContainsContainer(string[] profileContainers, string inputContainer)
+ public static bool ContainsContainer(string[]? profileContainers, string? inputContainer)
{
return ContainsContainer(profileContainers, false, inputContainer);
}
- public static bool ContainsContainer(string[] profileContainers, bool isNegativeList, string inputContainer)
+ public static bool ContainsContainer(string[]? profileContainers, bool isNegativeList, string? inputContainer)
{
- if (profileContainers.Length == 0)
+ if (profileContainers == null || profileContainers.Length == 0)
{
+ // Empty profiles always support all containers/codecs
return true;
}
- if (isNegativeList)
- {
- var allInputContainers = SplitValue(inputContainer);
+ var allInputContainers = SplitValue(inputContainer);
- foreach (var container in allInputContainers)
- {
- if (profileContainers.Contains(container, StringComparer.OrdinalIgnoreCase))
- {
- return false;
- }
- }
-
- return true;
- }
- else
+ foreach (var container in allInputContainers)
{
- var allInputContainers = SplitValue(inputContainer);
-
- foreach (var container in allInputContainers)
+ if (profileContainers.Contains(container, StringComparer.OrdinalIgnoreCase))
{
- if (profileContainers.Contains(container, StringComparer.OrdinalIgnoreCase))
- {
- return true;
- }
+ return !isNegativeList;
}
-
- return false;
}
+
+ return isNegativeList;
}
}
}
diff --git a/MediaBrowser.Model/Dlna/DeviceProfile.cs b/MediaBrowser.Model/Dlna/DeviceProfile.cs
index ff5186658..feb3d880e 100644
--- a/MediaBrowser.Model/Dlna/DeviceProfile.cs
+++ b/MediaBrowser.Model/Dlna/DeviceProfile.cs
@@ -1,6 +1,6 @@
-#nullable disable
#pragma warning disable CA1819 // Properties should not return arrays
using System;
+using System.ComponentModel;
using System.Linq;
using System.Xml.Serialization;
using MediaBrowser.Model.MediaInfo;
@@ -8,226 +8,219 @@ using MediaBrowser.Model.MediaInfo;
namespace MediaBrowser.Model.Dlna
{
/// <summary>
- /// Defines the <see cref="DeviceProfile" />.
+ /// A <see cref="DeviceProfile" /> represents a set of metadata which determines which content a certain device is able to play.
+ /// <br/>
+ /// Specifically, it defines the supported <see cref="ContainerProfiles">containers</see> and
+ /// <see cref="CodecProfiles">codecs</see> (video and/or audio, including codec profiles and levels)
+ /// the device is able to direct play (without transcoding or remuxing),
+ /// as well as which <see cref="TranscodingProfiles">containers/codecs to transcode to</see> in case it isn't.
/// </summary>
[XmlRoot("Profile")]
public class DeviceProfile
{
/// <summary>
- /// Initializes a new instance of the <see cref="DeviceProfile"/> class.
+ /// Gets or sets the name of this device profile.
/// </summary>
- public DeviceProfile()
- {
- DirectPlayProfiles = Array.Empty<DirectPlayProfile>();
- TranscodingProfiles = Array.Empty<TranscodingProfile>();
- ResponseProfiles = Array.Empty<ResponseProfile>();
- CodecProfiles = Array.Empty<CodecProfile>();
- ContainerProfiles = Array.Empty<ContainerProfile>();
- SubtitleProfiles = Array.Empty<SubtitleProfile>();
-
- XmlRootAttributes = Array.Empty<XmlAttribute>();
-
- SupportedMediaTypes = "Audio,Photo,Video";
- MaxStreamingBitrate = 8000000;
- MaxStaticBitrate = 8000000;
- MusicStreamingTranscodingBitrate = 128000;
- }
-
- /// <summary>
- /// Gets or sets the Name.
- /// </summary>
- public string Name { get; set; }
+ public string? Name { get; set; }
/// <summary>
/// Gets or sets the Id.
/// </summary>
[XmlIgnore]
- public string Id { get; set; }
+ public string? Id { get; set; }
/// <summary>
/// Gets or sets the Identification.
/// </summary>
- public DeviceIdentification Identification { get; set; }
+ public DeviceIdentification? Identification { get; set; }
/// <summary>
- /// Gets or sets the FriendlyName.
+ /// Gets or sets the friendly name of the device profile, which can be shown to users.
/// </summary>
- public string FriendlyName { get; set; }
+ public string? FriendlyName { get; set; }
/// <summary>
- /// Gets or sets the Manufacturer.
+ /// Gets or sets the manufacturer of the device which this profile represents.
/// </summary>
- public string Manufacturer { get; set; }
+ public string? Manufacturer { get; set; }
/// <summary>
- /// Gets or sets the ManufacturerUrl.
+ /// Gets or sets an url for the manufacturer of the device which this profile represents.
/// </summary>
- public string ManufacturerUrl { get; set; }
+ public string? ManufacturerUrl { get; set; }
/// <summary>
- /// Gets or sets the ModelName.
+ /// Gets or sets the model name of the device which this profile represents.
/// </summary>
- public string ModelName { get; set; }
+ public string? ModelName { get; set; }
/// <summary>
- /// Gets or sets the ModelDescription.
+ /// Gets or sets the model description of the device which this profile represents.
/// </summary>
- public string ModelDescription { get; set; }
+ public string? ModelDescription { get; set; }
/// <summary>
- /// Gets or sets the ModelNumber.
+ /// Gets or sets the model number of the device which this profile represents.
/// </summary>
- public string ModelNumber { get; set; }
+ public string? ModelNumber { get; set; }
/// <summary>
/// Gets or sets the ModelUrl.
/// </summary>
- public string ModelUrl { get; set; }
+ public string? ModelUrl { get; set; }
/// <summary>
- /// Gets or sets the SerialNumber.
+ /// Gets or sets the serial number of the device which this profile represents.
/// </summary>
- public string SerialNumber { get; set; }
+ public string? SerialNumber { get; set; }
/// <summary>
/// Gets or sets a value indicating whether EnableAlbumArtInDidl.
/// </summary>
+ [DefaultValue(false)]
public bool EnableAlbumArtInDidl { get; set; }
/// <summary>
/// Gets or sets a value indicating whether EnableSingleAlbumArtLimit.
/// </summary>
+ [DefaultValue(false)]
public bool EnableSingleAlbumArtLimit { get; set; }
/// <summary>
/// Gets or sets a value indicating whether EnableSingleSubtitleLimit.
/// </summary>
+ [DefaultValue(false)]
public bool EnableSingleSubtitleLimit { get; set; }
/// <summary>
/// Gets or sets the SupportedMediaTypes.
/// </summary>
- public string SupportedMediaTypes { get; set; }
+ public string SupportedMediaTypes { get; set; } = "Audio,Photo,Video";
/// <summary>
/// Gets or sets the UserId.
/// </summary>
- public string UserId { get; set; }
+ public string? UserId { get; set; }
/// <summary>
/// Gets or sets the AlbumArtPn.
/// </summary>
- public string AlbumArtPn { get; set; }
+ public string? AlbumArtPn { get; set; }
/// <summary>
/// Gets or sets the MaxAlbumArtWidth.
/// </summary>
- public int MaxAlbumArtWidth { get; set; }
+ public int? MaxAlbumArtWidth { get; set; }
/// <summary>
/// Gets or sets the MaxAlbumArtHeight.
/// </summary>
- public int MaxAlbumArtHeight { get; set; }
+ public int? MaxAlbumArtHeight { get; set; }
/// <summary>
- /// Gets or sets the MaxIconWidth.
+ /// Gets or sets the maximum allowed width of embedded icons.
/// </summary>
public int? MaxIconWidth { get; set; }
/// <summary>
- /// Gets or sets the MaxIconHeight.
+ /// Gets or sets the maximum allowed height of embedded icons.
/// </summary>
public int? MaxIconHeight { get; set; }
/// <summary>
- /// Gets or sets the MaxStreamingBitrate.
+ /// Gets or sets the maximum allowed bitrate for all streamed content.
/// </summary>
- public int? MaxStreamingBitrate { get; set; }
+ public int? MaxStreamingBitrate { get; set; } = 8000000;
/// <summary>
- /// Gets or sets the MaxStaticBitrate.
+ /// Gets or sets the maximum allowed bitrate for statically streamed content (= direct played files).
/// </summary>
- public int? MaxStaticBitrate { get; set; }
+ public int? MaxStaticBitrate { get; set; } = 8000000;
/// <summary>
- /// Gets or sets the MusicStreamingTranscodingBitrate.
+ /// Gets or sets the maximum allowed bitrate for transcoded music streams.
/// </summary>
- public int? MusicStreamingTranscodingBitrate { get; set; }
+ public int? MusicStreamingTranscodingBitrate { get; set; } = 128000;
/// <summary>
- /// Gets or sets the MaxStaticMusicBitrate.
+ /// Gets or sets the maximum allowed bitrate for statically streamed (= direct played) music files.
/// </summary>
- public int? MaxStaticMusicBitrate { get; set; }
+ public int? MaxStaticMusicBitrate { get; set; } = 8000000;
/// <summary>
/// Gets or sets the content of the aggregationFlags element in the urn:schemas-sonycom:av namespace.
/// </summary>
- public string SonyAggregationFlags { get; set; }
+ public string? SonyAggregationFlags { get; set; }
/// <summary>
/// Gets or sets the ProtocolInfo.
/// </summary>
- public string ProtocolInfo { get; set; }
+ public string? ProtocolInfo { get; set; }
/// <summary>
/// Gets or sets the TimelineOffsetSeconds.
/// </summary>
+ [DefaultValue(0)]
public int TimelineOffsetSeconds { get; set; }
/// <summary>
/// Gets or sets a value indicating whether RequiresPlainVideoItems.
/// </summary>
+ [DefaultValue(false)]
public bool RequiresPlainVideoItems { get; set; }
/// <summary>
/// Gets or sets a value indicating whether RequiresPlainFolders.
/// </summary>
+ [DefaultValue(false)]
public bool RequiresPlainFolders { get; set; }
/// <summary>
/// Gets or sets a value indicating whether EnableMSMediaReceiverRegistrar.
/// </summary>
+ [DefaultValue(false)]
public bool EnableMSMediaReceiverRegistrar { get; set; }
/// <summary>
/// Gets or sets a value indicating whether IgnoreTranscodeByteRangeRequests.
/// </summary>
+ [DefaultValue(false)]
public bool IgnoreTranscodeByteRangeRequests { get; set; }
/// <summary>
/// Gets or sets the XmlRootAttributes.
/// </summary>
- public XmlAttribute[] XmlRootAttributes { get; set; }
+ public XmlAttribute[] XmlRootAttributes { get; set; } = Array.Empty<XmlAttribute>();
/// <summary>
/// Gets or sets the direct play profiles.
/// </summary>
- public DirectPlayProfile[] DirectPlayProfiles { get; set; }
+ public DirectPlayProfile[] DirectPlayProfiles { get; set; } = Array.Empty<DirectPlayProfile>();
/// <summary>
/// Gets or sets the transcoding profiles.
/// </summary>
- public TranscodingProfile[] TranscodingProfiles { get; set; }
+ public TranscodingProfile[] TranscodingProfiles { get; set; } = Array.Empty<TranscodingProfile>();
/// <summary>
- /// Gets or sets the ContainerProfiles.
+ /// Gets or sets the container profiles.
/// </summary>
- public ContainerProfile[] ContainerProfiles { get; set; }
+ public ContainerProfile[] ContainerProfiles { get; set; } = Array.Empty<ContainerProfile>();
/// <summary>
- /// Gets or sets the CodecProfiles.
+ /// Gets or sets the codec profiles.
/// </summary>
- public CodecProfile[] CodecProfiles { get; set; }
+ public CodecProfile[] CodecProfiles { get; set; } = Array.Empty<CodecProfile>();
/// <summary>
/// Gets or sets the ResponseProfiles.
/// </summary>
- public ResponseProfile[] ResponseProfiles { get; set; }
+ public ResponseProfile[] ResponseProfiles { get; set; } = Array.Empty<ResponseProfile>();
/// <summary>
- /// Gets or sets the SubtitleProfiles.
+ /// Gets or sets the subtitle profiles.
/// </summary>
- public SubtitleProfile[] SubtitleProfiles { get; set; }
+ public SubtitleProfile[] SubtitleProfiles { get; set; } = Array.Empty<SubtitleProfile>();
/// <summary>
/// The GetSupportedMediaTypes.
@@ -244,13 +237,13 @@ namespace MediaBrowser.Model.Dlna
/// <param name="container">The container.</param>
/// <param name="audioCodec">The audio Codec.</param>
/// <returns>A <see cref="TranscodingProfile"/>.</returns>
- public TranscodingProfile GetAudioTranscodingProfile(string container, string audioCodec)
+ public TranscodingProfile? GetAudioTranscodingProfile(string? container, string? audioCodec)
{
container = (container ?? string.Empty).TrimStart('.');
foreach (var i in TranscodingProfiles)
{
- if (i.Type != MediaBrowser.Model.Dlna.DlnaProfileType.Audio)
+ if (i.Type != DlnaProfileType.Audio)
{
continue;
}
@@ -278,13 +271,13 @@ namespace MediaBrowser.Model.Dlna
/// <param name="audioCodec">The audio Codec.</param>
/// <param name="videoCodec">The video Codec.</param>
/// <returns>The <see cref="TranscodingProfile"/>.</returns>
- public TranscodingProfile GetVideoTranscodingProfile(string container, string audioCodec, string videoCodec)
+ public TranscodingProfile? GetVideoTranscodingProfile(string? container, string? audioCodec, string? videoCodec)
{
container = (container ?? string.Empty).TrimStart('.');
foreach (var i in TranscodingProfiles)
{
- if (i.Type != MediaBrowser.Model.Dlna.DlnaProfileType.Video)
+ if (i.Type != DlnaProfileType.Video)
{
continue;
}
@@ -299,7 +292,7 @@ namespace MediaBrowser.Model.Dlna
continue;
}
- if (!string.Equals(videoCodec, i.VideoCodec ?? string.Empty, StringComparison.OrdinalIgnoreCase))
+ if (!string.Equals(videoCodec, i.VideoCodec, StringComparison.OrdinalIgnoreCase))
{
continue;
}
@@ -320,7 +313,7 @@ namespace MediaBrowser.Model.Dlna
/// <param name="audioSampleRate">The audio sample rate.</param>
/// <param name="audioBitDepth">The audio bit depth.</param>
/// <returns>The <see cref="ResponseProfile"/>.</returns>
- public ResponseProfile GetAudioMediaProfile(string container, string audioCodec, int? audioChannels, int? audioBitrate, int? audioSampleRate, int? audioBitDepth)
+ public ResponseProfile? GetAudioMediaProfile(string container, string? audioCodec, int? audioChannels, int? audioBitrate, int? audioSampleRate, int? audioBitDepth)
{
foreach (var i in ResponseProfiles)
{
@@ -384,7 +377,7 @@ namespace MediaBrowser.Model.Dlna
/// <param name="width">The width.</param>
/// <param name="height">The height.</param>
/// <returns>The <see cref="ResponseProfile"/>.</returns>
- public ResponseProfile GetImageMediaProfile(string container, int? width, int? height)
+ public ResponseProfile? GetImageMediaProfile(string container, int? width, int? height)
{
foreach (var i in ResponseProfiles)
{
@@ -442,10 +435,10 @@ namespace MediaBrowser.Model.Dlna
/// <param name="videoCodecTag">The video Codec tag.</param>
/// <param name="isAvc">True if Avc.</param>
/// <returns>The <see cref="ResponseProfile"/>.</returns>
- public ResponseProfile GetVideoMediaProfile(
+ public ResponseProfile? GetVideoMediaProfile(
string container,
- string audioCodec,
- string videoCodec,
+ string? audioCodec,
+ string? videoCodec,
int? width,
int? height,
int? bitDepth,
diff --git a/MediaBrowser.Model/Dlna/DirectPlayProfile.cs b/MediaBrowser.Model/Dlna/DirectPlayProfile.cs
index 88cb83991..fa3ad098f 100644
--- a/MediaBrowser.Model/Dlna/DirectPlayProfile.cs
+++ b/MediaBrowser.Model/Dlna/DirectPlayProfile.cs
@@ -1,6 +1,6 @@
-#nullable disable
#pragma warning disable CS1591
+using System.ComponentModel.DataAnnotations;
using System.Xml.Serialization;
namespace MediaBrowser.Model.Dlna
@@ -8,13 +8,13 @@ namespace MediaBrowser.Model.Dlna
public class DirectPlayProfile
{
[XmlAttribute("container")]
- public string Container { get; set; }
+ public string? Container { get; set; }
[XmlAttribute("audioCodec")]
- public string AudioCodec { get; set; }
+ public string? AudioCodec { get; set; }
[XmlAttribute("videoCodec")]
- public string VideoCodec { get; set; }
+ public string? VideoCodec { get; set; }
[XmlAttribute("type")]
public DlnaProfileType Type { get; set; }
diff --git a/MediaBrowser.Model/Dlna/StreamBuilder.cs b/MediaBrowser.Model/Dlna/StreamBuilder.cs
index 398d47d5f..f4c69fe8f 100644
--- a/MediaBrowser.Model/Dlna/StreamBuilder.cs
+++ b/MediaBrowser.Model/Dlna/StreamBuilder.cs
@@ -297,7 +297,7 @@ namespace MediaBrowser.Model.Dlna
int? inputAudioSampleRate = audioStream?.SampleRate;
int? inputAudioBitDepth = audioStream?.BitDepth;
- if (directPlayMethods.Count() > 0)
+ if (directPlayMethods.Any())
{
string audioCodec = audioStream?.Codec;
diff --git a/MediaBrowser.Model/Dlna/TranscodingProfile.cs b/MediaBrowser.Model/Dlna/TranscodingProfile.cs
index f05e31047..214578a85 100644
--- a/MediaBrowser.Model/Dlna/TranscodingProfile.cs
+++ b/MediaBrowser.Model/Dlna/TranscodingProfile.cs
@@ -1,6 +1,7 @@
-#nullable disable
#pragma warning disable CS1591
+using System.ComponentModel;
+using System.ComponentModel.DataAnnotations;
using System.Xml.Serialization;
namespace MediaBrowser.Model.Dlna
@@ -8,47 +9,56 @@ namespace MediaBrowser.Model.Dlna
public class TranscodingProfile
{
[XmlAttribute("container")]
- public string Container { get; set; }
+ public string Container { get; set; } = string.Empty;
[XmlAttribute("type")]
public DlnaProfileType Type { get; set; }
[XmlAttribute("videoCodec")]
- public string VideoCodec { get; set; }
+ public string VideoCodec { get; set; } = string.Empty;
[XmlAttribute("audioCodec")]
- public string AudioCodec { get; set; }
+ public string AudioCodec { get; set; } = string.Empty;
[XmlAttribute("protocol")]
- public string Protocol { get; set; }
+ public string Protocol { get; set; } = string.Empty;
+ [DefaultValue(false)]
[XmlAttribute("estimateContentLength")]
public bool EstimateContentLength { get; set; }
+ [DefaultValue(false)]
[XmlAttribute("enableMpegtsM2TsMode")]
public bool EnableMpegtsM2TsMode { get; set; }
+ [DefaultValue(TranscodeSeekInfo.Auto)]
[XmlAttribute("transcodeSeekInfo")]
public TranscodeSeekInfo TranscodeSeekInfo { get; set; }
+ [DefaultValue(false)]
[XmlAttribute("copyTimestamps")]
public bool CopyTimestamps { get; set; }
+ [DefaultValue(EncodingContext.Streaming)]
[XmlAttribute("context")]
public EncodingContext Context { get; set; }
+ [DefaultValue(false)]
[XmlAttribute("enableSubtitlesInManifest")]
public bool EnableSubtitlesInManifest { get; set; }
[XmlAttribute("maxAudioChannels")]
- public string MaxAudioChannels { get; set; }
+ public string? MaxAudioChannels { get; set; }
+ [DefaultValue(0)]
[XmlAttribute("minSegments")]
public int MinSegments { get; set; }
+ [DefaultValue(0)]
[XmlAttribute("segmentLength")]
public int SegmentLength { get; set; }
+ [DefaultValue(false)]
[XmlAttribute("breakOnNonKeyFrames")]
public bool BreakOnNonKeyFrames { get; set; }
diff --git a/MediaBrowser.Model/Entities/MediaStream.cs b/MediaBrowser.Model/Entities/MediaStream.cs
index ade9d7e8d..e644c9ba7 100644
--- a/MediaBrowser.Model/Entities/MediaStream.cs
+++ b/MediaBrowser.Model/Entities/MediaStream.cs
@@ -163,7 +163,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);
}
@@ -202,7 +202,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);
}
@@ -522,9 +522,9 @@ namespace MediaBrowser.Model.Entities
// sub = external .sub file
- return codec.IndexOf("pgs", StringComparison.OrdinalIgnoreCase) == -1 &&
- codec.IndexOf("dvd", StringComparison.OrdinalIgnoreCase) == -1 &&
- codec.IndexOf("dvbsub", StringComparison.OrdinalIgnoreCase) == -1 &&
+ return !codec.Contains("pgs", StringComparison.OrdinalIgnoreCase) &&
+ !codec.Contains("dvd", StringComparison.OrdinalIgnoreCase) &&
+ !codec.Contains("dvbsub", StringComparison.OrdinalIgnoreCase) &&
!string.Equals(codec, "sub", StringComparison.OrdinalIgnoreCase) &&
!string.Equals(codec, "dvb_subtitle", StringComparison.OrdinalIgnoreCase);
}
diff --git a/MediaBrowser.Model/Entities/ProviderIdsExtensions.cs b/MediaBrowser.Model/Entities/ProviderIdsExtensions.cs
index 09d14dc6a..ce4b0ec92 100644
--- a/MediaBrowser.Model/Entities/ProviderIdsExtensions.cs
+++ b/MediaBrowser.Model/Entities/ProviderIdsExtensions.cs
@@ -123,10 +123,7 @@ namespace MediaBrowser.Model.Entities
else
{
// Ensure it exists
- if (instance.ProviderIds == null)
- {
- instance.ProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
- }
+ instance.ProviderIds ??= new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
instance.ProviderIds[name] = value;
}
diff --git a/MediaBrowser.Model/IO/FileSystemMetadata.cs b/MediaBrowser.Model/IO/FileSystemMetadata.cs
index 118c78e80..fb74886bf 100644
--- a/MediaBrowser.Model/IO/FileSystemMetadata.cs
+++ b/MediaBrowser.Model/IO/FileSystemMetadata.cs
@@ -38,12 +38,6 @@ namespace MediaBrowser.Model.IO
public long Length { get; set; }
/// <summary>
- /// Gets or sets the name of the directory.
- /// </summary>
- /// <value>The name of the directory.</value>
- public string DirectoryName { get; set; }
-
- /// <summary>
/// Gets or sets the last write time UTC.
/// </summary>
/// <value>The last write time UTC.</value>
diff --git a/MediaBrowser.Providers/Manager/MetadataService.cs b/MediaBrowser.Providers/Manager/MetadataService.cs
index 6b778a090..401c7e99f 100644
--- a/MediaBrowser.Providers/Manager/MetadataService.cs
+++ b/MediaBrowser.Providers/Manager/MetadataService.cs
@@ -281,8 +281,7 @@ namespace MediaBrowser.Providers.Manager
return true;
}
- var folder = item as Folder;
- if (folder != null)
+ if (item is Folder folder)
{
return folder.SupportsDateLastMediaAdded || folder.SupportsCumulativeRunTimeTicks;
}
@@ -336,8 +335,7 @@ namespace MediaBrowser.Providers.Manager
private ItemUpdateType UpdateCumulativeRunTimeTicks(TItemType item, IList<BaseItem> children)
{
- var folder = item as Folder;
- if (folder != null && folder.SupportsCumulativeRunTimeTicks)
+ if (item is Folder folder && folder.SupportsCumulativeRunTimeTicks)
{
long ticks = 0;
diff --git a/MediaBrowser.Providers/Manager/ProviderManager.cs b/MediaBrowser.Providers/Manager/ProviderManager.cs
index 08c92e15a..dd497845d 100644
--- a/MediaBrowser.Providers/Manager/ProviderManager.cs
+++ b/MediaBrowser.Providers/Manager/ProviderManager.cs
@@ -167,7 +167,7 @@ namespace MediaBrowser.Providers.Manager
throw new HttpRequestException("Invalid image received.", null, response.StatusCode);
}
- var contentType = response.Content.Headers.ContentType.MediaType;
+ var contentType = response.Content.Headers.ContentType?.MediaType;
// Workaround for tvheadend channel icons
// TODO: Isolate this hack into the tvh plugin
diff --git a/MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs b/MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs
index 64ad1bddf..03e45fb86 100644
--- a/MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs
+++ b/MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs
@@ -137,9 +137,7 @@ namespace MediaBrowser.Providers.MediaInfo
return false;
}
- var audio = item as Audio;
-
- return audio != null;
+ return item is Audio;
}
}
}
diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs
index 74849a522..f049cc81f 100644
--- a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs
+++ b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs
@@ -111,10 +111,7 @@ namespace MediaBrowser.Providers.MediaInfo
}
}
- if (streamFileNames == null)
- {
- streamFileNames = Array.Empty<string>();
- }
+ streamFileNames ??= Array.Empty<string>();
mediaInfoResult = await GetMediaInfo(item, cancellationToken).ConfigureAwait(false);
diff --git a/MediaBrowser.Providers/MediaInfo/SubtitleDownloader.cs b/MediaBrowser.Providers/MediaInfo/SubtitleDownloader.cs
index 912aedb0d..44ab5aa5b 100644
--- a/MediaBrowser.Providers/MediaInfo/SubtitleDownloader.cs
+++ b/MediaBrowser.Providers/MediaInfo/SubtitleDownloader.cs
@@ -172,9 +172,7 @@ namespace MediaBrowser.Providers.MediaInfo
SubtitleFetcherOrder = subtitleFetcherOrder
};
- var episode = video as Episode;
-
- if (episode != null)
+ if (video is Episode episode)
{
request.IndexNumberEnd = episode.IndexNumberEnd;
request.SeriesName = episode.SeriesName;
diff --git a/MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs b/MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs
index c36c3af6a..30af6710a 100644
--- a/MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs
+++ b/MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs
@@ -154,9 +154,7 @@ namespace MediaBrowser.Providers.MediaInfo
return false;
}
- var video = item as Video;
-
- if (video != null && !video.IsPlaceHolder && video.IsCompleteMedia)
+ if (item is Video video && !video.IsPlaceHolder && video.IsCompleteMedia)
{
return true;
}
diff --git a/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieProvider.cs
index d22c1b50a..4a0884c07 100644
--- a/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieProvider.cs
+++ b/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieProvider.cs
@@ -206,12 +206,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Movies
if (ourRelease != null)
{
- var ratingPrefix = string.Equals(info.MetadataCountryCode, "us", StringComparison.OrdinalIgnoreCase) ? string.Empty : info.MetadataCountryCode + "-";
- var newRating = ratingPrefix + ourRelease.Certification;
-
- newRating = newRating.Replace("de-", "FSK-", StringComparison.OrdinalIgnoreCase);
-
- movie.OfficialRating = newRating;
+ movie.OfficialRating = TmdbUtils.BuildParentalRating(ourRelease.Iso_3166_1, ourRelease.Certification);
}
else if (usRelease != null)
{
diff --git a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeriesProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeriesProvider.cs
index 496e1ae25..da76345b5 100644
--- a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeriesProvider.cs
+++ b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeriesProvider.cs
@@ -300,7 +300,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV
if (ourRelease != null)
{
- series.OfficialRating = ourRelease.Rating;
+ series.OfficialRating = TmdbUtils.BuildParentalRating(ourRelease.Iso_3166_1, ourRelease.Rating);
}
else if (usRelease != null)
{
diff --git a/MediaBrowser.Providers/Plugins/Tmdb/TmdbUtils.cs b/MediaBrowser.Providers/Plugins/Tmdb/TmdbUtils.cs
index 15a44c7ed..b4e165f82 100644
--- a/MediaBrowser.Providers/Plugins/Tmdb/TmdbUtils.cs
+++ b/MediaBrowser.Providers/Plugins/Tmdb/TmdbUtils.cs
@@ -63,19 +63,19 @@ namespace MediaBrowser.Providers.Plugins.Tmdb
/// <returns>The Jellyfin person type.</returns>
public static string MapCrewToPersonType(Crew crew)
{
- if (crew.Department.Equals("production", StringComparison.InvariantCultureIgnoreCase)
- && crew.Job.Contains("director", StringComparison.InvariantCultureIgnoreCase))
+ if (crew.Department.Equals("production", StringComparison.OrdinalIgnoreCase)
+ && crew.Job.Contains("director", StringComparison.OrdinalIgnoreCase))
{
return PersonType.Director;
}
- if (crew.Department.Equals("production", StringComparison.InvariantCultureIgnoreCase)
- && crew.Job.Contains("producer", StringComparison.InvariantCultureIgnoreCase))
+ if (crew.Department.Equals("production", StringComparison.OrdinalIgnoreCase)
+ && crew.Job.Contains("producer", StringComparison.OrdinalIgnoreCase))
{
return PersonType.Producer;
}
- if (crew.Department.Equals("writing", StringComparison.InvariantCultureIgnoreCase))
+ if (crew.Department.Equals("writing", StringComparison.OrdinalIgnoreCase))
{
return PersonType.Writer;
}
@@ -173,5 +173,20 @@ namespace MediaBrowser.Providers.Plugins.Tmdb
return imageLanguage;
}
+
+ /// <summary>
+ /// Combines the metadata country code and the parental rating from the Api into the value we store in our database.
+ /// </summary>
+ /// <param name="countryCode">The Iso 3166-1 country code of the rating country.</param>
+ /// <param name="ratingValue">The rating value returned by the Tmdb Api.</param>
+ /// <returns>The combined parental rating of country code+rating value.</returns>
+ public static string BuildParentalRating(string countryCode, string ratingValue)
+ {
+ // exclude US because we store us values as TV-14 without the country code.
+ var ratingPrefix = string.Equals(countryCode, "US", StringComparison.OrdinalIgnoreCase) ? string.Empty : countryCode + "-";
+ var newRating = ratingPrefix + ratingValue;
+
+ return newRating.Replace("DE-", "FSK-", StringComparison.OrdinalIgnoreCase);
+ }
}
}
diff --git a/MediaBrowser.Providers/Studios/StudiosImageProvider.cs b/MediaBrowser.Providers/Studios/StudiosImageProvider.cs
index 5fcf6d9aa..5ec9a02cb 100644
--- a/MediaBrowser.Providers/Studios/StudiosImageProvider.cs
+++ b/MediaBrowser.Providers/Studios/StudiosImageProvider.cs
@@ -8,6 +8,7 @@ using System.Linq;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
+using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
@@ -177,13 +178,11 @@ namespace MediaBrowser.Providers.Studios
{
var lines = new List<string>();
- while (!reader.EndOfStream)
+ foreach (var line in reader.ReadAllLines())
{
- var text = reader.ReadLine();
-
- if (!string.IsNullOrWhiteSpace(text))
+ if (!string.IsNullOrWhiteSpace(line))
{
- lines.Add(text);
+ lines.Add(line);
}
}
diff --git a/MediaBrowser.Providers/Subtitles/SubtitleManager.cs b/MediaBrowser.Providers/Subtitles/SubtitleManager.cs
index 1f3d9acff..bf0c853ae 100644
--- a/MediaBrowser.Providers/Subtitles/SubtitleManager.cs
+++ b/MediaBrowser.Providers/Subtitles/SubtitleManager.cs
@@ -207,7 +207,7 @@ namespace MediaBrowser.Providers.Subtitles
{
var mediaFolderPath = Path.GetFullPath(Path.Combine(video.ContainingFolderPath, saveFileName));
// TODO: Add some error handling to the API user: return BadRequest("Could not save subtitle, bad path.");
- if (mediaFolderPath.StartsWith(video.ContainingFolderPath))
+ if (mediaFolderPath.StartsWith(video.ContainingFolderPath, StringComparison.Ordinal))
{
savePaths.Add(mediaFolderPath);
}
@@ -216,7 +216,7 @@ namespace MediaBrowser.Providers.Subtitles
var internalPath = Path.GetFullPath(Path.Combine(video.GetInternalMetadataPath(), saveFileName));
// TODO: Add some error to the user: return BadRequest("Could not save subtitle, bad path.");
- if (internalPath.StartsWith(video.GetInternalMetadataPath()))
+ if (internalPath.StartsWith(video.GetInternalMetadataPath(), StringComparison.Ordinal))
{
savePaths.Add(internalPath);
}
@@ -234,7 +234,7 @@ namespace MediaBrowser.Providers.Subtitles
private async Task TrySaveToFiles(Stream stream, List<string> savePaths)
{
- Exception exceptionToThrow = null;
+ List<Exception> exs = null;
foreach (var savePath in savePaths)
{
@@ -256,10 +256,7 @@ namespace MediaBrowser.Providers.Subtitles
}
catch (Exception ex)
{
- if (exceptionToThrow == null)
- {
- exceptionToThrow = ex;
- }
+ (exs ??= new List<Exception>()).Add(ex);
}
finally
{
@@ -269,9 +266,9 @@ namespace MediaBrowser.Providers.Subtitles
stream.Position = 0;
}
- if (exceptionToThrow != null)
+ if (exs != null)
{
- throw exceptionToThrow;
+ throw new AggregateException(exs);
}
}
diff --git a/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs b/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs
index ff9f11eab..302c93f0b 100644
--- a/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs
+++ b/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs
@@ -662,6 +662,21 @@ namespace MediaBrowser.XbmcMetadata.Parsers
break;
}
+ case "ratings":
+ {
+ if (!reader.IsEmptyElement)
+ {
+ using var subtree = reader.ReadSubtree();
+ FetchFromRatingsNode(subtree, item);
+ }
+ else
+ {
+ reader.Read();
+ }
+
+ break;
+ }
+
case "aired":
case "formed":
case "premiered":
@@ -1080,6 +1095,92 @@ namespace MediaBrowser.XbmcMetadata.Parsers
}
}
+ private void FetchFromRatingsNode(XmlReader reader, T item)
+ {
+ reader.MoveToContent();
+ reader.Read();
+
+ // Loop through each element
+ while (!reader.EOF && reader.ReadState == ReadState.Interactive)
+ {
+ if (reader.NodeType == XmlNodeType.Element)
+ {
+ switch (reader.Name)
+ {
+ case "rating":
+ {
+ if (reader.IsEmptyElement)
+ {
+ reader.Read();
+ continue;
+ }
+
+ var ratingName = reader.GetAttribute("name");
+
+ using var subtree = reader.ReadSubtree();
+ FetchFromRatingNode(subtree, item, ratingName);
+
+ break;
+ }
+
+ default:
+ reader.Skip();
+ break;
+ }
+ }
+ else
+ {
+ reader.Read();
+ }
+ }
+ }
+
+ private void FetchFromRatingNode(XmlReader reader, T item, string? ratingName)
+ {
+ reader.MoveToContent();
+ reader.Read();
+
+ // Loop through each element
+ while (!reader.EOF && reader.ReadState == ReadState.Interactive)
+ {
+ if (reader.NodeType == XmlNodeType.Element)
+ {
+ switch (reader.Name)
+ {
+ case "value":
+ var val = reader.ReadElementContentAsString();
+
+ if (!string.IsNullOrWhiteSpace(val))
+ {
+ if (float.TryParse(val, NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out var ratingValue))
+ {
+ // if ratingName contains tomato --> assume critic rating
+ if (ratingName != null &&
+ ratingName.Contains("tomato", StringComparison.OrdinalIgnoreCase) &&
+ !ratingName.Contains("audience", StringComparison.OrdinalIgnoreCase))
+ {
+ item.CriticRating = ratingValue;
+ }
+ else
+ {
+ item.CommunityRating = ratingValue;
+ }
+ }
+ }
+
+ break;
+ default:
+ reader.Skip();
+ break;
+ }
+ }
+ else
+ {
+ reader.Read();
+ }
+ }
+ }
+
/// <summary>
/// Gets the persons from XML node.
/// </summary>
@@ -1232,6 +1333,7 @@ namespace MediaBrowser.XbmcMetadata.Parsers
"discart" => ImageType.Disc,
"landscape" => ImageType.Thumb,
"clearart" => ImageType.Art,
+ "fanart" => ImageType.Backdrop,
// unknown type (including "poster") --> primary
_ => ImageType.Primary,
};
diff --git a/MediaBrowser.XbmcMetadata/Providers/AlbumNfoProvider.cs b/MediaBrowser.XbmcMetadata/Providers/AlbumNfoProvider.cs
index bd557d783..f7a85a07e 100644
--- a/MediaBrowser.XbmcMetadata/Providers/AlbumNfoProvider.cs
+++ b/MediaBrowser.XbmcMetadata/Providers/AlbumNfoProvider.cs
@@ -57,7 +57,7 @@ namespace MediaBrowser.XbmcMetadata.Providers
}
/// <inheritdoc />
- protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService)
+ protected override FileSystemMetadata? GetXmlFile(ItemInfo info, IDirectoryService directoryService)
=> directoryService.GetFile(Path.Combine(info.Path, "album.nfo"));
}
}
diff --git a/MediaBrowser.XbmcMetadata/Providers/ArtistNfoProvider.cs b/MediaBrowser.XbmcMetadata/Providers/ArtistNfoProvider.cs
index 54bb83114..2b563b7fa 100644
--- a/MediaBrowser.XbmcMetadata/Providers/ArtistNfoProvider.cs
+++ b/MediaBrowser.XbmcMetadata/Providers/ArtistNfoProvider.cs
@@ -57,7 +57,7 @@ namespace MediaBrowser.XbmcMetadata.Providers
}
/// <inheritdoc />
- protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService)
+ protected override FileSystemMetadata? GetXmlFile(ItemInfo info, IDirectoryService directoryService)
=> directoryService.GetFile(Path.Combine(info.Path, "artist.nfo"));
}
}
diff --git a/MediaBrowser.XbmcMetadata/Providers/EpisodeNfoProvider.cs b/MediaBrowser.XbmcMetadata/Providers/EpisodeNfoProvider.cs
index 64b208345..f6c5877b4 100644
--- a/MediaBrowser.XbmcMetadata/Providers/EpisodeNfoProvider.cs
+++ b/MediaBrowser.XbmcMetadata/Providers/EpisodeNfoProvider.cs
@@ -57,7 +57,7 @@ namespace MediaBrowser.XbmcMetadata.Providers
}
/// <inheritdoc />
- protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService)
+ protected override FileSystemMetadata? GetXmlFile(ItemInfo info, IDirectoryService directoryService)
{
var path = Path.ChangeExtension(info.Path, ".nfo");
diff --git a/MediaBrowser.XbmcMetadata/Providers/SeasonNfoProvider.cs b/MediaBrowser.XbmcMetadata/Providers/SeasonNfoProvider.cs
index 97220cf7e..d01abadf6 100644
--- a/MediaBrowser.XbmcMetadata/Providers/SeasonNfoProvider.cs
+++ b/MediaBrowser.XbmcMetadata/Providers/SeasonNfoProvider.cs
@@ -57,7 +57,7 @@ namespace MediaBrowser.XbmcMetadata.Providers
}
/// <inheritdoc />
- protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService)
+ protected override FileSystemMetadata? GetXmlFile(ItemInfo info, IDirectoryService directoryService)
=> directoryService.GetFile(Path.Combine(info.Path, "season.nfo"));
}
}
diff --git a/MediaBrowser.XbmcMetadata/Providers/SeriesNfoProvider.cs b/MediaBrowser.XbmcMetadata/Providers/SeriesNfoProvider.cs
index 9a9b94123..002b94463 100644
--- a/MediaBrowser.XbmcMetadata/Providers/SeriesNfoProvider.cs
+++ b/MediaBrowser.XbmcMetadata/Providers/SeriesNfoProvider.cs
@@ -57,7 +57,7 @@ namespace MediaBrowser.XbmcMetadata.Providers
}
/// <inheritdoc />
- protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService)
+ protected override FileSystemMetadata? GetXmlFile(ItemInfo info, IDirectoryService directoryService)
=> directoryService.GetFile(Path.Combine(info.Path, "tvshow.nfo"));
}
}
diff --git a/RSSDP/SsdpCommunicationsServer.cs b/RSSDP/SsdpCommunicationsServer.cs
index 8f1f0fa61..f448ad38b 100644
--- a/RSSDP/SsdpCommunicationsServer.cs
+++ b/RSSDP/SsdpCommunicationsServer.cs
@@ -415,10 +415,7 @@ namespace Rssdp.Infrastructure
{
lock (_SendSocketSynchroniser)
{
- if (_sendSockets == null)
- {
- _sendSockets = CreateSocketAndListenForResponsesAsync();
- }
+ _sendSockets ??= CreateSocketAndListenForResponsesAsync();
}
}
}
diff --git a/apiclient/.openapi-generator-ignore b/apiclient/.openapi-generator-ignore
deleted file mode 100644
index f3802cf54..000000000
--- a/apiclient/.openapi-generator-ignore
+++ /dev/null
@@ -1,2 +0,0 @@
-# Prevent generator from creating these files:
-git_push.sh
diff --git a/apiclient/templates/typescript/axios/generate.sh b/apiclient/templates/typescript/axios/generate.sh
deleted file mode 100644
index 9599f85db..000000000
--- a/apiclient/templates/typescript/axios/generate.sh
+++ /dev/null
@@ -1,11 +0,0 @@
-#!/bin/bash
-
-artifactsDirectory="${1}"
-
-java -jar openapi-generator-cli.jar generate \
- --input-spec ${artifactsDirectory}/openapispec/openapi.json \
- --generator-name typescript-axios \
- --output ./apiclient/generated/typescript/axios \
- --template-dir ./apiclient/templates/typescript/axios \
- --ignore-file-override ./apiclient/.openapi-generator-ignore \
- --additional-properties=useSingleRequestParameter="true",withSeparateModelsAndApi="true",modelPackage="models",apiPackage="api",npmName="axios"
diff --git a/apiclient/templates/typescript/axios/package.mustache b/apiclient/templates/typescript/axios/package.mustache
deleted file mode 100644
index 7bfab08cb..000000000
--- a/apiclient/templates/typescript/axios/package.mustache
+++ /dev/null
@@ -1,30 +0,0 @@
-{
- "name": "@jellyfin/client-axios",
- "version": "10.7.0{{snapshotVersion}}",
- "description": "Jellyfin api client using axios",
- "author": "Jellyfin Contributors",
- "keywords": [
- "axios",
- "typescript",
- "jellyfin"
- ],
- "license": "GPL-3.0-only",
- "main": "./dist/index.js",
- "typings": "./dist/index.d.ts",
- "scripts": {
- "build": "tsc --outDir dist/",
- "prepublishOnly": "npm run build"
- },
- "dependencies": {
- "axios": "^0.19.2"
- },
- "devDependencies": {
- "@types/node": "^12.11.5",
- "typescript": "^3.6.4"
- }{{#npmRepository}},{{/npmRepository}}
-{{#npmRepository}}
- "publishConfig": {
- "registry": "{{npmRepository}}"
- }
-{{/npmRepository}}
-}
diff --git a/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj b/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj
index 0071cda6e..397b863b7 100644
--- a/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj
+++ b/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj
@@ -16,8 +16,8 @@
<ItemGroup>
<PackageReference Include="AutoFixture" Version="4.17.0" />
- <PackageReference Include="AutoFixture.AutoMoq" Version="4.16.0" />
- <PackageReference Include="AutoFixture.Xunit2" Version="4.16.0" />
+ <PackageReference Include="AutoFixture.AutoMoq" Version="4.17.0" />
+ <PackageReference Include="AutoFixture.Xunit2" Version="4.17.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="5.0.5" />
<PackageReference Include="Microsoft.Extensions.Options" Version="5.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.4" />
diff --git a/tests/Jellyfin.Model.Tests/Dlna/ContainerProfileTests.cs b/tests/Jellyfin.Model.Tests/Dlna/ContainerProfileTests.cs
new file mode 100644
index 000000000..cca056c28
--- /dev/null
+++ b/tests/Jellyfin.Model.Tests/Dlna/ContainerProfileTests.cs
@@ -0,0 +1,19 @@
+using MediaBrowser.Model.Dlna;
+using Xunit;
+
+namespace Jellyfin.Model.Tests.Dlna
+{
+ public class ContainerProfileTests
+ {
+ private readonly ContainerProfile _emptyContainerProfile = new ContainerProfile();
+
+ [Theory]
+ [InlineData(null)]
+ [InlineData("")]
+ [InlineData("mp4")]
+ public void ContainsContainer_EmptyContainerProfile_True(string? containers)
+ {
+ Assert.True(_emptyContainerProfile.ContainsContainer(containers));
+ }
+ }
+}
diff --git a/tests/Jellyfin.Networking.Tests/NetworkParseTests.cs b/tests/Jellyfin.Networking.Tests/NetworkParseTests.cs
index 9b0da2b3c..671b8598d 100644
--- a/tests/Jellyfin.Networking.Tests/NetworkParseTests.cs
+++ b/tests/Jellyfin.Networking.Tests/NetworkParseTests.cs
@@ -384,6 +384,9 @@ namespace Jellyfin.Networking.Tests
[InlineData("jellyfin.org", "eth16", false, "eth16")]
// User on external network, no binding - so result is the 1st external.
[InlineData("jellyfin.org", "", false, "eth11")]
+ // Dns failure - should skip the test.
+ // https://en.wikipedia.org/wiki/.test
+ [InlineData("invalid.domain.test", "", false, "eth11")]
// User assumed to be internal, no binding - so result is the 1st internal.
[InlineData("", "", false, "eth16")]
public void TestBindInterfaces(string source, string bindAddresses, bool ipv6enabled, string result)
@@ -416,10 +419,13 @@ namespace Jellyfin.Networking.Tests
_ = nm.TryParseInterface(result, out Collection<IPObject>? resultObj);
- if (resultObj != null)
+ // Check to see if dns resolution is working. If not, skip test.
+ _ = IPHost.TryParse(source, out var host);
+
+ if (resultObj != null && host?.HasAddress == true)
{
result = ((IPNetAddress)resultObj[0]).ToString(true);
- var intf = nm.GetBindInterface(source, out int? _);
+ var intf = nm.GetBindInterface(source, out _);
Assert.Equal(intf, result);
}
diff --git a/tests/Jellyfin.Server.Implementations.Tests/Data/SqliteItemRepositoryTests.cs b/tests/Jellyfin.Server.Implementations.Tests/Data/SqliteItemRepositoryTests.cs
new file mode 100644
index 000000000..71f8c5181
--- /dev/null
+++ b/tests/Jellyfin.Server.Implementations.Tests/Data/SqliteItemRepositoryTests.cs
@@ -0,0 +1,250 @@
+using System;
+using System.Collections.Generic;
+using AutoFixture;
+using AutoFixture.AutoMoq;
+using Emby.Server.Implementations.Data;
+using MediaBrowser.Controller;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Model.Entities;
+using Moq;
+using Xunit;
+
+namespace Jellyfin.Server.Implementations.Tests.Data
+{
+ public class SqliteItemRepositoryTests
+ {
+ public const string VirtualMetaDataPath = "%MetadataPath%";
+ public const string MetaDataPath = "/meta/data/path";
+
+ private readonly IFixture _fixture;
+ private readonly SqliteItemRepository _sqliteItemRepository;
+
+ public SqliteItemRepositoryTests()
+ {
+ var appHost = new Mock<IServerApplicationHost>();
+ appHost.Setup(x => x.ExpandVirtualPath(It.IsAny<string>()))
+ .Returns((string x) => x.Replace(VirtualMetaDataPath, MetaDataPath, StringComparison.Ordinal));
+ appHost.Setup(x => x.ReverseVirtualPath(It.IsAny<string>()))
+ .Returns((string x) => x.Replace(MetaDataPath, VirtualMetaDataPath, StringComparison.Ordinal));
+
+ _fixture = new Fixture().Customize(new AutoMoqCustomization { ConfigureMembers = true });
+ _fixture.Inject(appHost);
+ _sqliteItemRepository = _fixture.Create<SqliteItemRepository>();
+ }
+
+ public static IEnumerable<object[]> ItemImageInfoFromValueString_Valid_TestData()
+ {
+ yield return new object[]
+ {
+ "/mnt/series/Family Guy/Season 1/Family Guy - S01E01-thumb.jpg*637452096478512963*Primary*1920*1080*WjQbtJtSO8nhNZ%L_Io#R/oaS6o}-;adXAoIn7j[%hW9s:WGw[nN",
+ new ItemImageInfo
+ {
+ Path = "/mnt/series/Family Guy/Season 1/Family Guy - S01E01-thumb.jpg",
+ Type = ImageType.Primary,
+ DateModified = new DateTime(637452096478512963, DateTimeKind.Utc),
+ Width = 1920,
+ Height = 1080,
+ BlurHash = "WjQbtJtSO8nhNZ%L_Io#R*oaS6o}-;adXAoIn7j[%hW9s:WGw[nN"
+ }
+ };
+
+ yield return new object[]
+ {
+ "https://image.tmdb.org/t/p/original/zhB5CHEgqqh4wnEqDNJLfWXJlcL.jpg*0*Primary*0*0",
+ new ItemImageInfo
+ {
+ Path = "https://image.tmdb.org/t/p/original/zhB5CHEgqqh4wnEqDNJLfWXJlcL.jpg",
+ Type = ImageType.Primary,
+ }
+ };
+
+ yield return new object[]
+ {
+ "https://image.tmdb.org/t/p/original/zhB5CHEgqqh4wnEqDNJLfWXJlcL.jpg*0*Primary",
+ new ItemImageInfo
+ {
+ Path = "https://image.tmdb.org/t/p/original/zhB5CHEgqqh4wnEqDNJLfWXJlcL.jpg",
+ Type = ImageType.Primary,
+ }
+ };
+
+ yield return new object[]
+ {
+ "https://image.tmdb.org/t/p/original/zhB5CHEgqqh4wnEqDNJLfWXJlcL.jpg*0*Primary*600",
+ new ItemImageInfo
+ {
+ Path = "https://image.tmdb.org/t/p/original/zhB5CHEgqqh4wnEqDNJLfWXJlcL.jpg",
+ Type = ImageType.Primary,
+ }
+ };
+
+ yield return new object[]
+ {
+ "%MetadataPath%/library/68/68578562b96c80a7ebd530848801f645/poster.jpg*637264380567586027*Primary*600*336",
+ new ItemImageInfo
+ {
+ Path = "/meta/data/path/library/68/68578562b96c80a7ebd530848801f645/poster.jpg",
+ Type = ImageType.Primary,
+ DateModified = new DateTime(637264380567586027, DateTimeKind.Utc),
+ Width = 600,
+ Height = 336
+ }
+ };
+ }
+
+ [Theory]
+ [MemberData(nameof(ItemImageInfoFromValueString_Valid_TestData))]
+ public void ItemImageInfoFromValueString_Valid_Success(string value, ItemImageInfo expected)
+ {
+ var result = _sqliteItemRepository.ItemImageInfoFromValueString(value);
+ Assert.Equal(expected.Path, result.Path);
+ Assert.Equal(expected.Type, result.Type);
+ Assert.Equal(expected.DateModified, result.DateModified);
+ Assert.Equal(expected.Width, result.Width);
+ Assert.Equal(expected.Height, result.Height);
+ Assert.Equal(expected.BlurHash, result.BlurHash);
+ }
+
+ [Theory]
+ [InlineData("")]
+ [InlineData("*")]
+ [InlineData("https://image.tmdb.org/t/p/original/zhB5CHEgqqh4wnEqDNJLfWXJlcL.jpg*0")]
+ public void ItemImageInfoFromValueString_Invalid_Null(string value)
+ {
+ Assert.Null(_sqliteItemRepository.ItemImageInfoFromValueString(value));
+ }
+
+ public static IEnumerable<object[]> DeserializeImages_Valid_TestData()
+ {
+ yield return new object[]
+ {
+ "/mnt/series/Family Guy/Season 1/Family Guy - S01E01-thumb.jpg*637452096478512963*Primary*1920*1080*WjQbtJtSO8nhNZ%L_Io#R/oaS6o}-;adXAoIn7j[%hW9s:WGw[nN",
+ new ItemImageInfo[]
+ {
+ new ItemImageInfo()
+ {
+ Path = "/mnt/series/Family Guy/Season 1/Family Guy - S01E01-thumb.jpg",
+ Type = ImageType.Primary,
+ DateModified = new DateTime(637452096478512963, DateTimeKind.Utc),
+ Width = 1920,
+ Height = 1080,
+ BlurHash = "WjQbtJtSO8nhNZ%L_Io#R*oaS6o}-;adXAoIn7j[%hW9s:WGw[nN"
+ }
+ }
+ };
+
+ yield return new object[]
+ {
+ "%MetadataPath%/library/2a/2a27372f1e9bc757b1db99721bbeae1e/poster.jpg*637261226720645297*Primary*0*0|%MetadataPath%/library/2a/2a27372f1e9bc757b1db99721bbeae1e/logo.png*637261226720805297*Logo*0*0|%MetadataPath%/library/2a/2a27372f1e9bc757b1db99721bbeae1e/landscape.jpg*637261226721285297*Thumb*0*0|%MetadataPath%/library/2a/2a27372f1e9bc757b1db99721bbeae1e/backdrop.jpg*637261226721685297*Backdrop*0*0",
+ new ItemImageInfo[]
+ {
+ new ItemImageInfo()
+ {
+ Path = "/meta/data/path/library/2a/2a27372f1e9bc757b1db99721bbeae1e/poster.jpg",
+ Type = ImageType.Primary,
+ DateModified = new DateTime(637261226720645297, DateTimeKind.Utc),
+ },
+ new ItemImageInfo()
+ {
+ Path = "/meta/data/path/library/2a/2a27372f1e9bc757b1db99721bbeae1e/logo.png",
+ Type = ImageType.Logo,
+ DateModified = new DateTime(637261226720805297, DateTimeKind.Utc),
+ },
+ new ItemImageInfo()
+ {
+ Path = "/meta/data/path/library/2a/2a27372f1e9bc757b1db99721bbeae1e/landscape.jpg",
+ Type = ImageType.Thumb,
+ DateModified = new DateTime(637261226721285297, DateTimeKind.Utc),
+ },
+ new ItemImageInfo()
+ {
+ Path = "/meta/data/path/library/2a/2a27372f1e9bc757b1db99721bbeae1e/backdrop.jpg",
+ Type = ImageType.Backdrop,
+ DateModified = new DateTime(637261226721685297, DateTimeKind.Utc),
+ }
+ }
+ };
+ }
+
+ [Theory]
+ [MemberData(nameof(DeserializeImages_Valid_TestData))]
+ public void DeserializeImages_Valid_Success(string value, ItemImageInfo[] expected)
+ {
+ var result = _sqliteItemRepository.DeserializeImages(value);
+ Assert.Equal(expected.Length, result.Length);
+ for (int i = 0; i < expected.Length; i++)
+ {
+ Assert.Equal(expected[i].Path, result[i].Path);
+ Assert.Equal(expected[i].Type, result[i].Type);
+ Assert.Equal(expected[i].DateModified, result[i].DateModified);
+ Assert.Equal(expected[i].Width, result[i].Width);
+ Assert.Equal(expected[i].Height, result[i].Height);
+ Assert.Equal(expected[i].BlurHash, result[i].BlurHash);
+ }
+ }
+
+ [Theory]
+ [MemberData(nameof(DeserializeImages_Valid_TestData))]
+ public void SerializeImages_Valid_Success(string expected, ItemImageInfo[] value)
+ {
+ Assert.Equal(expected, _sqliteItemRepository.SerializeImages(value));
+ }
+
+ public static IEnumerable<object[]> DeserializeProviderIds_Valid_TestData()
+ {
+ yield return new object[]
+ {
+ "Imdb=tt0119567",
+ new Dictionary<string, string>()
+ {
+ { "Imdb", "tt0119567" },
+ }
+ };
+
+ yield return new object[]
+ {
+ "Imdb=tt0119567|Tmdb=330|TmdbCollection=328",
+ new Dictionary<string, string>()
+ {
+ { "Imdb", "tt0119567" },
+ { "Tmdb", "330" },
+ { "TmdbCollection", "328" },
+ }
+ };
+
+ yield return new object[]
+ {
+ "MusicBrainzAlbum=9d363e43-f24f-4b39-bc5a-7ef305c677c7|MusicBrainzReleaseGroup=63eba062-847c-3b73-8b0f-6baf27bba6fa|AudioDbArtist=111352|AudioDbAlbum=2116560|MusicBrainzAlbumArtist=20244d07-534f-4eff-b4d4-930878889970",
+ new Dictionary<string, string>()
+ {
+ { "MusicBrainzAlbum", "9d363e43-f24f-4b39-bc5a-7ef305c677c7" },
+ { "MusicBrainzReleaseGroup", "63eba062-847c-3b73-8b0f-6baf27bba6fa" },
+ { "AudioDbArtist", "111352" },
+ { "AudioDbAlbum", "2116560" },
+ { "MusicBrainzAlbumArtist", "20244d07-534f-4eff-b4d4-930878889970" },
+ }
+ };
+ }
+
+ [Theory]
+ [MemberData(nameof(DeserializeProviderIds_Valid_TestData))]
+ public void DeserializeProviderIds_Valid_Success(string value, Dictionary<string, string> expected)
+ {
+ var result = new ProviderIdsExtensionsTestsObject();
+ SqliteItemRepository.DeserializeProviderIds(value, result);
+ Assert.Equal(expected, result.ProviderIds);
+ }
+
+ [Theory]
+ [MemberData(nameof(DeserializeProviderIds_Valid_TestData))]
+ public void SerializeProviderIds_Valid_Success(string expected, Dictionary<string, string> values)
+ {
+ Assert.Equal(expected, SqliteItemRepository.SerializeProviderIds(values));
+ }
+
+ private class ProviderIdsExtensionsTestsObject : IHasProviderIds
+ {
+ public Dictionary<string, string> ProviderIds { get; set; } = new Dictionary<string, string>();
+ }
+ }
+}
diff --git a/tests/Jellyfin.Server.Implementations.Tests/IO/ManagedFileSystemTests.cs b/tests/Jellyfin.Server.Implementations.Tests/IO/ManagedFileSystemTests.cs
index 614a68975..30e6542f9 100644
--- a/tests/Jellyfin.Server.Implementations.Tests/IO/ManagedFileSystemTests.cs
+++ b/tests/Jellyfin.Server.Implementations.Tests/IO/ManagedFileSystemTests.cs
@@ -42,6 +42,16 @@ namespace Jellyfin.Server.Implementations.Tests.IO
}
}
+ [Theory]
+ [InlineData("ValidFileName", "ValidFileName")]
+ [InlineData("AC/DC", "AC DC")]
+ [InlineData("Invalid\0", "Invalid ")]
+ [InlineData("AC/DC\0KD/A", "AC DC KD A")]
+ public void GetValidFilename_ReturnsValidFilename(string filename, string expectedFileName)
+ {
+ Assert.Equal(expectedFileName, _sut.GetValidFilename(filename));
+ }
+
[SkippableFact]
public void GetFileInfo_DanglingSymlink_ExistsFalse()
{
diff --git a/tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj b/tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj
index 7a4ab9b26..27713d58a 100644
--- a/tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj
+++ b/tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj
@@ -23,7 +23,7 @@
<ItemGroup>
<PackageReference Include="AutoFixture" Version="4.17.0" />
- <PackageReference Include="AutoFixture.AutoMoq" Version="4.16.0" />
+ <PackageReference Include="AutoFixture.AutoMoq" Version="4.17.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.4" />
<PackageReference Include="Moq" Version="4.16.1" />
<PackageReference Include="xunit" Version="2.4.1" />
diff --git a/tests/Jellyfin.Server.Implementations.Tests/Library/EpisodeResolverTest.cs b/tests/Jellyfin.Server.Implementations.Tests/Library/EpisodeResolverTest.cs
index 876519215..c393742eb 100644
--- a/tests/Jellyfin.Server.Implementations.Tests/Library/EpisodeResolverTest.cs
+++ b/tests/Jellyfin.Server.Implementations.Tests/Library/EpisodeResolverTest.cs
@@ -6,6 +6,7 @@ using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.IO;
using Moq;
using Xunit;
@@ -28,7 +29,10 @@ namespace Jellyfin.Server.Implementations.Tests.Library
{
Parent = parent,
CollectionType = CollectionType.TvShows,
- Path = "All My Children/Season 01/Extras/All My Children S01E01 - Behind The Scenes.mkv"
+ FileInfo = new FileSystemMetadata()
+ {
+ FullName = "All My Children/Season 01/Extras/All My Children S01E01 - Behind The Scenes.mkv"
+ }
};
Assert.Null(episodeResolver.Resolve(itemResolveArgs));
@@ -48,7 +52,10 @@ namespace Jellyfin.Server.Implementations.Tests.Library
{
Parent = series,
CollectionType = CollectionType.TvShows,
- Path = "Extras/Extras S01E01.mkv"
+ FileInfo = new FileSystemMetadata()
+ {
+ FullName = "Extras/Extras S01E01.mkv"
+ }
};
Assert.NotNull(episodeResolver.Resolve(itemResolveArgs));
}
diff --git a/tests/Jellyfin.Server.Implementations.Tests/Library/PathExtensionsTests.cs b/tests/Jellyfin.Server.Implementations.Tests/Library/PathExtensionsTests.cs
index e5508243f..c5cc056f5 100644
--- a/tests/Jellyfin.Server.Implementations.Tests/Library/PathExtensionsTests.cs
+++ b/tests/Jellyfin.Server.Implementations.Tests/Library/PathExtensionsTests.cs
@@ -33,6 +33,7 @@ namespace Jellyfin.Server.Implementations.Tests.Library
[InlineData("C:\\Users\\jeff\\myfile.mkv", "C:\\Users/jeff", "/home/jeff/", "/home/jeff/myfile.mkv")]
[InlineData("C:\\Users\\jeff\\myfile.mkv", "C:\\Users/jeff/", "/home/jeff/", "/home/jeff/myfile.mkv")]
[InlineData("C:\\Users\\jeff\\myfile.mkv", "C:\\Users/jeff/", "/", "/myfile.mkv")]
+ [InlineData("/o", "/o", "/s", "/s")] // regression test for #5977
public void TryReplaceSubPath_ValidArgs_Correct(string path, string subPath, string newSubPath, string? expectedResult)
{
Assert.True(PathExtensions.TryReplaceSubPath(path, subPath, newSubPath, out var result));
diff --git a/tests/Jellyfin.Server.Integration.Tests/Jellyfin.Server.Integration.Tests.csproj b/tests/Jellyfin.Server.Integration.Tests/Jellyfin.Server.Integration.Tests.csproj
index 8646b60b1..938385a2a 100644
--- a/tests/Jellyfin.Server.Integration.Tests/Jellyfin.Server.Integration.Tests.csproj
+++ b/tests/Jellyfin.Server.Integration.Tests/Jellyfin.Server.Integration.Tests.csproj
@@ -10,8 +10,8 @@
<ItemGroup>
<PackageReference Include="AutoFixture" Version="4.17.0" />
- <PackageReference Include="AutoFixture.AutoMoq" Version="4.16.0" />
- <PackageReference Include="AutoFixture.Xunit2" Version="4.16.0" />
+ <PackageReference Include="AutoFixture.AutoMoq" Version="4.17.0" />
+ <PackageReference Include="AutoFixture.Xunit2" Version="4.17.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="5.0.5" />
<PackageReference Include="Microsoft.Extensions.Options" Version="5.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.4" />
@@ -22,6 +22,13 @@
<PackageReference Include="Moq" Version="4.16.0" />
</ItemGroup>
+ <ItemGroup>
+ <!-- Don't run tests in parallel -->
+ <None Update="xunit.runner.json">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </None>
+ </ItemGroup>
+
<!-- Code Analyzers -->
<ItemGroup Condition=" '$(Configuration)' == 'Debug' ">
<PackageReference Include="SerilogAnalyzer" Version="0.15.0" PrivateAssets="All" />
diff --git a/tests/Jellyfin.Server.Integration.Tests/xunit.runner.json b/tests/Jellyfin.Server.Integration.Tests/xunit.runner.json
new file mode 100644
index 000000000..809e880c7
--- /dev/null
+++ b/tests/Jellyfin.Server.Integration.Tests/xunit.runner.json
@@ -0,0 +1,4 @@
+{
+ "parallelizeAssembly": false,
+ "parallelizeTestCollections": false
+}
diff --git a/tests/Jellyfin.Server.Tests/Jellyfin.Server.Tests.csproj b/tests/Jellyfin.Server.Tests/Jellyfin.Server.Tests.csproj
index 64383a2d9..72e40ebcb 100644
--- a/tests/Jellyfin.Server.Tests/Jellyfin.Server.Tests.csproj
+++ b/tests/Jellyfin.Server.Tests/Jellyfin.Server.Tests.csproj
@@ -11,8 +11,8 @@
<ItemGroup>
<PackageReference Include="AutoFixture" Version="4.17.0" />
- <PackageReference Include="AutoFixture.AutoMoq" Version="4.16.0" />
- <PackageReference Include="AutoFixture.Xunit2" Version="4.16.0" />
+ <PackageReference Include="AutoFixture.AutoMoq" Version="4.17.0" />
+ <PackageReference Include="AutoFixture.Xunit2" Version="4.17.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="5.0.5" />
<PackageReference Include="Microsoft.Extensions.Options" Version="5.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.4" />
diff --git a/tests/Jellyfin.XbmcMetadata.Tests/Parsers/MovieNfoParserTests.cs b/tests/Jellyfin.XbmcMetadata.Tests/Parsers/MovieNfoParserTests.cs
index b58151b3b..30a48857a 100644
--- a/tests/Jellyfin.XbmcMetadata.Tests/Parsers/MovieNfoParserTests.cs
+++ b/tests/Jellyfin.XbmcMetadata.Tests/Parsers/MovieNfoParserTests.cs
@@ -156,7 +156,7 @@ namespace Jellyfin.XbmcMetadata.Tests.Parsers
Assert.Equal("Justice League Collection", item.CollectionName);
// Images
- Assert.Equal(6, result.RemoteImages.Count);
+ Assert.Equal(7, result.RemoteImages.Count);
var posters = result.RemoteImages.Where(x => x.type == ImageType.Primary).ToList();
Assert.Single(posters);
@@ -182,6 +182,10 @@ namespace Jellyfin.XbmcMetadata.Tests.Parsers
Assert.Single(discArt);
Assert.Equal("https://assets.fanart.tv/fanart/movies/141052/moviedisc/justice-league-5a3af26360617.png", discArt[0].url);
+ var backdrop = result.RemoteImages.Where(x => x.type == ImageType.Backdrop).ToList();
+ Assert.Single(backdrop);
+ Assert.Equal("https://assets.fanart.tv/fanart/movies/141052/moviebackground/justice-league-5793f518c6d6e.jpg", backdrop[0].url);
+
// Local Image - contains only one item depending on operating system
Assert.Single(result.Images);
Assert.Equal(_localImageFileMetadata.Name, result.Images[0].FileInfo.Name);
diff --git a/tests/Jellyfin.XbmcMetadata.Tests/Test Data/Justice League.nfo b/tests/Jellyfin.XbmcMetadata.Tests/Test Data/Justice League.nfo
index b0c5e3c57..4e8c79dca 100644
--- a/tests/Jellyfin.XbmcMetadata.Tests/Test Data/Justice League.nfo
+++ b/tests/Jellyfin.XbmcMetadata.Tests/Test Data/Justice League.nfo
@@ -82,8 +82,8 @@
<thumb aspect="discart" preview="https://assets.fanart.tv/preview/movies/141052/moviedisc/justice-league-5a0b913c233be.png">https://assets.fanart.tv/fanart/movies/141052/moviedisc/justice-league-5a0b913c233be.png</thumb>
<thumb aspect="discart" preview="https://assets.fanart.tv/preview/movies/141052/moviedisc/justice-league-5a87e0cdb1209.png">https://assets.fanart.tv/fanart/movies/141052/moviedisc/justice-league-5a87e0cdb1209.png</thumb>
<thumb aspect="discart" preview="https://assets.fanart.tv/preview/movies/141052/moviedisc/justice-league-59dc595362ef1.png">https://assets.fanart.tv/fanart/movies/141052/moviedisc/justice-league-59dc595362ef1.png</thumb>
+ <thumb aspect="fanart">https://assets.fanart.tv/fanart/movies/141052/moviebackground/justice-league-5793f518c6d6e.jpg</thumb>
<fanart>
- <thumb preview="https://assets.fanart.tv/preview/movies/141052/moviebackground/justice-league-5793f518c6d6e.jpg">https://assets.fanart.tv/fanart/movies/141052/moviebackground/justice-league-5793f518c6d6e.jpg</thumb>
<thumb preview="https://assets.fanart.tv/preview/movies/141052/moviebackground/justice-league-5a5332c7b5e77.jpg">https://assets.fanart.tv/fanart/movies/141052/moviebackground/justice-league-5a5332c7b5e77.jpg</thumb>
<thumb preview="https://assets.fanart.tv/preview/movies/141052/moviebackground/justice-league-5a53cf2dac1c8.jpg">https://assets.fanart.tv/fanart/movies/141052/moviebackground/justice-league-5a53cf2dac1c8.jpg</thumb>
<thumb preview="https://assets.fanart.tv/preview/movies/141052/moviebackground/justice-league-5976ba93eb5d3.jpg">https://assets.fanart.tv/fanart/movies/141052/moviebackground/justice-league-5976ba93eb5d3.jpg</thumb>