aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLogicalPhallacy <44458166+LogicalPhallacy@users.noreply.github.com>2019-02-11 22:48:50 -0800
committerGitHub <noreply@github.com>2019-02-11 22:48:50 -0800
commit8bf88f4cb2ddb140baffd8e4542d8f528b482a67 (patch)
tree5f60f345a22c2468b504b925c0bf4785869185ae
parent4519ce26e2250cb233836296d292ddb7b3cf6346 (diff)
parenteb4b7051676b7493a57a99a821d5dd38bd9d4919 (diff)
Merge pull request #9 from jellyfin/master
Yanking in latest changes
-rw-r--r--CONTRIBUTORS.md1
-rw-r--r--Dockerfile4
-rw-r--r--Dockerfile.arm2
-rw-r--r--Dockerfile.arm642
-rw-r--r--Emby.Dlna/Api/DlnaServerService.cs4
-rw-r--r--Emby.Dlna/ContentDirectory/ControlHandler.cs6
-rw-r--r--Emby.Dlna/Didl/DidlBuilder.cs159
-rw-r--r--Emby.Dlna/DlnaManager.cs15
-rw-r--r--Emby.Dlna/Main/DlnaEntryPoint.cs17
-rw-r--r--Emby.Dlna/PlayTo/Device.cs247
-rw-r--r--Emby.Dlna/PlayTo/PlayToController.cs32
-rw-r--r--Emby.Dlna/PlayTo/PlayToManager.cs7
-rw-r--r--Emby.Dlna/Server/DescriptionXmlBuilder.cs146
-rw-r--r--Emby.Dlna/Ssdp/DeviceDiscovery.cs8
-rw-r--r--Emby.Drawing/ImageProcessor.cs39
-rw-r--r--Emby.Drawing/NullImageEncoder.cs15
-rw-r--r--Emby.IsoMounting/IsoMounter/LinuxIsoManager.cs7
-rw-r--r--Emby.Notifications/CoreNotificationTypes.cs10
-rw-r--r--Emby.Notifications/Notifications.cs13
-rw-r--r--Emby.Photos/PhotoProvider.cs2
-rw-r--r--Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs13
-rw-r--r--Emby.Server.Implementations/AppBase/BaseApplicationPaths.cs4
-rw-r--r--Emby.Server.Implementations/AppBase/BaseConfigurationManager.cs21
-rw-r--r--Emby.Server.Implementations/ApplicationHost.cs76
-rw-r--r--Emby.Server.Implementations/Collections/CollectionImageProvider.cs3
-rw-r--r--Emby.Server.Implementations/Collections/CollectionManager.cs2
-rw-r--r--Emby.Server.Implementations/Data/SqliteItemRepository.cs33
-rw-r--r--Emby.Server.Implementations/Devices/DeviceManager.cs2
-rw-r--r--Emby.Server.Implementations/Diagnostics/CommonProcess.cs2
-rw-r--r--Emby.Server.Implementations/Dto/DtoService.cs40
-rw-r--r--Emby.Server.Implementations/Emby.Server.Implementations.csproj7
-rw-r--r--Emby.Server.Implementations/EntryPoints/AutomaticRestartEntryPoint.cs13
-rw-r--r--Emby.Server.Implementations/EntryPoints/ExternalPortForwarding.cs17
-rw-r--r--Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs35
-rw-r--r--Emby.Server.Implementations/EntryPoints/RecordingNotifier.cs5
-rw-r--r--Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs5
-rw-r--r--Emby.Server.Implementations/EntryPoints/StartupWizard.cs9
-rw-r--r--Emby.Server.Implementations/EntryPoints/UdpServerEntryPoint.cs5
-rw-r--r--Emby.Server.Implementations/EntryPoints/UserDataChangeNotifier.cs16
-rw-r--r--Emby.Server.Implementations/FFMpeg/FFMpegLoader.cs6
-rw-r--r--Emby.Server.Implementations/HttpClientManager/HttpClientManager.cs6
-rw-r--r--Emby.Server.Implementations/HttpServer/HttpResultFactory.cs2
-rw-r--r--Emby.Server.Implementations/IO/FileRefresher.cs14
-rw-r--r--Emby.Server.Implementations/IO/LibraryMonitor.cs31
-rw-r--r--Emby.Server.Implementations/IStartupOptions.cs40
-rw-r--r--Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs2
-rw-r--r--Emby.Server.Implementations/Library/LibraryManager.cs28
-rw-r--r--Emby.Server.Implementations/Library/MediaSourceManager.cs20
-rw-r--r--Emby.Server.Implementations/Library/Resolvers/PhotoResolver.cs7
-rw-r--r--Emby.Server.Implementations/Library/SearchEngine.cs2
-rw-r--r--Emby.Server.Implementations/Library/UserManager.cs74
-rw-r--r--Emby.Server.Implementations/Library/UserViewManager.cs4
-rw-r--r--Emby.Server.Implementations/Library/Validators/GameGenresPostScanTask.cs45
-rw-r--r--Emby.Server.Implementations/Library/Validators/GameGenresValidator.cs72
-rw-r--r--Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs25
-rw-r--r--Emby.Server.Implementations/LiveTv/EmbyTV/EntryPoint.cs5
-rw-r--r--Emby.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs10
-rw-r--r--Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs2
-rw-r--r--Emby.Server.Implementations/LiveTv/LiveTvDtoService.cs8
-rw-r--r--Emby.Server.Implementations/LiveTv/LiveTvManager.cs35
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs2
-rw-r--r--Emby.Server.Implementations/Localization/Core/ar.json3
-rw-r--r--Emby.Server.Implementations/Localization/Core/bg-BG.json3
-rw-r--r--Emby.Server.Implementations/Localization/Core/ca.json3
-rw-r--r--Emby.Server.Implementations/Localization/Core/cs.json3
-rw-r--r--Emby.Server.Implementations/Localization/Core/da.json3
-rw-r--r--Emby.Server.Implementations/Localization/Core/de.json3
-rw-r--r--Emby.Server.Implementations/Localization/Core/el.json3
-rw-r--r--Emby.Server.Implementations/Localization/Core/en-GB.json3
-rw-r--r--Emby.Server.Implementations/Localization/Core/en-US.json3
-rw-r--r--Emby.Server.Implementations/Localization/Core/es-AR.json3
-rw-r--r--Emby.Server.Implementations/Localization/Core/es-MX.json3
-rw-r--r--Emby.Server.Implementations/Localization/Core/es.json3
-rw-r--r--Emby.Server.Implementations/Localization/Core/fa.json3
-rw-r--r--Emby.Server.Implementations/Localization/Core/fr-CA.json3
-rw-r--r--Emby.Server.Implementations/Localization/Core/fr.json3
-rw-r--r--Emby.Server.Implementations/Localization/Core/gsw.json3
-rw-r--r--Emby.Server.Implementations/Localization/Core/he.json3
-rw-r--r--Emby.Server.Implementations/Localization/Core/hr.json3
-rw-r--r--Emby.Server.Implementations/Localization/Core/hu.json3
-rw-r--r--Emby.Server.Implementations/Localization/Core/it.json3
-rw-r--r--Emby.Server.Implementations/Localization/Core/kk.json3
-rw-r--r--Emby.Server.Implementations/Localization/Core/ko.json3
-rw-r--r--Emby.Server.Implementations/Localization/Core/lt-LT.json3
-rw-r--r--Emby.Server.Implementations/Localization/Core/ms.json3
-rw-r--r--Emby.Server.Implementations/Localization/Core/nb.json3
-rw-r--r--Emby.Server.Implementations/Localization/Core/nl.json3
-rw-r--r--Emby.Server.Implementations/Localization/Core/pl.json3
-rw-r--r--Emby.Server.Implementations/Localization/Core/pt-BR.json3
-rw-r--r--Emby.Server.Implementations/Localization/Core/pt-PT.json3
-rw-r--r--Emby.Server.Implementations/Localization/Core/ru.json3
-rw-r--r--Emby.Server.Implementations/Localization/Core/sk.json3
-rw-r--r--Emby.Server.Implementations/Localization/Core/sl-SI.json3
-rw-r--r--Emby.Server.Implementations/Localization/Core/sv.json3
-rw-r--r--Emby.Server.Implementations/Localization/Core/tr.json3
-rw-r--r--Emby.Server.Implementations/Localization/Core/zh-CN.json3
-rw-r--r--Emby.Server.Implementations/Localization/Core/zh-HK.json3
-rw-r--r--Emby.Server.Implementations/Localization/LocalizationManager.cs317
-rw-r--r--Emby.Server.Implementations/Localization/Ratings/br.csv (renamed from Emby.Server.Implementations/Localization/Ratings/br.txt)0
-rw-r--r--Emby.Server.Implementations/Localization/Ratings/ca.csv (renamed from Emby.Server.Implementations/Localization/Ratings/ca.txt)0
-rw-r--r--Emby.Server.Implementations/Localization/Ratings/co.csv (renamed from Emby.Server.Implementations/Localization/Ratings/co.txt)0
-rw-r--r--Emby.Server.Implementations/Localization/Ratings/dk.csv (renamed from Emby.Server.Implementations/Localization/Ratings/dk.txt)0
-rw-r--r--Emby.Server.Implementations/Localization/Ratings/es.csv (renamed from Emby.Server.Implementations/Localization/Ratings/es.txt)0
-rw-r--r--Emby.Server.Implementations/Localization/Ratings/fr.csv (renamed from Emby.Server.Implementations/Localization/Ratings/fr.txt)0
-rw-r--r--Emby.Server.Implementations/Localization/Ratings/gb.csv (renamed from Emby.Server.Implementations/Localization/Ratings/gb.txt)0
-rw-r--r--Emby.Server.Implementations/Localization/Ratings/ie.csv (renamed from Emby.Server.Implementations/Localization/Ratings/ie.txt)0
-rw-r--r--Emby.Server.Implementations/Localization/Ratings/jp.csv (renamed from Emby.Server.Implementations/Localization/Ratings/jp.txt)0
-rw-r--r--Emby.Server.Implementations/Localization/Ratings/kz.csv (renamed from Emby.Server.Implementations/Localization/Ratings/kz.txt)0
-rw-r--r--Emby.Server.Implementations/Localization/Ratings/mx.csv (renamed from Emby.Server.Implementations/Localization/Ratings/mx.txt)0
-rw-r--r--Emby.Server.Implementations/Localization/Ratings/nl.csv (renamed from Emby.Server.Implementations/Localization/Ratings/nl.txt)0
-rw-r--r--Emby.Server.Implementations/Localization/Ratings/nz.csv (renamed from Emby.Server.Implementations/Localization/Ratings/nz.txt)0
-rw-r--r--Emby.Server.Implementations/Localization/Ratings/ro.csv (renamed from Emby.Server.Implementations/Localization/Ratings/ro.txt)0
-rw-r--r--Emby.Server.Implementations/Localization/Ratings/uk.csv (renamed from Emby.Server.Implementations/Localization/Ratings/uk.txt)0
-rw-r--r--Emby.Server.Implementations/Localization/Ratings/us.csv (renamed from Emby.Server.Implementations/Localization/Ratings/us.txt)0
-rw-r--r--Emby.Server.Implementations/Localization/TextLocalizer.cs63
-rw-r--r--Emby.Server.Implementations/Localization/iso6392.txt1
-rw-r--r--Emby.Server.Implementations/Networking/IPNetwork/BigIntegerExt.cs9
-rw-r--r--Emby.Server.Implementations/Networking/IPNetwork/IPAddressCollection.cs6
-rw-r--r--Emby.Server.Implementations/Networking/IPNetwork/IPNetwork.cs22
-rw-r--r--Emby.Server.Implementations/Networking/IPNetwork/IPNetworkCollection.cs7
-rw-r--r--Emby.Server.Implementations/Networking/NetworkManager.cs8
-rw-r--r--Emby.Server.Implementations/Playlists/PlaylistImageProvider.cs4
-rw-r--r--Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs1
-rw-r--r--Emby.Server.Implementations/ScheduledTasks/TaskManager.cs43
-rw-r--r--Emby.Server.Implementations/ScheduledTasks/Tasks/ChapterImagesTask.cs (renamed from Emby.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs)22
-rw-r--r--Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs22
-rw-r--r--Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteLogFileTask.cs22
-rw-r--r--Emby.Server.Implementations/ScheduledTasks/Tasks/PeopleValidationTask.cs (renamed from Emby.Server.Implementations/ScheduledTasks/PeopleValidationTask.cs)22
-rw-r--r--Emby.Server.Implementations/ScheduledTasks/Tasks/PluginUpdateTask.cs119
-rw-r--r--Emby.Server.Implementations/ScheduledTasks/Tasks/RefreshMediaLibraryTask.cs (renamed from Emby.Server.Implementations/ScheduledTasks/RefreshMediaLibraryTask.cs)18
-rw-r--r--Emby.Server.Implementations/ScheduledTasks/Triggers/DailyTrigger.cs (renamed from Emby.Server.Implementations/ScheduledTasks/DailyTrigger.cs)0
-rw-r--r--Emby.Server.Implementations/ScheduledTasks/Triggers/IntervalTrigger.cs (renamed from Emby.Server.Implementations/ScheduledTasks/IntervalTrigger.cs)0
-rw-r--r--Emby.Server.Implementations/ScheduledTasks/Triggers/StartupTrigger.cs (renamed from Emby.Server.Implementations/ScheduledTasks/StartupTrigger.cs)0
-rw-r--r--Emby.Server.Implementations/ScheduledTasks/Triggers/WeeklyTrigger.cs (renamed from Emby.Server.Implementations/ScheduledTasks/WeeklyTrigger.cs)0
-rw-r--r--Emby.Server.Implementations/Serialization/JsonSerializer.cs3
-rw-r--r--Emby.Server.Implementations/ServerApplicationPaths.cs15
-rw-r--r--Emby.Server.Implementations/Services/RequestHelper.cs2
-rw-r--r--Emby.Server.Implementations/Services/ResponseHelper.cs2
-rw-r--r--Emby.Server.Implementations/Services/ServiceExec.cs4
-rw-r--r--Emby.Server.Implementations/Services/ServiceMethod.cs2
-rw-r--r--Emby.Server.Implementations/Services/ServicePath.cs10
-rw-r--r--Emby.Server.Implementations/Services/SwaggerService.cs28
-rw-r--r--Emby.Server.Implementations/Session/SessionManager.cs14
-rw-r--r--Emby.Server.Implementations/Sorting/GameSystemComparer.cs51
-rw-r--r--Emby.Server.Implementations/Sorting/PlayersComparer.cs43
-rw-r--r--Emby.Server.Implementations/StartupOptions.cs30
-rw-r--r--Emby.Server.Implementations/Threading/CommonTimer.cs36
-rw-r--r--Emby.Server.Implementations/Threading/TimerFactory.cs18
-rw-r--r--Emby.Server.Implementations/Updates/InstallationManager.cs12
-rw-r--r--Emby.Server.Implementations/UserViews/CollectionFolderImageProvider.cs4
-rw-r--r--Emby.Server.Implementations/UserViews/DynamicImageProvider.cs4
-rw-r--r--Emby.Server.Implementations/UserViews/FolderImageProvider.cs2
-rw-r--r--Jellyfin.Drawing.Skia/SkiaEncoder.cs13
-rw-r--r--Jellyfin.Drawing.Skia/StripCollageBuilder.cs2
-rw-r--r--Jellyfin.Server/CoreAppHost.cs4
-rw-r--r--Jellyfin.Server/Jellyfin.Server.csproj6
-rw-r--r--Jellyfin.Server/Program.cs88
-rw-r--r--Jellyfin.Server/SocketSharp/HttpFile.cs2
-rw-r--r--Jellyfin.Server/SocketSharp/RequestMono.cs86
-rw-r--r--Jellyfin.Server/SocketSharp/SharpWebSocket.cs2
-rw-r--r--Jellyfin.Server/SocketSharp/WebSocketSharpListener.cs2
-rw-r--r--Jellyfin.Server/SocketSharp/WebSocketSharpRequest.cs84
-rw-r--r--Jellyfin.Server/SocketSharp/WebSocketSharpResponse.cs2
-rw-r--r--Jellyfin.Server/StartupOptions.cs44
-rw-r--r--MediaBrowser.Api/ApiEntryPoint.cs128
-rw-r--r--MediaBrowser.Api/BaseApiService.cs41
-rw-r--r--MediaBrowser.Api/FilterService.cs10
-rw-r--r--MediaBrowser.Api/GamesService.cs140
-rw-r--r--MediaBrowser.Api/Images/ImageByNameService.cs2
-rw-r--r--MediaBrowser.Api/Images/ImageService.cs6
-rw-r--r--MediaBrowser.Api/ItemLookupService.cs13
-rw-r--r--MediaBrowser.Api/ItemUpdateService.cs12
-rw-r--r--MediaBrowser.Api/Library/LibraryService.cs20
-rw-r--r--MediaBrowser.Api/LiveTv/LiveTvService.cs4
-rw-r--r--MediaBrowser.Api/LocalizationService.cs5
-rw-r--r--MediaBrowser.Api/Movies/MoviesService.cs6
-rw-r--r--MediaBrowser.Api/PackageService.cs2
-rw-r--r--MediaBrowser.Api/Playback/BaseStreamingService.cs97
-rw-r--r--MediaBrowser.Api/Playback/Hls/BaseHlsService.cs39
-rw-r--r--MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs31
-rw-r--r--MediaBrowser.Api/Playback/Hls/HlsSegmentService.cs4
-rw-r--r--MediaBrowser.Api/Playback/Hls/VideoHlsService.cs31
-rw-r--r--MediaBrowser.Api/Playback/Progressive/AudioService.cs28
-rw-r--r--MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs29
-rw-r--r--MediaBrowser.Api/Playback/Progressive/VideoService.cs28
-rw-r--r--MediaBrowser.Api/Playback/TranscodingThrottler.cs29
-rw-r--r--MediaBrowser.Api/Playback/UniversalAudioService.cs3
-rw-r--r--MediaBrowser.Api/Session/SessionsService.cs2
-rw-r--r--MediaBrowser.Api/StartupWizardService.cs16
-rw-r--r--MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs1
-rw-r--r--MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs6
-rw-r--r--MediaBrowser.Api/UserLibrary/GameGenresService.cs105
-rw-r--r--MediaBrowser.Api/UserLibrary/GenresService.cs5
-rw-r--r--MediaBrowser.Api/UserLibrary/ItemsService.cs2
-rw-r--r--MediaBrowser.Api/UserLibrary/PlaystateService.cs22
-rw-r--r--MediaBrowser.Api/UserService.cs6
-rw-r--r--MediaBrowser.Common/IApplicationHost.cs4
-rw-r--r--MediaBrowser.Controller/Connect/UserLinkResult.cs9
-rw-r--r--MediaBrowser.Controller/Drawing/IImageEncoder.cs5
-rw-r--r--MediaBrowser.Controller/Drawing/IImageProcessor.cs29
-rw-r--r--MediaBrowser.Controller/Entities/BaseItem.cs4
-rw-r--r--MediaBrowser.Controller/Entities/CollectionFolder.cs6
-rw-r--r--MediaBrowser.Controller/Entities/Folder.cs10
-rw-r--r--MediaBrowser.Controller/Entities/Game.cs113
-rw-r--r--MediaBrowser.Controller/Entities/GameGenre.cs109
-rw-r--r--MediaBrowser.Controller/Entities/GameSystem.cs77
-rw-r--r--MediaBrowser.Controller/Entities/Genre.cs2
-rw-r--r--MediaBrowser.Controller/Entities/InternalItemsQuery.cs3
-rw-r--r--MediaBrowser.Controller/Entities/TV/Series.cs2
-rw-r--r--MediaBrowser.Controller/Entities/User.cs6
-rw-r--r--MediaBrowser.Controller/Entities/UserView.cs1
-rw-r--r--MediaBrowser.Controller/Entities/UserViewBuilder.cs46
-rw-r--r--MediaBrowser.Controller/Entities/Video.cs2
-rw-r--r--MediaBrowser.Controller/Extensions/StringExtensions.cs46
-rw-r--r--MediaBrowser.Controller/IServerApplicationPaths.cs6
-rw-r--r--MediaBrowser.Controller/Library/ILibraryManager.cs10
-rw-r--r--MediaBrowser.Controller/Library/NameExtensions.cs8
-rw-r--r--MediaBrowser.Controller/LiveTv/ILiveTvService.cs5
-rw-r--r--MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs16
-rw-r--r--MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs124
-rw-r--r--MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs22
-rw-r--r--MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs19
-rw-r--r--MediaBrowser.Controller/Persistence/IItemRepository.cs2
-rw-r--r--MediaBrowser.Controller/Plugins/IServerEntryPoint.cs3
-rw-r--r--MediaBrowser.Controller/Providers/GameInfo.cs11
-rw-r--r--MediaBrowser.Controller/Providers/GameSystemInfo.cs11
-rw-r--r--MediaBrowser.Controller/Session/SessionInfo.cs8
-rw-r--r--MediaBrowser.LocalMetadata/Images/LocalImageProvider.cs18
-rw-r--r--MediaBrowser.LocalMetadata/Parsers/GameSystemXmlParser.cs66
-rw-r--r--MediaBrowser.LocalMetadata/Parsers/GameXmlParser.cs85
-rw-r--r--MediaBrowser.LocalMetadata/Providers/GameSystemXmlProvider.cs36
-rw-r--r--MediaBrowser.LocalMetadata/Providers/GameXmlProvider.cs39
-rw-r--r--MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs6
-rw-r--r--MediaBrowser.LocalMetadata/Savers/GameSystemXmlSaver.cs48
-rw-r--r--MediaBrowser.LocalMetadata/Savers/GameXmlSaver.cs68
-rw-r--r--MediaBrowser.LocalMetadata/Savers/PersonXmlSaver.cs47
-rw-r--r--MediaBrowser.MediaEncoding/Encoder/AudioEncoder.cs58
-rw-r--r--MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs372
-rw-r--r--MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs149
-rw-r--r--MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs307
-rw-r--r--MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs43
-rw-r--r--MediaBrowser.MediaEncoding/Encoder/VideoEncoder.cs59
-rw-r--r--MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs24
-rw-r--r--MediaBrowser.Model/Channels/ChannelMediaContentType.cs4
-rw-r--r--MediaBrowser.Model/Configuration/UnratedItem.cs1
-rw-r--r--MediaBrowser.Model/Connect/ConnectAuthorization.cs21
-rw-r--r--MediaBrowser.Model/Connect/ConnectUser.cs11
-rw-r--r--MediaBrowser.Model/Connect/ConnectUserQuery.cs10
-rw-r--r--MediaBrowser.Model/Connect/UserLinkType.cs14
-rw-r--r--MediaBrowser.Model/Dlna/StreamInfo.cs22
-rw-r--r--MediaBrowser.Model/Drawing/ImageDimensions.cs (renamed from MediaBrowser.Model/Drawing/ImageSize.cs)2
-rw-r--r--MediaBrowser.Model/Dto/BaseItemDto.cs13
-rw-r--r--MediaBrowser.Model/Dto/GameSystemSummary.cs48
-rw-r--r--MediaBrowser.Model/Dto/ItemCounts.cs10
-rw-r--r--MediaBrowser.Model/Dto/UserDto.cs17
-rw-r--r--MediaBrowser.Model/Entities/CollectionType.cs1
-rw-r--r--MediaBrowser.Model/Entities/MediaStream.cs6
-rw-r--r--MediaBrowser.Model/Entities/MediaType.cs4
-rw-r--r--MediaBrowser.Model/Entities/MetadataProviders.cs1
-rw-r--r--MediaBrowser.Model/Extensions/LinqExtensions.cs85
-rw-r--r--MediaBrowser.Model/Extensions/StringHelper.cs2
-rw-r--r--MediaBrowser.Model/Globalization/ILocalizationManager.cs8
-rw-r--r--MediaBrowser.Model/MediaInfo/AudioCodec.cs9
-rw-r--r--MediaBrowser.Model/Net/MimeTypes.cs2
-rw-r--r--MediaBrowser.Model/Notifications/NotificationType.cs2
-rw-r--r--MediaBrowser.Model/Providers/RemoteSearchResult.cs2
-rw-r--r--MediaBrowser.Model/Querying/ItemSortBy.cs2
-rw-r--r--MediaBrowser.Model/Threading/ITimer.cs10
-rw-r--r--MediaBrowser.Model/Threading/ITimerFactory.cs10
-rw-r--r--MediaBrowser.Providers/GameGenres/GameGenreMetadataService.cs23
-rw-r--r--MediaBrowser.Providers/Games/GameMetadataService.cs36
-rw-r--r--MediaBrowser.Providers/Games/GameSystemMetadataService.cs31
-rw-r--r--MediaBrowser.Providers/Manager/GenericPriorityQueue.cs1
-rw-r--r--MediaBrowser.Providers/Manager/ImageSaver.cs4
-rw-r--r--MediaBrowser.Providers/Manager/ItemImageProvider.cs2
-rw-r--r--MediaBrowser.Providers/Manager/MetadataService.cs3
-rw-r--r--MediaBrowser.Providers/Manager/ProviderManager.cs2
-rw-r--r--MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs15
-rw-r--r--MediaBrowser.Providers/MediaInfo/SubtitleResolver.cs2
-rw-r--r--MediaBrowser.Providers/MediaInfo/SubtitleScheduledTask.cs18
-rw-r--r--MediaBrowser.Providers/Movies/FanartMovieImageProvider.cs1
-rw-r--r--MediaBrowser.Providers/Movies/MovieDbProvider.cs2
-rw-r--r--MediaBrowser.Providers/Movies/MovieDbSearch.cs2
-rw-r--r--MediaBrowser.Providers/Music/FanArtArtistProvider.cs1
-rw-r--r--MediaBrowser.Providers/People/TvdbPersonImageProvider.cs1
-rw-r--r--MediaBrowser.Providers/Subtitles/SubtitleManager.cs6
-rw-r--r--MediaBrowser.Providers/TV/FanArt/FanArtSeasonProvider.cs2
-rw-r--r--MediaBrowser.Providers/TV/FanArt/FanartSeriesProvider.cs2
-rw-r--r--MediaBrowser.Providers/TV/MissingEpisodeProvider.cs1
-rw-r--r--MediaBrowser.Providers/TV/Omdb/OmdbEpisodeProvider.cs2
-rw-r--r--MediaBrowser.Providers/TV/TheMovieDb/MovieDbEpisodeImageProvider.cs2
-rw-r--r--MediaBrowser.Providers/TV/TheMovieDb/MovieDbEpisodeProvider.cs2
-rw-r--r--MediaBrowser.Providers/TV/TheMovieDb/MovieDbProviderBase.cs2
-rw-r--r--MediaBrowser.Providers/TV/TheMovieDb/MovieDbSeasonProvider.cs2
-rw-r--r--MediaBrowser.Providers/TV/TheMovieDb/MovieDbSeriesImageProvider.cs2
-rw-r--r--MediaBrowser.Providers/TV/TheMovieDb/MovieDbSeriesProvider.cs2
-rw-r--r--MediaBrowser.Providers/TV/TheTVDB/TvdbEpisodeImageProvider.cs2
-rw-r--r--MediaBrowser.Providers/TV/TheTVDB/TvdbEpisodeProvider.cs2
-rw-r--r--MediaBrowser.Providers/TV/TheTVDB/TvdbPrescanTask.cs2
-rw-r--r--MediaBrowser.Providers/TV/TheTVDB/TvdbSeasonImageProvider.cs2
-rw-r--r--MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesImageProvider.cs2
-rw-r--r--MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesProvider.cs8
-rw-r--r--MediaBrowser.Providers/TV/TvExternalIds.cs1
-rw-r--r--MediaBrowser.WebDashboard/Api/DashboardService.cs6
-rw-r--r--MediaBrowser.WebDashboard/ServerEntryPoint.cs5
-rw-r--r--MediaBrowser.XbmcMetadata/EntryPoint.cs5
-rw-r--r--MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs33
-rw-r--r--README.md24
-rw-r--r--RSSDP/SsdpDeviceLocator.cs9
-rw-r--r--RSSDP/SsdpDevicePublisher.cs9
-rw-r--r--SocketHttpListener/Ext.cs2
-rw-r--r--SocketHttpListener/Net/HttpListenerRequest.cs2
-rwxr-xr-xbuild24
-rwxr-xr-xbump_version3
-rw-r--r--deployment/README.md2
-rw-r--r--deployment/centos-package-x64/Dockerfile27
-rwxr-xr-xdeployment/centos-package-x64/clean.sh34
-rw-r--r--deployment/centos-package-x64/dependencies.txt1
-rwxr-xr-xdeployment/centos-package-x64/docker-build.sh20
-rwxr-xr-xdeployment/centos-package-x64/package.sh80
l---------deployment/centos-package-x64/pkg-src1
-rw-r--r--deployment/debian-package-x64/Dockerfile32
-rwxr-xr-xdeployment/debian-package-x64/clean.sh26
-rwxr-xr-xdeployment/debian-package-x64/docker-build.sh19
-rwxr-xr-xdeployment/debian-package-x64/package.sh54
-rw-r--r--deployment/debian-package-x64/pkg-src/bin/restart.sh10
-rw-r--r--deployment/debian-package-x64/pkg-src/conf/jellyfin23
-rw-r--r--deployment/debian-package-x64/pkg-src/conf/jellyfin-sudoers (renamed from deployment/debian-package-x64/pkg-src/bin/jellyfin-sudoers)24
-rw-r--r--deployment/debian-package-x64/pkg-src/install2
-rw-r--r--deployment/debian-package-x64/pkg-src/jellyfin.service2
-rw-r--r--deployment/debian-package-x64/pkg-src/postinst11
-rw-r--r--deployment/debian-package-x64/pkg-src/postrm8
-rw-r--r--deployment/debian-package-x64/pkg-src/preinst8
-rw-r--r--deployment/debian-package-x64/pkg-src/prerm3
-rw-r--r--deployment/fedora-package-x64/Dockerfile40
-rwxr-xr-xdeployment/fedora-package-x64/clean.sh42
-rwxr-xr-xdeployment/fedora-package-x64/docker-build.sh20
-rwxr-xr-xdeployment/fedora-package-x64/package.sh76
-rw-r--r--deployment/fedora-package-x64/pkg-src/jellyfin.env20
-rw-r--r--deployment/fedora-package-x64/pkg-src/jellyfin.service2
-rw-r--r--deployment/fedora-package-x64/pkg-src/jellyfin.spec33
-rw-r--r--deployment/fedora-package-x64/pkg-src/jellyfin.sudoers14
-rw-r--r--deployment/ubuntu-package-x64/Dockerfile21
-rwxr-xr-xdeployment/ubuntu-package-x64/clean.sh29
-rw-r--r--deployment/ubuntu-package-x64/dependencies.txt1
-rwxr-xr-xdeployment/ubuntu-package-x64/docker-build.sh19
-rwxr-xr-xdeployment/ubuntu-package-x64/package.sh31
l---------deployment/ubuntu-package-x64/pkg-src1
-rw-r--r--deployment/win-generic/install-jellyfin.ps110
349 files changed, 2455 insertions, 4848 deletions
diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md
index eca16ad38..5e3455fba 100644
--- a/CONTRIBUTORS.md
+++ b/CONTRIBUTORS.md
@@ -15,6 +15,7 @@
- [cvium](https://github.com/cvium)
- [wtayl0r](https://github.com/wtayl0r)
- [TtheCreator](https://github.com/Tthecreator)
+ - [dkanada](https://github.com/dkanada)
- [LogicalPhallacy](https://github.com/LogicalPhallacy/)
- [RazeLighter777](https://github.com/RazeLighter777)
diff --git a/Dockerfile b/Dockerfile
index c79d6f8ee..266b59f1c 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -10,7 +10,7 @@ RUN export DOTNET_CLI_TELEMETRY_OPTOUT=1 \
--output /jellyfin \
Jellyfin.Server
-FROM jrottenberg/ffmpeg:4.0-scratch as ffmpeg
+FROM jrottenberg/ffmpeg:4.0-vaapi as ffmpeg
FROM microsoft/dotnet:${DOTNET_VERSION}-runtime
# libfontconfig1 is required for Skia
RUN apt-get update \
@@ -23,4 +23,4 @@ COPY --from=ffmpeg / /
COPY --from=builder /jellyfin /jellyfin
EXPOSE 8096
VOLUME /config /media
-ENTRYPOINT dotnet /jellyfin/jellyfin.dll -programdata /config
+ENTRYPOINT dotnet /jellyfin/jellyfin.dll --datadir /config
diff --git a/Dockerfile.arm b/Dockerfile.arm
index 657cb4ac6..039274197 100644
--- a/Dockerfile.arm
+++ b/Dockerfile.arm
@@ -21,4 +21,4 @@ RUN apt-get update \
COPY --from=builder /jellyfin /jellyfin
EXPOSE 8096
VOLUME /config /media
-ENTRYPOINT dotnet /jellyfin/jellyfin.dll -programdata /config
+ENTRYPOINT dotnet /jellyfin/jellyfin.dll --datadir /config
diff --git a/Dockerfile.arm64 b/Dockerfile.arm64
index 979dfc1dc..06ba21b91 100644
--- a/Dockerfile.arm64
+++ b/Dockerfile.arm64
@@ -30,4 +30,4 @@ COPY --from=qemu_extract qemu-* /usr/bin
COPY --from=builder /jellyfin /jellyfin
EXPOSE 8096
VOLUME /config /media
-ENTRYPOINT dotnet /jellyfin/jellyfin.dll -programdata /config
+ENTRYPOINT dotnet /jellyfin/jellyfin.dll --datadir /config
diff --git a/Emby.Dlna/Api/DlnaServerService.cs b/Emby.Dlna/Api/DlnaServerService.cs
index 01c9fe50f..68bf80163 100644
--- a/Emby.Dlna/Api/DlnaServerService.cs
+++ b/Emby.Dlna/Api/DlnaServerService.cs
@@ -236,7 +236,9 @@ namespace Emby.Dlna.Api
public object Get(GetIcon request)
{
- var contentType = "image/" + Path.GetExtension(request.Filename).TrimStart('.').ToLower();
+ var contentType = "image/" + Path.GetExtension(request.Filename)
+ .TrimStart('.')
+ .ToLowerInvariant();
var cacheLength = TimeSpan.FromDays(365);
var cacheKey = Request.RawUrl.GetMD5();
diff --git a/Emby.Dlna/ContentDirectory/ControlHandler.cs b/Emby.Dlna/ContentDirectory/ControlHandler.cs
index 2d8bb87f9..1150afdba 100644
--- a/Emby.Dlna/ContentDirectory/ControlHandler.cs
+++ b/Emby.Dlna/ContentDirectory/ControlHandler.cs
@@ -63,7 +63,7 @@ namespace Emby.Dlna.ContentDirectory
_profile = profile;
_config = config;
- _didlBuilder = new DidlBuilder(profile, user, imageProcessor, serverAddress, accessToken, userDataManager, localization, mediaSourceManager, _logger, libraryManager, mediaEncoder);
+ _didlBuilder = new DidlBuilder(profile, user, imageProcessor, serverAddress, accessToken, userDataManager, localization, mediaSourceManager, _logger, mediaEncoder);
}
protected override IEnumerable<KeyValuePair<string, string>> GetResult(string methodName, IDictionary<string, string> methodParams)
@@ -454,7 +454,7 @@ namespace Emby.Dlna.ContentDirectory
User = user,
Recursive = true,
IsMissing = false,
- ExcludeItemTypes = new[] { typeof(Game).Name, typeof(Book).Name },
+ ExcludeItemTypes = new[] { typeof(Book).Name },
IsFolder = isFolder,
MediaTypes = mediaTypes.ToArray(),
DtoOptions = GetDtoOptions()
@@ -523,7 +523,7 @@ namespace Emby.Dlna.ContentDirectory
Limit = limit,
StartIndex = startIndex,
IsVirtualItem = false,
- ExcludeItemTypes = new[] { typeof(Game).Name, typeof(Book).Name },
+ ExcludeItemTypes = new[] { typeof(Book).Name },
IsPlaceHolder = false,
DtoOptions = GetDtoOptions()
};
diff --git a/Emby.Dlna/Didl/DidlBuilder.cs b/Emby.Dlna/Didl/DidlBuilder.cs
index e4a9cbfc6..605f4f37b 100644
--- a/Emby.Dlna/Didl/DidlBuilder.cs
+++ b/Emby.Dlna/Didl/DidlBuilder.cs
@@ -43,22 +43,30 @@ namespace Emby.Dlna.Didl
private readonly ILocalizationManager _localization;
private readonly IMediaSourceManager _mediaSourceManager;
private readonly ILogger _logger;
- private readonly ILibraryManager _libraryManager;
private readonly IMediaEncoder _mediaEncoder;
- public DidlBuilder(DeviceProfile profile, User user, IImageProcessor imageProcessor, string serverAddress, string accessToken, IUserDataManager userDataManager, ILocalizationManager localization, IMediaSourceManager mediaSourceManager, ILogger logger, ILibraryManager libraryManager, IMediaEncoder mediaEncoder)
+ public DidlBuilder(
+ DeviceProfile profile,
+ User user,
+ IImageProcessor imageProcessor,
+ string serverAddress,
+ string accessToken,
+ IUserDataManager userDataManager,
+ ILocalizationManager localization,
+ IMediaSourceManager mediaSourceManager,
+ ILogger logger,
+ IMediaEncoder mediaEncoder)
{
_profile = profile;
+ _user = user;
_imageProcessor = imageProcessor;
_serverAddress = serverAddress;
+ _accessToken = accessToken;
_userDataManager = userDataManager;
_localization = localization;
_mediaSourceManager = mediaSourceManager;
_logger = logger;
- _libraryManager = libraryManager;
_mediaEncoder = mediaEncoder;
- _accessToken = accessToken;
- _user = user;
}
public static string NormalizeDlnaMediaUrl(string url)
@@ -117,7 +125,8 @@ namespace Emby.Dlna.Didl
}
}
- public void WriteItemElement(DlnaOptions options,
+ public void WriteItemElement(
+ DlnaOptions options,
XmlWriter writer,
BaseItem item,
User user,
@@ -232,12 +241,15 @@ namespace Emby.Dlna.Didl
AddVideoResource(writer, video, deviceId, filter, contentFeature, streamInfo);
}
- var subtitleProfiles = streamInfo.GetSubtitleProfiles(_mediaEncoder, false, _serverAddress, _accessToken)
- .Where(subtitle => subtitle.DeliveryMethod == SubtitleDeliveryMethod.External)
- .ToList();
+ var subtitleProfiles = streamInfo.GetSubtitleProfiles(_mediaEncoder, false, _serverAddress, _accessToken);
foreach (var subtitle in subtitleProfiles)
{
+ if (subtitle.DeliveryMethod != SubtitleDeliveryMethod.External)
+ {
+ continue;
+ }
+
var subtitleAdded = AddSubtitleElement(writer, subtitle);
if (subtitleAdded && _profile.EnableSingleSubtitleLimit)
@@ -250,7 +262,8 @@ namespace Emby.Dlna.Didl
private bool AddSubtitleElement(XmlWriter writer, SubtitleStreamInfo info)
{
var subtitleProfile = _profile.SubtitleProfiles
- .FirstOrDefault(i => string.Equals(info.Format, i.Format, StringComparison.OrdinalIgnoreCase) && i.Method == SubtitleDeliveryMethod.External);
+ .FirstOrDefault(i => string.Equals(info.Format, i.Format, StringComparison.OrdinalIgnoreCase)
+ && i.Method == SubtitleDeliveryMethod.External);
if (subtitleProfile == null)
{
@@ -265,7 +278,7 @@ namespace Emby.Dlna.Didl
// <sec:CaptionInfo sec:type="srt">http://192.168.1.3:9999/video.srt</sec:CaptionInfo>
writer.WriteStartElement("sec", "CaptionInfoEx", null);
- writer.WriteAttributeString("sec", "type", null, info.Format.ToLower());
+ writer.WriteAttributeString("sec", "type", null, info.Format.ToLowerInvariant());
writer.WriteString(info.Url);
writer.WriteFullEndElement();
@@ -282,7 +295,7 @@ namespace Emby.Dlna.Didl
else
{
writer.WriteStartElement(string.Empty, "res", NS_DIDL);
- var protocolInfo = string.Format("http-get:*:text/{0}:*", info.Format.ToLower());
+ var protocolInfo = string.Format("http-get:*:text/{0}:*", info.Format.ToLowerInvariant());
writer.WriteAttributeString("protocolInfo", protocolInfo);
writer.WriteString(info.Url);
@@ -387,91 +400,39 @@ namespace Emby.Dlna.Didl
private string GetDisplayName(BaseItem item, StubType? itemStubType, BaseItem context)
{
- if (itemStubType.HasValue && itemStubType.Value == StubType.Latest)
- {
- return _localization.GetLocalizedString("Latest");
- }
- if (itemStubType.HasValue && itemStubType.Value == StubType.Playlists)
+ if (itemStubType.HasValue)
{
- return _localization.GetLocalizedString("Playlists");
- }
- if (itemStubType.HasValue && itemStubType.Value == StubType.AlbumArtists)
- {
- return _localization.GetLocalizedString("HeaderAlbumArtists");
- }
- if (itemStubType.HasValue && itemStubType.Value == StubType.Albums)
- {
- return _localization.GetLocalizedString("Albums");
- }
- if (itemStubType.HasValue && itemStubType.Value == StubType.Artists)
- {
- return _localization.GetLocalizedString("Artists");
- }
- if (itemStubType.HasValue && itemStubType.Value == StubType.Songs)
- {
- return _localization.GetLocalizedString("Songs");
- }
- if (itemStubType.HasValue && itemStubType.Value == StubType.Genres)
- {
- return _localization.GetLocalizedString("Genres");
- }
- if (itemStubType.HasValue && itemStubType.Value == StubType.FavoriteAlbums)
- {
- return _localization.GetLocalizedString("HeaderFavoriteAlbums");
- }
- if (itemStubType.HasValue && itemStubType.Value == StubType.FavoriteArtists)
- {
- return _localization.GetLocalizedString("HeaderFavoriteArtists");
- }
- if (itemStubType.HasValue && itemStubType.Value == StubType.FavoriteSongs)
- {
- return _localization.GetLocalizedString("HeaderFavoriteSongs");
- }
- if (itemStubType.HasValue && itemStubType.Value == StubType.ContinueWatching)
- {
- return _localization.GetLocalizedString("HeaderContinueWatching");
- }
- if (itemStubType.HasValue && itemStubType.Value == StubType.Movies)
- {
- return _localization.GetLocalizedString("Movies");
- }
- if (itemStubType.HasValue && itemStubType.Value == StubType.Collections)
- {
- return _localization.GetLocalizedString("Collections");
- }
- if (itemStubType.HasValue && itemStubType.Value == StubType.Favorites)
- {
- return _localization.GetLocalizedString("Favorites");
- }
- if (itemStubType.HasValue && itemStubType.Value == StubType.NextUp)
- {
- return _localization.GetLocalizedString("HeaderNextUp");
- }
- if (itemStubType.HasValue && itemStubType.Value == StubType.FavoriteSeries)
- {
- return _localization.GetLocalizedString("HeaderFavoriteShows");
- }
- if (itemStubType.HasValue && itemStubType.Value == StubType.FavoriteEpisodes)
- {
- return _localization.GetLocalizedString("HeaderFavoriteEpisodes");
- }
- if (itemStubType.HasValue && itemStubType.Value == StubType.Series)
- {
- return _localization.GetLocalizedString("Shows");
+ switch (itemStubType.Value)
+ {
+ case StubType.Latest: return _localization.GetLocalizedString("Latest");
+ case StubType.Playlists: return _localization.GetLocalizedString("Playlists");
+ case StubType.AlbumArtists: return _localization.GetLocalizedString("HeaderAlbumArtists");
+ case StubType.Albums: return _localization.GetLocalizedString("Albums");
+ case StubType.Artists: return _localization.GetLocalizedString("Artists");
+ case StubType.Songs: return _localization.GetLocalizedString("Songs");
+ case StubType.Genres: return _localization.GetLocalizedString("Genres");
+ case StubType.FavoriteAlbums: return _localization.GetLocalizedString("HeaderFavoriteAlbums");
+ case StubType.FavoriteArtists: return _localization.GetLocalizedString("HeaderFavoriteArtists");
+ case StubType.FavoriteSongs: return _localization.GetLocalizedString("HeaderFavoriteSongs");
+ case StubType.ContinueWatching: return _localization.GetLocalizedString("HeaderContinueWatching");
+ case StubType.Movies: return _localization.GetLocalizedString("Movies");
+ case StubType.Collections: return _localization.GetLocalizedString("Collections");
+ case StubType.Favorites: return _localization.GetLocalizedString("Favorites");
+ case StubType.NextUp: return _localization.GetLocalizedString("HeaderNextUp");
+ case StubType.FavoriteSeries: return _localization.GetLocalizedString("HeaderFavoriteShows");
+ case StubType.FavoriteEpisodes: return _localization.GetLocalizedString("HeaderFavoriteEpisodes");
+ case StubType.Series: return _localization.GetLocalizedString("Shows");
+ default: break;
+ }
}
- var episode = item as Episode;
- var season = context as Season;
-
- if (episode != null && season != null)
+ if (item is Episode episode && context is Season season)
{
// This is a special embedded within a season
- if (item.ParentIndexNumber.HasValue && item.ParentIndexNumber.Value == 0)
+ if (item.ParentIndexNumber.HasValue && item.ParentIndexNumber.Value == 0
+ && season.IndexNumber.HasValue && season.IndexNumber.Value != 0)
{
- if (season.IndexNumber.HasValue && season.IndexNumber.Value != 0)
- {
- return string.Format(_localization.GetLocalizedString("ValueSpecialEpisodeName"), item.Name);
- }
+ return string.Format(_localization.GetLocalizedString("ValueSpecialEpisodeName"), item.Name);
}
if (item.IndexNumber.HasValue)
@@ -585,10 +546,8 @@ namespace Emby.Dlna.Didl
public static bool IsIdRoot(string id)
{
- if (string.IsNullOrWhiteSpace(id) ||
-
- string.Equals(id, "0", StringComparison.OrdinalIgnoreCase)
-
+ if (string.IsNullOrWhiteSpace(id)
+ || string.Equals(id, "0", StringComparison.OrdinalIgnoreCase)
// Samsung sometimes uses 1 as root
|| string.Equals(id, "1", StringComparison.OrdinalIgnoreCase))
{
@@ -808,7 +767,7 @@ namespace Emby.Dlna.Didl
{
writer.WriteString(_profile.RequiresPlainFolders ? "object.container.storageFolder" : "object.container.genre.musicGenre");
}
- else if (item is Genre || item is GameGenre)
+ else if (item is Genre)
{
writer.WriteString(_profile.RequiresPlainFolders ? "object.container.storageFolder" : "object.container.genre");
}
@@ -844,7 +803,7 @@ namespace Emby.Dlna.Didl
// var type = types.FirstOrDefault(i => string.Equals(i, actor.Type, StringComparison.OrdinalIgnoreCase) || string.Equals(i, actor.Role, StringComparison.OrdinalIgnoreCase))
// ?? PersonType.Actor;
- // AddValue(writer, "upnp", type.ToLower(), actor.Name, NS_UPNP);
+ // AddValue(writer, "upnp", type.ToLowerInvariant(), actor.Name, NS_UPNP);
// index++;
@@ -1112,7 +1071,7 @@ namespace Emby.Dlna.Didl
};
}
- class ImageDownloadInfo
+ private class ImageDownloadInfo
{
internal Guid ItemId;
internal string ImageTag;
@@ -1128,7 +1087,7 @@ namespace Emby.Dlna.Didl
internal ItemImageInfo ItemImageInfo;
}
- class ImageUrlInfo
+ private class ImageUrlInfo
{
internal string Url;
@@ -1147,7 +1106,7 @@ namespace Emby.Dlna.Didl
if (stubType.HasValue)
{
- id = stubType.Value.ToString().ToLower() + "_" + id;
+ id = stubType.Value.ToString().ToLowerInvariant() + "_" + id;
}
return id;
diff --git a/Emby.Dlna/DlnaManager.cs b/Emby.Dlna/DlnaManager.cs
index fd7b408fd..c507b14e9 100644
--- a/Emby.Dlna/DlnaManager.cs
+++ b/Emby.Dlna/DlnaManager.cs
@@ -4,6 +4,7 @@ using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
+using System.Threading.Tasks;
using Emby.Dlna.Profiles;
using Emby.Dlna.Server;
using MediaBrowser.Common.Configuration;
@@ -48,11 +49,11 @@ namespace Emby.Dlna
_assemblyInfo = assemblyInfo;
}
- public void InitProfiles()
+ public async Task InitProfilesAsync()
{
try
{
- ExtractSystemProfiles();
+ await ExtractSystemProfilesAsync();
LoadProfiles();
}
catch (Exception ex)
@@ -300,7 +301,7 @@ namespace Emby.Dlna
profile = ReserializeProfile(tempProfile);
- profile.Id = path.ToLower().GetMD5().ToString("N");
+ profile.Id = path.ToLowerInvariant().GetMD5().ToString("N");
_profiles[path] = new Tuple<InternalProfileInfo, DeviceProfile>(GetInternalProfileInfo(_fileSystem.GetFileInfo(path), type), profile);
@@ -352,14 +353,14 @@ namespace Emby.Dlna
Info = new DeviceProfileInfo
{
- Id = file.FullName.ToLower().GetMD5().ToString("N"),
+ Id = file.FullName.ToLowerInvariant().GetMD5().ToString("N"),
Name = _fileSystem.GetFileNameWithoutExtension(file),
Type = type
}
};
}
- private void ExtractSystemProfiles()
+ private async Task ExtractSystemProfilesAsync()
{
var namespaceName = GetType().Namespace + ".Profiles.Xml.";
@@ -383,7 +384,7 @@ namespace Emby.Dlna
using (var fileStream = _fileSystem.GetFileStream(path, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read))
{
- stream.CopyTo(fileStream);
+ await stream.CopyToAsync(fileStream);
}
}
}
@@ -506,7 +507,7 @@ namespace Emby.Dlna
? ImageFormat.Png
: ImageFormat.Jpg;
- var resource = GetType().Namespace + ".Images." + filename.ToLower();
+ var resource = GetType().Namespace + ".Images." + filename.ToLowerInvariant();
return new ImageStream
{
diff --git a/Emby.Dlna/Main/DlnaEntryPoint.cs b/Emby.Dlna/Main/DlnaEntryPoint.cs
index 1ab6014eb..a20006578 100644
--- a/Emby.Dlna/Main/DlnaEntryPoint.cs
+++ b/Emby.Dlna/Main/DlnaEntryPoint.cs
@@ -20,7 +20,6 @@ using MediaBrowser.Model.Dlna;
using MediaBrowser.Model.Globalization;
using MediaBrowser.Model.Net;
using MediaBrowser.Model.System;
-using MediaBrowser.Model.Threading;
using MediaBrowser.Model.Xml;
using Microsoft.Extensions.Logging;
using Rssdp;
@@ -49,8 +48,7 @@ namespace Emby.Dlna.Main
private readonly IDeviceDiscovery _deviceDiscovery;
private SsdpDevicePublisher _Publisher;
-
- private readonly ITimerFactory _timerFactory;
+
private readonly ISocketFactory _socketFactory;
private readonly IEnvironmentInfo _environmentInfo;
private readonly INetworkManager _networkManager;
@@ -78,7 +76,6 @@ namespace Emby.Dlna.Main
IDeviceDiscovery deviceDiscovery,
IMediaEncoder mediaEncoder,
ISocketFactory socketFactory,
- ITimerFactory timerFactory,
IEnvironmentInfo environmentInfo,
INetworkManager networkManager,
IUserViewManager userViewManager,
@@ -99,7 +96,6 @@ namespace Emby.Dlna.Main
_deviceDiscovery = deviceDiscovery;
_mediaEncoder = mediaEncoder;
_socketFactory = socketFactory;
- _timerFactory = timerFactory;
_environmentInfo = environmentInfo;
_networkManager = networkManager;
_logger = loggerFactory.CreateLogger("Dlna");
@@ -125,9 +121,9 @@ namespace Emby.Dlna.Main
Current = this;
}
- public void Run()
+ public async Task RunAsync()
{
- ((DlnaManager)_dlnaManager).InitProfiles();
+ await ((DlnaManager)_dlnaManager).InitProfilesAsync().ConfigureAwait(false);
ReloadComponents();
@@ -233,7 +229,7 @@ namespace Emby.Dlna.Main
try
{
- _Publisher = new SsdpDevicePublisher(_communicationsServer, _timerFactory, _environmentInfo.OperatingSystemName, _environmentInfo.OperatingSystemVersion);
+ _Publisher = new SsdpDevicePublisher(_communicationsServer, _environmentInfo.OperatingSystemName, _environmentInfo.OperatingSystemVersion);
_Publisher.LogFunction = LogMessage;
_Publisher.SupportPnpRootDevice = false;
@@ -263,7 +259,7 @@ namespace Emby.Dlna.Main
var fullService = "urn:schemas-upnp-org:device:MediaServer:1";
- _logger.LogInformation("Registering publisher for {0} on {1}", fullService, address.ToString());
+ _logger.LogInformation("Registering publisher for {0} on {1}", fullService, address);
var descriptorUri = "/dlna/" + udn + "/description.xml";
var uri = new Uri(_appHost.GetLocalApiUrl(address) + descriptorUri);
@@ -353,8 +349,7 @@ namespace Emby.Dlna.Main
_userDataManager,
_localization,
_mediaSourceManager,
- _mediaEncoder,
- _timerFactory);
+ _mediaEncoder);
_manager.Start();
}
diff --git a/Emby.Dlna/PlayTo/Device.cs b/Emby.Dlna/PlayTo/Device.cs
index 68aa0a6a7..037cdd8aa 100644
--- a/Emby.Dlna/PlayTo/Device.cs
+++ b/Emby.Dlna/PlayTo/Device.cs
@@ -10,7 +10,6 @@ using Emby.Dlna.Server;
using Emby.Dlna.Ssdp;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Model.Threading;
using Microsoft.Extensions.Logging;
namespace Emby.Dlna.PlayTo
@@ -19,7 +18,7 @@ namespace Emby.Dlna.PlayTo
{
#region Fields & Properties
- private ITimer _timer;
+ private Timer _timer;
public DeviceInfo Properties { get; set; }
@@ -40,12 +39,7 @@ namespace Emby.Dlna.PlayTo
public TimeSpan? Duration { get; set; }
- private TimeSpan _position = TimeSpan.FromSeconds(0);
- public TimeSpan Position
- {
- get => _position;
- set => _position = value;
- }
+ public TimeSpan Position { get; set; } = TimeSpan.FromSeconds(0);
public TRANSPORTSTATE TransportState { get; private set; }
@@ -61,24 +55,20 @@ namespace Emby.Dlna.PlayTo
private readonly ILogger _logger;
private readonly IServerConfigurationManager _config;
- public DateTime DateLastActivity { get; private set; }
public Action OnDeviceUnavailable { get; set; }
- private readonly ITimerFactory _timerFactory;
-
- public Device(DeviceInfo deviceProperties, IHttpClient httpClient, ILogger logger, IServerConfigurationManager config, ITimerFactory timerFactory)
+ public Device(DeviceInfo deviceProperties, IHttpClient httpClient, ILogger logger, IServerConfigurationManager config)
{
Properties = deviceProperties;
_httpClient = httpClient;
_logger = logger;
_config = config;
- _timerFactory = timerFactory;
}
public void Start()
{
_logger.LogDebug("Dlna Device.Start");
- _timer = _timerFactory.Create(TimerCallback, null, 1000, Timeout.Infinite);
+ _timer = new Timer(TimerCallback, null, 1000, Timeout.Infinite);
}
private DateTime _lastVolumeRefresh;
@@ -119,7 +109,9 @@ namespace Emby.Dlna.PlayTo
lock (_timerLock)
{
if (_disposed)
+ {
return;
+ }
_volumeRefreshActive = true;
@@ -136,7 +128,9 @@ namespace Emby.Dlna.PlayTo
lock (_timerLock)
{
if (_disposed)
+ {
return;
+ }
_volumeRefreshActive = false;
@@ -144,11 +138,6 @@ namespace Emby.Dlna.PlayTo
}
}
- public void OnPlaybackStartedExternally()
- {
- RestartTimer(true);
- }
-
#region Commanding
public Task VolumeDown(CancellationToken cancellationToken)
@@ -333,7 +322,9 @@ namespace Emby.Dlna.PlayTo
private string CreateDidlMeta(string value)
{
if (string.IsNullOrEmpty(value))
+ {
return string.Empty;
+ }
return DescriptionXmlBuilder.Escape(value);
}
@@ -342,10 +333,11 @@ namespace Emby.Dlna.PlayTo
{
var command = avCommands.ServiceActions.FirstOrDefault(c => c.Name == "Play");
if (command == null)
+ {
return Task.CompletedTask;
+ }
var service = GetAvTransportService();
-
if (service == null)
{
throw new InvalidOperationException("Unable to find service");
@@ -369,7 +361,9 @@ namespace Emby.Dlna.PlayTo
var command = avCommands.ServiceActions.FirstOrDefault(c => c.Name == "Stop");
if (command == null)
+ {
return;
+ }
var service = GetAvTransportService();
@@ -385,7 +379,9 @@ namespace Emby.Dlna.PlayTo
var command = avCommands.ServiceActions.FirstOrDefault(c => c.Name == "Pause");
if (command == null)
+ {
return;
+ }
var service = GetAvTransportService();
@@ -405,7 +401,9 @@ namespace Emby.Dlna.PlayTo
private async void TimerCallback(object sender)
{
if (_disposed)
+ {
return;
+ }
try
{
@@ -425,8 +423,6 @@ namespace Emby.Dlna.PlayTo
return;
}
- DateLastActivity = DateTime.UtcNow;
-
if (transportState.HasValue)
{
// If we're not playing anything no need to get additional data
@@ -505,7 +501,9 @@ namespace Emby.Dlna.PlayTo
var command = rendererCommands.ServiceActions.FirstOrDefault(c => c.Name == "GetVolume");
if (command == null)
+ {
return;
+ }
var service = GetServiceRenderingControl();
@@ -518,13 +516,17 @@ namespace Emby.Dlna.PlayTo
.ConfigureAwait(false);
if (result == null || result.Document == null)
+ {
return;
+ }
var volume = result.Document.Descendants(uPnpNamespaces.RenderingControl + "GetVolumeResponse").Select(i => i.Element("CurrentVolume")).FirstOrDefault(i => i != null);
- var volumeValue = volume == null ? null : volume.Value;
+ var volumeValue = volume?.Value;
if (string.IsNullOrWhiteSpace(volumeValue))
+ {
return;
+ }
Volume = int.Parse(volumeValue, UsCulture);
@@ -545,7 +547,9 @@ namespace Emby.Dlna.PlayTo
var command = rendererCommands.ServiceActions.FirstOrDefault(c => c.Name == "GetMute");
if (command == null)
+ {
return;
+ }
var service = GetServiceRenderingControl();
@@ -560,39 +564,44 @@ namespace Emby.Dlna.PlayTo
if (result == null || result.Document == null)
return;
- var valueNode = result.Document.Descendants(uPnpNamespaces.RenderingControl + "GetMuteResponse").Select(i => i.Element("CurrentMute")).FirstOrDefault(i => i != null);
- var value = valueNode == null ? null : valueNode.Value;
+ var valueNode = result.Document.Descendants(uPnpNamespaces.RenderingControl + "GetMuteResponse")
+ .Select(i => i.Element("CurrentMute"))
+ .FirstOrDefault(i => i != null);
- IsMuted = string.Equals(value, "1", StringComparison.OrdinalIgnoreCase);
+ IsMuted = string.Equals(valueNode?.Value, "1", StringComparison.OrdinalIgnoreCase);
}
private async Task<TRANSPORTSTATE?> GetTransportInfo(TransportCommands avCommands, CancellationToken cancellationToken)
{
var command = avCommands.ServiceActions.FirstOrDefault(c => c.Name == "GetTransportInfo");
if (command == null)
+ {
return null;
+ }
var service = GetAvTransportService();
if (service == null)
+ {
return null;
+ }
var result = await new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, avCommands.BuildPost(command, service.ServiceType), false)
.ConfigureAwait(false);
if (result == null || result.Document == null)
+ {
return null;
+ }
var transportState =
result.Document.Descendants(uPnpNamespaces.AvTransport + "GetTransportInfoResponse").Select(i => i.Element("CurrentTransportState")).FirstOrDefault(i => i != null);
var transportStateValue = transportState == null ? null : transportState.Value;
- if (transportStateValue != null)
+ if (transportStateValue != null
+ && Enum.TryParse(transportStateValue, true, out TRANSPORTSTATE state))
{
- if (Enum.TryParse(transportStateValue, true, out TRANSPORTSTATE state))
- {
- return state;
- }
+ return state;
}
return null;
@@ -602,10 +611,11 @@ namespace Emby.Dlna.PlayTo
{
var command = avCommands.ServiceActions.FirstOrDefault(c => c.Name == "GetMediaInfo");
if (command == null)
+ {
return null;
+ }
var service = GetAvTransportService();
-
if (service == null)
{
throw new InvalidOperationException("Unable to find service");
@@ -617,7 +627,9 @@ namespace Emby.Dlna.PlayTo
.ConfigureAwait(false);
if (result == null || result.Document == null)
+ {
return null;
+ }
var track = result.Document.Descendants("CurrentURIMetaData").FirstOrDefault();
@@ -657,11 +669,13 @@ namespace Emby.Dlna.PlayTo
return null;
}
- private async Task<Tuple<bool, uBaseObject>> GetPositionInfo(TransportCommands avCommands, CancellationToken cancellationToken)
+ private async Task<(bool, uBaseObject)> GetPositionInfo(TransportCommands avCommands, CancellationToken cancellationToken)
{
var command = avCommands.ServiceActions.FirstOrDefault(c => c.Name == "GetPositionInfo");
if (command == null)
- return new Tuple<bool, uBaseObject>(false, null);
+ {
+ return (false, null);
+ }
var service = GetAvTransportService();
@@ -676,7 +690,9 @@ namespace Emby.Dlna.PlayTo
.ConfigureAwait(false);
if (result == null || result.Document == null)
- return new Tuple<bool, uBaseObject>(false, null);
+ {
+ return (false, null);
+ }
var trackUriElem = result.Document.Descendants(uPnpNamespaces.AvTransport + "GetPositionInfoResponse").Select(i => i.Element("TrackURI")).FirstOrDefault(i => i != null);
var trackUri = trackUriElem == null ? null : trackUriElem.Value;
@@ -684,8 +700,8 @@ namespace Emby.Dlna.PlayTo
var durationElem = result.Document.Descendants(uPnpNamespaces.AvTransport + "GetPositionInfoResponse").Select(i => i.Element("TrackDuration")).FirstOrDefault(i => i != null);
var duration = durationElem == null ? null : durationElem.Value;
- if (!string.IsNullOrWhiteSpace(duration) &&
- !string.Equals(duration, "NOT_IMPLEMENTED", StringComparison.OrdinalIgnoreCase))
+ if (!string.IsNullOrWhiteSpace(duration)
+ && !string.Equals(duration, "NOT_IMPLEMENTED", StringComparison.OrdinalIgnoreCase))
{
Duration = TimeSpan.Parse(duration, UsCulture);
}
@@ -707,14 +723,14 @@ namespace Emby.Dlna.PlayTo
if (track == null)
{
//If track is null, some vendors do this, use GetMediaInfo instead
- return new Tuple<bool, uBaseObject>(true, null);
+ return (true, null);
}
var trackString = (string)track;
if (string.IsNullOrWhiteSpace(trackString) || string.Equals(trackString, "NOT_IMPLEMENTED", StringComparison.OrdinalIgnoreCase))
{
- return new Tuple<bool, uBaseObject>(true, null);
+ return (true, null);
}
XElement uPnpResponse;
@@ -735,7 +751,7 @@ namespace Emby.Dlna.PlayTo
catch (Exception ex)
{
_logger.LogError(ex, "Unable to parse xml {0}", trackString);
- return new Tuple<bool, uBaseObject>(true, null);
+ return (true, null);
}
}
@@ -743,7 +759,7 @@ namespace Emby.Dlna.PlayTo
var uTrack = CreateUBaseObject(e, trackUri);
- return new Tuple<bool, uBaseObject>(true, uTrack);
+ return (true, uTrack);
}
private static uBaseObject CreateUBaseObject(XElement container, string trackUri)
@@ -801,11 +817,9 @@ namespace Emby.Dlna.PlayTo
private async Task<TransportCommands> GetAVProtocolAsync(CancellationToken cancellationToken)
{
- var avCommands = AvCommands;
-
- if (avCommands != null)
+ if (AvCommands != null)
{
- return avCommands;
+ return AvCommands;
}
if (_disposed)
@@ -825,18 +839,15 @@ namespace Emby.Dlna.PlayTo
var document = await httpClient.GetDataAsync(url, cancellationToken).ConfigureAwait(false);
- avCommands = TransportCommands.Create(document);
- AvCommands = avCommands;
- return avCommands;
+ AvCommands = TransportCommands.Create(document);
+ return AvCommands;
}
private async Task<TransportCommands> GetRenderingProtocolAsync(CancellationToken cancellationToken)
{
- var rendererCommands = RendererCommands;
-
- if (rendererCommands != null)
+ if (RendererCommands != null)
{
- return rendererCommands;
+ return RendererCommands;
}
if (_disposed)
@@ -845,7 +856,6 @@ namespace Emby.Dlna.PlayTo
}
var avService = GetServiceRenderingControl();
-
if (avService == null)
{
throw new ArgumentException("Device AvService is null");
@@ -857,9 +867,8 @@ namespace Emby.Dlna.PlayTo
_logger.LogDebug("Dlna Device.GetRenderingProtocolAsync");
var document = await httpClient.GetDataAsync(url, cancellationToken).ConfigureAwait(false);
- rendererCommands = TransportCommands.Create(document);
- RendererCommands = rendererCommands;
- return rendererCommands;
+ RendererCommands = TransportCommands.Create(document);
+ return RendererCommands;
}
private string NormalizeUrl(string baseUrl, string url)
@@ -871,85 +880,103 @@ namespace Emby.Dlna.PlayTo
}
if (!url.Contains("/"))
+ {
url = "/dmr/" + url;
+ }
+
if (!url.StartsWith("/"))
+ {
url = "/" + url;
+ }
return baseUrl + url;
}
- private TransportCommands AvCommands
- {
- get;
- set;
- }
+ private TransportCommands AvCommands { get; set; }
- private TransportCommands RendererCommands
- {
- get;
- set;
- }
+ private TransportCommands RendererCommands { get; set; }
- public static async Task<Device> CreateuPnpDeviceAsync(Uri url, IHttpClient httpClient, IServerConfigurationManager config, ILogger logger, ITimerFactory timerFactory, CancellationToken cancellationToken)
+ public static async Task<Device> CreateuPnpDeviceAsync(Uri url, IHttpClient httpClient, IServerConfigurationManager config, ILogger logger, CancellationToken cancellationToken)
{
var ssdpHttpClient = new SsdpHttpClient(httpClient, config);
var document = await ssdpHttpClient.GetDataAsync(url.ToString(), cancellationToken).ConfigureAwait(false);
- var deviceProperties = new DeviceInfo();
-
var friendlyNames = new List<string>();
var name = document.Descendants(uPnpNamespaces.ud.GetName("friendlyName")).FirstOrDefault();
if (name != null && !string.IsNullOrWhiteSpace(name.Value))
+ {
friendlyNames.Add(name.Value);
+ }
var room = document.Descendants(uPnpNamespaces.ud.GetName("roomName")).FirstOrDefault();
if (room != null && !string.IsNullOrWhiteSpace(room.Value))
+ {
friendlyNames.Add(room.Value);
+ }
- deviceProperties.Name = string.Join(" ", friendlyNames.ToArray());
+ var deviceProperties = new DeviceInfo()
+ {
+ Name = string.Join(" ", friendlyNames),
+ BaseUrl = string.Format("http://{0}:{1}", url.Host, url.Port)
+ };
var model = document.Descendants(uPnpNamespaces.ud.GetName("modelName")).FirstOrDefault();
if (model != null)
+ {
deviceProperties.ModelName = model.Value;
+ }
var modelNumber = document.Descendants(uPnpNamespaces.ud.GetName("modelNumber")).FirstOrDefault();
if (modelNumber != null)
+ {
deviceProperties.ModelNumber = modelNumber.Value;
+ }
var uuid = document.Descendants(uPnpNamespaces.ud.GetName("UDN")).FirstOrDefault();
if (uuid != null)
+ {
deviceProperties.UUID = uuid.Value;
+ }
var manufacturer = document.Descendants(uPnpNamespaces.ud.GetName("manufacturer")).FirstOrDefault();
if (manufacturer != null)
+ {
deviceProperties.Manufacturer = manufacturer.Value;
+ }
var manufacturerUrl = document.Descendants(uPnpNamespaces.ud.GetName("manufacturerURL")).FirstOrDefault();
if (manufacturerUrl != null)
+ {
deviceProperties.ManufacturerUrl = manufacturerUrl.Value;
+ }
var presentationUrl = document.Descendants(uPnpNamespaces.ud.GetName("presentationURL")).FirstOrDefault();
if (presentationUrl != null)
+ {
deviceProperties.PresentationUrl = presentationUrl.Value;
+ }
var modelUrl = document.Descendants(uPnpNamespaces.ud.GetName("modelURL")).FirstOrDefault();
if (modelUrl != null)
+ {
deviceProperties.ModelUrl = modelUrl.Value;
+ }
var serialNumber = document.Descendants(uPnpNamespaces.ud.GetName("serialNumber")).FirstOrDefault();
if (serialNumber != null)
+ {
deviceProperties.SerialNumber = serialNumber.Value;
+ }
var modelDescription = document.Descendants(uPnpNamespaces.ud.GetName("modelDescription")).FirstOrDefault();
if (modelDescription != null)
+ {
deviceProperties.ModelDescription = modelDescription.Value;
-
- deviceProperties.BaseUrl = string.Format("http://{0}:{1}", url.Host, url.Port);
+ }
var icon = document.Descendants(uPnpNamespaces.ud.GetName("icon")).FirstOrDefault();
-
if (icon != null)
{
deviceProperties.Icon = CreateIcon(icon);
@@ -958,12 +985,15 @@ namespace Emby.Dlna.PlayTo
foreach (var services in document.Descendants(uPnpNamespaces.ud.GetName("serviceList")))
{
if (services == null)
+ {
continue;
+ }
var servicesList = services.Descendants(uPnpNamespaces.ud.GetName("service"));
-
if (servicesList == null)
+ {
continue;
+ }
foreach (var element in servicesList)
{
@@ -976,9 +1006,7 @@ namespace Emby.Dlna.PlayTo
}
}
- var device = new Device(deviceProperties, httpClient, logger, config, timerFactory);
-
- return device;
+ return new Device(deviceProperties, httpClient, logger, config);
}
#endregion
@@ -1065,13 +1093,10 @@ namespace Emby.Dlna.PlayTo
private void OnPlaybackStart(uBaseObject mediaInfo)
{
- if (PlaybackStart != null)
+ PlaybackStart?.Invoke(this, new PlaybackStartEventArgs
{
- PlaybackStart.Invoke(this, new PlaybackStartEventArgs
- {
- MediaInfo = mediaInfo
- });
- }
+ MediaInfo = mediaInfo
+ });
}
private void OnPlaybackProgress(uBaseObject mediaInfo)
@@ -1082,58 +1107,56 @@ namespace Emby.Dlna.PlayTo
return;
}
- if (PlaybackProgress != null)
+ PlaybackProgress?.Invoke(this, new PlaybackProgressEventArgs
{
- PlaybackProgress.Invoke(this, new PlaybackProgressEventArgs
- {
- MediaInfo = mediaInfo
- });
- }
+ MediaInfo = mediaInfo
+ });
}
private void OnPlaybackStop(uBaseObject mediaInfo)
{
- if (PlaybackStopped != null)
+
+ PlaybackStopped?.Invoke(this, new PlaybackStoppedEventArgs
{
- PlaybackStopped.Invoke(this, new PlaybackStoppedEventArgs
- {
- MediaInfo = mediaInfo
- });
- }
+ MediaInfo = mediaInfo
+ });
}
private void OnMediaChanged(uBaseObject old, uBaseObject newMedia)
{
- if (MediaChanged != null)
+ MediaChanged?.Invoke(this, new MediaChangedEventArgs
{
- MediaChanged.Invoke(this, new MediaChangedEventArgs
- {
- OldMediaInfo = old,
- NewMediaInfo = newMedia
- });
- }
+ OldMediaInfo = old,
+ NewMediaInfo = newMedia
+ });
}
#region IDisposable
bool _disposed;
+
public void Dispose()
{
- if (!_disposed)
- {
- _disposed = true;
-
- DisposeTimer();
- }
+ Dispose(true);
+ GC.SuppressFinalize(this);
}
- private void DisposeTimer()
+ protected virtual void Dispose(bool disposing)
{
- if (_timer != null)
+ if (_disposed)
{
- _timer.Dispose();
- _timer = null;
+ return;
}
+
+ if (disposing)
+ {
+ _timer?.Dispose();
+ }
+
+ _timer = null;
+ Properties = null;
+
+ _disposed = true;
}
#endregion
diff --git a/Emby.Dlna/PlayTo/PlayToController.cs b/Emby.Dlna/PlayTo/PlayToController.cs
index 409b8442c..be86dde16 100644
--- a/Emby.Dlna/PlayTo/PlayToController.cs
+++ b/Emby.Dlna/PlayTo/PlayToController.cs
@@ -42,30 +42,43 @@ namespace Emby.Dlna.PlayTo
private readonly IDeviceDiscovery _deviceDiscovery;
private readonly string _serverAddress;
private readonly string _accessToken;
- private readonly DateTime _creationTime;
public bool IsSessionActive => !_disposed && _device != null;
public bool SupportsMediaControl => IsSessionActive;
- public PlayToController(SessionInfo session, ISessionManager sessionManager, ILibraryManager libraryManager, ILogger logger, IDlnaManager dlnaManager, IUserManager userManager, IImageProcessor imageProcessor, string serverAddress, string accessToken, IDeviceDiscovery deviceDiscovery, IUserDataManager userDataManager, ILocalizationManager localization, IMediaSourceManager mediaSourceManager, IConfigurationManager config, IMediaEncoder mediaEncoder)
+ public PlayToController(
+ SessionInfo session,
+ ISessionManager sessionManager,
+ ILibraryManager libraryManager,
+ ILogger logger,
+ IDlnaManager dlnaManager,
+ IUserManager userManager,
+ IImageProcessor imageProcessor,
+ string serverAddress,
+ string accessToken,
+ IDeviceDiscovery deviceDiscovery,
+ IUserDataManager userDataManager,
+ ILocalizationManager localization,
+ IMediaSourceManager mediaSourceManager,
+ IConfigurationManager config,
+ IMediaEncoder mediaEncoder)
{
_session = session;
_sessionManager = sessionManager;
_libraryManager = libraryManager;
+ _logger = logger;
_dlnaManager = dlnaManager;
_userManager = userManager;
_imageProcessor = imageProcessor;
_serverAddress = serverAddress;
+ _accessToken = accessToken;
_deviceDiscovery = deviceDiscovery;
_userDataManager = userDataManager;
_localization = localization;
_mediaSourceManager = mediaSourceManager;
_config = config;
_mediaEncoder = mediaEncoder;
- _accessToken = accessToken;
- _logger = logger;
- _creationTime = DateTime.UtcNow;
}
public void Init(Device device)
@@ -374,9 +387,7 @@ namespace Emby.Dlna.PlayTo
return _device.IsPaused ? _device.SetPlay(CancellationToken.None) : _device.SetPause(CancellationToken.None);
case PlaystateCommand.Seek:
- {
- return Seek(command.SeekPositionTicks ?? 0);
- }
+ return Seek(command.SeekPositionTicks ?? 0);
case PlaystateCommand.NextTrack:
return SetPlaylistIndex(_currentPlaylistIndex + 1);
@@ -442,8 +453,7 @@ namespace Emby.Dlna.PlayTo
var profile = _dlnaManager.GetProfile(deviceInfo.ToDeviceIdentification()) ??
_dlnaManager.GetDefaultProfile();
- var hasMediaSources = item as IHasMediaSources;
- var mediaSources = hasMediaSources != null
+ var mediaSources = item is IHasMediaSources
? (_mediaSourceManager.GetStaticMediaSources(item, true, user))
: new List<MediaSourceInfo>();
@@ -452,7 +462,7 @@ namespace Emby.Dlna.PlayTo
playlistItem.StreamUrl = DidlBuilder.NormalizeDlnaMediaUrl(playlistItem.StreamInfo.ToUrl(_serverAddress, _accessToken));
- var itemXml = new DidlBuilder(profile, user, _imageProcessor, _serverAddress, _accessToken, _userDataManager, _localization, _mediaSourceManager, _logger, _libraryManager, _mediaEncoder)
+ var itemXml = new DidlBuilder(profile, user, _imageProcessor, _serverAddress, _accessToken, _userDataManager, _localization, _mediaSourceManager, _logger, _mediaEncoder)
.GetItemDidl(_config.GetDlnaConfiguration(), item, user, null, _session.DeviceId, new Filter(), playlistItem.StreamInfo);
playlistItem.Didl = itemXml;
diff --git a/Emby.Dlna/PlayTo/PlayToManager.cs b/Emby.Dlna/PlayTo/PlayToManager.cs
index 790625705..6cce312ee 100644
--- a/Emby.Dlna/PlayTo/PlayToManager.cs
+++ b/Emby.Dlna/PlayTo/PlayToManager.cs
@@ -16,7 +16,6 @@ using MediaBrowser.Model.Events;
using MediaBrowser.Model.Globalization;
using MediaBrowser.Model.Net;
using MediaBrowser.Model.Session;
-using MediaBrowser.Model.Threading;
using Microsoft.Extensions.Logging;
namespace Emby.Dlna.PlayTo
@@ -39,13 +38,12 @@ namespace Emby.Dlna.PlayTo
private readonly IDeviceDiscovery _deviceDiscovery;
private readonly IMediaSourceManager _mediaSourceManager;
private readonly IMediaEncoder _mediaEncoder;
- private readonly ITimerFactory _timerFactory;
private bool _disposed;
private SemaphoreSlim _sessionLock = new SemaphoreSlim(1, 1);
private CancellationTokenSource _disposeCancellationTokenSource = new CancellationTokenSource();
- public PlayToManager(ILogger logger, ISessionManager sessionManager, ILibraryManager libraryManager, IUserManager userManager, IDlnaManager dlnaManager, IServerApplicationHost appHost, IImageProcessor imageProcessor, IDeviceDiscovery deviceDiscovery, IHttpClient httpClient, IServerConfigurationManager config, IUserDataManager userDataManager, ILocalizationManager localization, IMediaSourceManager mediaSourceManager, IMediaEncoder mediaEncoder, ITimerFactory timerFactory)
+ public PlayToManager(ILogger logger, ISessionManager sessionManager, ILibraryManager libraryManager, IUserManager userManager, IDlnaManager dlnaManager, IServerApplicationHost appHost, IImageProcessor imageProcessor, IDeviceDiscovery deviceDiscovery, IHttpClient httpClient, IServerConfigurationManager config, IUserDataManager userDataManager, ILocalizationManager localization, IMediaSourceManager mediaSourceManager, IMediaEncoder mediaEncoder)
{
_logger = logger;
_sessionManager = sessionManager;
@@ -61,7 +59,6 @@ namespace Emby.Dlna.PlayTo
_localization = localization;
_mediaSourceManager = mediaSourceManager;
_mediaEncoder = mediaEncoder;
- _timerFactory = timerFactory;
}
public void Start()
@@ -168,7 +165,7 @@ namespace Emby.Dlna.PlayTo
if (controller == null)
{
- var device = await Device.CreateuPnpDeviceAsync(uri, _httpClient, _config, _logger, _timerFactory, cancellationToken).ConfigureAwait(false);
+ var device = await Device.CreateuPnpDeviceAsync(uri, _httpClient, _config, _logger, cancellationToken).ConfigureAwait(false);
string deviceName = device.Properties.Name;
diff --git a/Emby.Dlna/Server/DescriptionXmlBuilder.cs b/Emby.Dlna/Server/DescriptionXmlBuilder.cs
index e0ecbee43..03d8f80ab 100644
--- a/Emby.Dlna/Server/DescriptionXmlBuilder.cs
+++ b/Emby.Dlna/Server/DescriptionXmlBuilder.cs
@@ -107,19 +107,19 @@ namespace Emby.Dlna.Server
'&'
};
- private static readonly string[] s_escapeStringPairs = new string[]
-{
- "<",
- "&lt;",
- ">",
- "&gt;",
- "\"",
- "&quot;",
- "'",
- "&apos;",
- "&",
- "&amp;"
-};
+ private static readonly string[] s_escapeStringPairs = new[]
+ {
+ "<",
+ "&lt;",
+ ">",
+ "&gt;",
+ "\"",
+ "&quot;",
+ "'",
+ "&apos;",
+ "&",
+ "&amp;"
+ };
private static string GetEscapeSequence(char c)
{
@@ -133,7 +133,7 @@ namespace Emby.Dlna.Server
return result;
}
}
- return c.ToString();
+ return c.ToString(CultureInfo.InvariantCulture);
}
/// <summary>Replaces invalid XML characters in a string with their valid XML equivalent.</summary>
@@ -145,6 +145,7 @@ namespace Emby.Dlna.Server
{
return null;
}
+
StringBuilder stringBuilder = null;
int length = str.Length;
int num = 0;
@@ -230,9 +231,9 @@ namespace Emby.Dlna.Server
var serverName = new string(characters);
- var name = (_profile.FriendlyName ?? string.Empty).Replace("${HostName}", serverName, StringComparison.OrdinalIgnoreCase);
+ var name = _profile.FriendlyName?.Replace("${HostName}", serverName, StringComparison.OrdinalIgnoreCase);
- return name;
+ return name ?? string.Empty;
}
private void AppendIconList(StringBuilder builder)
@@ -295,65 +296,62 @@ namespace Emby.Dlna.Server
}
private IEnumerable<DeviceIcon> GetIcons()
- {
- var list = new List<DeviceIcon>();
-
- list.Add(new DeviceIcon
- {
- MimeType = "image/png",
- Depth = "24",
- Width = 240,
- Height = 240,
- Url = "icons/logo240.png"
- });
-
- list.Add(new DeviceIcon
- {
- MimeType = "image/jpeg",
- Depth = "24",
- Width = 240,
- Height = 240,
- Url = "icons/logo240.jpg"
- });
-
- list.Add(new DeviceIcon
- {
- MimeType = "image/png",
- Depth = "24",
- Width = 120,
- Height = 120,
- Url = "icons/logo120.png"
- });
-
- list.Add(new DeviceIcon
- {
- MimeType = "image/jpeg",
- Depth = "24",
- Width = 120,
- Height = 120,
- Url = "icons/logo120.jpg"
- });
-
- list.Add(new DeviceIcon
- {
- MimeType = "image/png",
- Depth = "24",
- Width = 48,
- Height = 48,
- Url = "icons/logo48.png"
- });
-
- list.Add(new DeviceIcon
+ => new[]
{
- MimeType = "image/jpeg",
- Depth = "24",
- Width = 48,
- Height = 48,
- Url = "icons/logo48.jpg"
- });
-
- return list;
- }
+ new DeviceIcon
+ {
+ MimeType = "image/png",
+ Depth = "24",
+ Width = 240,
+ Height = 240,
+ Url = "icons/logo240.png"
+ },
+
+ new DeviceIcon
+ {
+ MimeType = "image/jpeg",
+ Depth = "24",
+ Width = 240,
+ Height = 240,
+ Url = "icons/logo240.jpg"
+ },
+
+ new DeviceIcon
+ {
+ MimeType = "image/png",
+ Depth = "24",
+ Width = 120,
+ Height = 120,
+ Url = "icons/logo120.png"
+ },
+
+ new DeviceIcon
+ {
+ MimeType = "image/jpeg",
+ Depth = "24",
+ Width = 120,
+ Height = 120,
+ Url = "icons/logo120.jpg"
+ },
+
+ new DeviceIcon
+ {
+ MimeType = "image/png",
+ Depth = "24",
+ Width = 48,
+ Height = 48,
+ Url = "icons/logo48.png"
+ },
+
+ new DeviceIcon
+ {
+ MimeType = "image/jpeg",
+ Depth = "24",
+ Width = 48,
+ Height = 48,
+ Url = "icons/logo48.jpg"
+ }
+ };
private IEnumerable<DeviceService> GetServices()
{
diff --git a/Emby.Dlna/Ssdp/DeviceDiscovery.cs b/Emby.Dlna/Ssdp/DeviceDiscovery.cs
index 89a88705f..298f68a28 100644
--- a/Emby.Dlna/Ssdp/DeviceDiscovery.cs
+++ b/Emby.Dlna/Ssdp/DeviceDiscovery.cs
@@ -5,7 +5,6 @@ using MediaBrowser.Controller.Configuration;
using MediaBrowser.Model.Dlna;
using MediaBrowser.Model.Events;
using MediaBrowser.Model.Net;
-using MediaBrowser.Model.Threading;
using Microsoft.Extensions.Logging;
using Rssdp;
using Rssdp.Infrastructure;
@@ -48,20 +47,17 @@ namespace Emby.Dlna.Ssdp
private SsdpDeviceLocator _deviceLocator;
- private readonly ITimerFactory _timerFactory;
private readonly ISocketFactory _socketFactory;
private ISsdpCommunicationsServer _commsServer;
public DeviceDiscovery(
ILoggerFactory loggerFactory,
IServerConfigurationManager config,
- ISocketFactory socketFactory,
- ITimerFactory timerFactory)
+ ISocketFactory socketFactory)
{
_logger = loggerFactory.CreateLogger(nameof(DeviceDiscovery));
_config = config;
_socketFactory = socketFactory;
- _timerFactory = timerFactory;
}
// Call this method from somewhere in your code to start the search.
@@ -78,7 +74,7 @@ namespace Emby.Dlna.Ssdp
{
if (_listenerCount > 0 && _deviceLocator == null)
{
- _deviceLocator = new SsdpDeviceLocator(_commsServer, _timerFactory);
+ _deviceLocator = new SsdpDeviceLocator(_commsServer);
// (Optional) Set the filter so we only see notifications for devices we care about
// (can be any search target value i.e device type, uuid value etc - any value that appears in the
diff --git a/Emby.Drawing/ImageProcessor.cs b/Emby.Drawing/ImageProcessor.cs
index 4901561eb..faaeb5af8 100644
--- a/Emby.Drawing/ImageProcessor.cs
+++ b/Emby.Drawing/ImageProcessor.cs
@@ -83,8 +83,8 @@ namespace Emby.Drawing
}
}
- public string[] SupportedInputFormats =>
- new string[]
+ public IReadOnlyCollection<string> SupportedInputFormats =>
+ new HashSet<string>(StringComparer.OrdinalIgnoreCase)
{
"tiff",
"tif",
@@ -137,14 +137,14 @@ namespace Emby.Drawing
}
}
- public ImageFormat[] GetSupportedImageOutputFormats()
- {
- return _imageEncoder.SupportedOutputFormats;
- }
+ public IReadOnlyCollection<ImageFormat> GetSupportedImageOutputFormats()
+ => _imageEncoder.SupportedOutputFormats;
+
+ private static readonly HashSet<string> TransparentImageTypes
+ = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { ".png", ".webp", ".gif" };
- private static readonly string[] TransparentImageTypes = new string[] { ".png", ".webp", ".gif" };
public bool SupportsTransparency(string path)
- => TransparentImageTypes.Contains(Path.GetExtension(path).ToLower());
+ => TransparentImageTypes.Contains(Path.GetExtension(path));
public async Task<(string path, string mimeType, DateTime dateModified)> ProcessImage(ImageProcessingOptions options)
{
@@ -261,15 +261,6 @@ namespace Emby.Drawing
return (cacheFilePath, GetMimeType(outputFormat, cacheFilePath), _fileSystem.GetLastWriteTimeUtc(cacheFilePath));
}
- catch (ArgumentOutOfRangeException ex)
- {
- // Decoder failed to decode it
-#if DEBUG
- _logger.LogError(ex, "Error encoding image");
-#endif
- // Just spit out the original file if all the options are default
- return (originalImagePath, MimeTypes.GetMimeType(originalImagePath), dateModified);
- }
catch (Exception ex)
{
// If it fails for whatever reason, return the original image
@@ -374,13 +365,13 @@ namespace Emby.Drawing
filename += "v=" + Version;
- return GetCachePath(ResizedImageCachePath, filename, "." + format.ToString().ToLower());
+ return GetCachePath(ResizedImageCachePath, filename, "." + format.ToString().ToLowerInvariant());
}
- public ImageDimensions GetImageSize(BaseItem item, ItemImageInfo info)
- => GetImageSize(item, info, true);
+ public ImageDimensions GetImageDimensions(BaseItem item, ItemImageInfo info)
+ => GetImageDimensions(item, info, true);
- public ImageDimensions GetImageSize(BaseItem item, ItemImageInfo info, bool updateItem)
+ public ImageDimensions GetImageDimensions(BaseItem item, ItemImageInfo info, bool updateItem)
{
int width = info.Width;
int height = info.Height;
@@ -393,7 +384,7 @@ namespace Emby.Drawing
string path = info.Path;
_logger.LogInformation("Getting image size for item {ItemType} {Path}", item.GetType().Name, path);
- ImageDimensions size = GetImageSize(path);
+ ImageDimensions size = GetImageDimensions(path);
info.Width = size.Width;
info.Height = size.Height;
@@ -408,7 +399,7 @@ namespace Emby.Drawing
/// <summary>
/// Gets the size of the image.
/// </summary>
- public ImageDimensions GetImageSize(string path)
+ public ImageDimensions GetImageDimensions(string path)
=> _imageEncoder.GetImageSize(path);
/// <summary>
@@ -481,7 +472,7 @@ namespace Emby.Drawing
return (originalImagePath, dateModified);
}
- if (!_imageEncoder.SupportedInputFormats.Contains(inputFormat, StringComparer.OrdinalIgnoreCase))
+ if (!_imageEncoder.SupportedInputFormats.Contains(inputFormat))
{
try
{
diff --git a/Emby.Drawing/NullImageEncoder.cs b/Emby.Drawing/NullImageEncoder.cs
index 14f0424ac..fc4a5af9f 100644
--- a/Emby.Drawing/NullImageEncoder.cs
+++ b/Emby.Drawing/NullImageEncoder.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections.Generic;
using MediaBrowser.Controller.Drawing;
using MediaBrowser.Model.Drawing;
@@ -6,15 +7,11 @@ namespace Emby.Drawing
{
public class NullImageEncoder : IImageEncoder
{
- public string[] SupportedInputFormats =>
- new[]
- {
- "png",
- "jpeg",
- "jpg"
- };
-
- public ImageFormat[] SupportedOutputFormats => new[] { ImageFormat.Jpg, ImageFormat.Png };
+ public IReadOnlyCollection<string> SupportedInputFormats
+ => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "png", "jpeg", "jpg" };
+
+ public IReadOnlyCollection<ImageFormat> SupportedOutputFormats
+ => new HashSet<ImageFormat>() { ImageFormat.Jpg, ImageFormat.Png };
public void CropWhiteSpace(string inputPath, string outputPath)
{
diff --git a/Emby.IsoMounting/IsoMounter/LinuxIsoManager.cs b/Emby.IsoMounting/IsoMounter/LinuxIsoManager.cs
index c5564fd61..a6fc53953 100644
--- a/Emby.IsoMounting/IsoMounter/LinuxIsoManager.cs
+++ b/Emby.IsoMounting/IsoMounter/LinuxIsoManager.cs
@@ -121,7 +121,7 @@ namespace IsoMounter
path,
Path.GetExtension(path),
EnvironmentInfo.OperatingSystem,
- ExecutablesAvailable.ToString()
+ ExecutablesAvailable
);
if (ExecutablesAvailable)
@@ -183,7 +183,7 @@ namespace IsoMounter
_logger.LogInformation(
"[{0}] Disposing [{1}].",
Name,
- disposing.ToString()
+ disposing
);
if (disposing)
@@ -229,9 +229,8 @@ namespace IsoMounter
var uid = getuid();
_logger.LogDebug(
- "[{0}] Our current UID is [{1}], GetUserId() returned [{2}].",
+ "[{0}] GetUserId() returned [{2}].",
Name,
- uid.ToString(),
uid
);
diff --git a/Emby.Notifications/CoreNotificationTypes.cs b/Emby.Notifications/CoreNotificationTypes.cs
index 158898084..8cc14fa01 100644
--- a/Emby.Notifications/CoreNotificationTypes.cs
+++ b/Emby.Notifications/CoreNotificationTypes.cs
@@ -75,11 +75,6 @@ namespace Emby.Notifications
new NotificationTypeInfo
{
- Type = NotificationType.GamePlayback.ToString()
- },
-
- new NotificationTypeInfo
- {
Type = NotificationType.VideoPlayback.ToString()
},
@@ -90,11 +85,6 @@ namespace Emby.Notifications
new NotificationTypeInfo
{
- Type = NotificationType.GamePlaybackStopped.ToString()
- },
-
- new NotificationTypeInfo
- {
Type = NotificationType.VideoPlaybackStopped.ToString()
},
diff --git a/Emby.Notifications/Notifications.cs b/Emby.Notifications/Notifications.cs
index fbdc39f94..d3290479f 100644
--- a/Emby.Notifications/Notifications.cs
+++ b/Emby.Notifications/Notifications.cs
@@ -20,7 +20,6 @@ using MediaBrowser.Model.Events;
using MediaBrowser.Model.Globalization;
using MediaBrowser.Model.Notifications;
using MediaBrowser.Model.Tasks;
-using MediaBrowser.Model.Threading;
using Microsoft.Extensions.Logging;
namespace Emby.Notifications
@@ -40,9 +39,8 @@ namespace Emby.Notifications
private readonly ILibraryManager _libraryManager;
private readonly ISessionManager _sessionManager;
private readonly IServerApplicationHost _appHost;
- private readonly ITimerFactory _timerFactory;
- private ITimer LibraryUpdateTimer { get; set; }
+ private Timer LibraryUpdateTimer { get; set; }
private readonly object _libraryChangedSyncLock = new object();
private readonly IConfigurationManager _config;
@@ -52,7 +50,7 @@ namespace Emby.Notifications
private string[] _coreNotificationTypes;
- public Notifications(IInstallationManager installationManager, IActivityManager activityManager, ILocalizationManager localization, IUserManager userManager, ILogger logger, ITaskManager taskManager, INotificationManager notificationManager, ILibraryManager libraryManager, ISessionManager sessionManager, IServerApplicationHost appHost, IConfigurationManager config, IDeviceManager deviceManager, ITimerFactory timerFactory)
+ public Notifications(IInstallationManager installationManager, IActivityManager activityManager, ILocalizationManager localization, IUserManager userManager, ILogger logger, ITaskManager taskManager, INotificationManager notificationManager, ILibraryManager libraryManager, ISessionManager sessionManager, IServerApplicationHost appHost, IConfigurationManager config, IDeviceManager deviceManager)
{
_installationManager = installationManager;
_userManager = userManager;
@@ -64,19 +62,20 @@ namespace Emby.Notifications
_appHost = appHost;
_config = config;
_deviceManager = deviceManager;
- _timerFactory = timerFactory;
_localization = localization;
_activityManager = activityManager;
_coreNotificationTypes = new CoreNotificationTypes(localization, appHost).GetNotificationTypes().Select(i => i.Type).ToArray();
}
- public void Run()
+ public Task RunAsync()
{
_libraryManager.ItemAdded += _libraryManager_ItemAdded;
_appHost.HasPendingRestartChanged += _appHost_HasPendingRestartChanged;
_appHost.HasUpdateAvailableChanged += _appHost_HasUpdateAvailableChanged;
_activityManager.EntryCreated += _activityManager_EntryCreated;
+
+ return Task.CompletedTask;
}
private async void _appHost_HasPendingRestartChanged(object sender, EventArgs e)
@@ -157,7 +156,7 @@ namespace Emby.Notifications
{
if (LibraryUpdateTimer == null)
{
- LibraryUpdateTimer = _timerFactory.Create(LibraryUpdateTimerCallback, null, 5000,
+ LibraryUpdateTimer = new Timer(LibraryUpdateTimerCallback, null, 5000,
Timeout.Infinite);
}
else
diff --git a/Emby.Photos/PhotoProvider.cs b/Emby.Photos/PhotoProvider.cs
index aaebe1a21..f3457d105 100644
--- a/Emby.Photos/PhotoProvider.cs
+++ b/Emby.Photos/PhotoProvider.cs
@@ -181,7 +181,7 @@ namespace Emby.Photos
try
{
- var size = _imageProcessor.GetImageSize(item, img, false);
+ var size = _imageProcessor.GetImageDimensions(item, img, false);
if (size.Width > 0 && size.Height > 0)
{
diff --git a/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs b/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs
index efe8f98ec..739f68767 100644
--- a/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs
+++ b/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs
@@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
+using System.Threading.Tasks;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Plugins;
using MediaBrowser.Common.Updates;
@@ -58,7 +59,7 @@ namespace Emby.Server.Implementations.Activity
_deviceManager = deviceManager;
}
- public void Run()
+ public Task RunAsync()
{
_taskManager.TaskCompleted += _taskManager_TaskCompleted;
@@ -90,6 +91,8 @@ namespace Emby.Server.Implementations.Activity
_deviceManager.CameraImageUploaded += _deviceManager_CameraImageUploaded;
_appHost.ApplicationUpdated += _appHost_ApplicationUpdated;
+
+ return Task.CompletedTask;
}
void _deviceManager_CameraImageUploaded(object sender, GenericEventArgs<CameraImageUploadInfo> e)
@@ -207,10 +210,6 @@ namespace Emby.Server.Implementations.Activity
{
return NotificationType.AudioPlayback.ToString();
}
- if (string.Equals(mediaType, MediaType.Game, StringComparison.OrdinalIgnoreCase))
- {
- return NotificationType.GamePlayback.ToString();
- }
if (string.Equals(mediaType, MediaType.Video, StringComparison.OrdinalIgnoreCase))
{
return NotificationType.VideoPlayback.ToString();
@@ -225,10 +224,6 @@ namespace Emby.Server.Implementations.Activity
{
return NotificationType.AudioPlaybackStopped.ToString();
}
- if (string.Equals(mediaType, MediaType.Game, StringComparison.OrdinalIgnoreCase))
- {
- return NotificationType.GamePlaybackStopped.ToString();
- }
if (string.Equals(mediaType, MediaType.Video, StringComparison.OrdinalIgnoreCase))
{
return NotificationType.VideoPlaybackStopped.ToString();
diff --git a/Emby.Server.Implementations/AppBase/BaseApplicationPaths.cs b/Emby.Server.Implementations/AppBase/BaseApplicationPaths.cs
index e4a2cd9df..701c04f9e 100644
--- a/Emby.Server.Implementations/AppBase/BaseApplicationPaths.cs
+++ b/Emby.Server.Implementations/AppBase/BaseApplicationPaths.cs
@@ -16,12 +16,14 @@ namespace Emby.Server.Implementations.AppBase
string programDataPath,
string appFolderPath,
string logDirectoryPath = null,
- string configurationDirectoryPath = null)
+ string configurationDirectoryPath = null,
+ string cacheDirectoryPath = null)
{
ProgramDataPath = programDataPath;
ProgramSystemPath = appFolderPath;
LogDirectoryPath = logDirectoryPath;
ConfigurationDirectoryPath = configurationDirectoryPath;
+ CachePath = cacheDirectoryPath;
}
public string ProgramDataPath { get; private set; }
diff --git a/Emby.Server.Implementations/AppBase/BaseConfigurationManager.cs b/Emby.Server.Implementations/AppBase/BaseConfigurationManager.cs
index 90b43bc59..5feac1adf 100644
--- a/Emby.Server.Implementations/AppBase/BaseConfigurationManager.cs
+++ b/Emby.Server.Implementations/AppBase/BaseConfigurationManager.cs
@@ -171,16 +171,29 @@ namespace Emby.Server.Implementations.AppBase
private void UpdateCachePath()
{
string cachePath;
-
+ // If the configuration file has no entry (i.e. not set in UI)
if (string.IsNullOrWhiteSpace(CommonConfiguration.CachePath))
{
- cachePath = null;
+ // If the current live configuration has no entry (i.e. not set on CLI/envvars, during startup)
+ if (string.IsNullOrWhiteSpace(((BaseApplicationPaths)CommonApplicationPaths).CachePath))
+ {
+ // Set cachePath to a default value under ProgramDataPath
+ cachePath = Path.Combine(((BaseApplicationPaths)CommonApplicationPaths).ProgramDataPath, "cache");
+ }
+ else
+ {
+ // Set cachePath to the existing live value; will require restart if UI value is removed (but not replaced)
+ // TODO: Figure out how to re-grab this from the CLI/envvars while running
+ cachePath = ((BaseApplicationPaths)CommonApplicationPaths).CachePath;
+ }
}
else
{
- cachePath = Path.Combine(CommonConfiguration.CachePath, "cache");
+ // Set cachePath to the new UI-set value
+ cachePath = CommonConfiguration.CachePath;
}
+ Logger.LogInformation("Setting cache path to " + cachePath);
((BaseApplicationPaths)CommonApplicationPaths).CachePath = cachePath;
}
@@ -217,7 +230,7 @@ namespace Emby.Server.Implementations.AppBase
private string GetConfigurationFile(string key)
{
- return Path.Combine(CommonApplicationPaths.ConfigurationDirectoryPath, key.ToLower() + ".xml");
+ return Path.Combine(CommonApplicationPaths.ConfigurationDirectoryPath, key.ToLowerInvariant() + ".xml");
}
public object GetConfiguration(string key)
diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs
index 31dad48be..bb475eb2c 100644
--- a/Emby.Server.Implementations/ApplicationHost.cs
+++ b/Emby.Server.Implementations/ApplicationHost.cs
@@ -12,7 +12,6 @@ using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
-using Emby.Common.Implementations.Serialization;
using Emby.Dlna;
using Emby.Dlna.Main;
using Emby.Dlna.Ssdp;
@@ -43,7 +42,6 @@ using Emby.Server.Implementations.ScheduledTasks;
using Emby.Server.Implementations.Security;
using Emby.Server.Implementations.Serialization;
using Emby.Server.Implementations.Session;
-using Emby.Server.Implementations.Threading;
using Emby.Server.Implementations.TV;
using Emby.Server.Implementations.Updates;
using Emby.Server.Implementations.Xml;
@@ -99,7 +97,6 @@ using MediaBrowser.Model.Serialization;
using MediaBrowser.Model.Services;
using MediaBrowser.Model.System;
using MediaBrowser.Model.Tasks;
-using MediaBrowser.Model.Threading;
using MediaBrowser.Model.Updates;
using MediaBrowser.Model.Xml;
using MediaBrowser.Providers.Chapters;
@@ -110,7 +107,6 @@ using MediaBrowser.XbmcMetadata.Providers;
using Microsoft.Extensions.Logging;
using ServiceStack;
using ServiceStack.Text.Jsv;
-using StringExtensions = MediaBrowser.Controller.Extensions.StringExtensions;
using X509Certificate = System.Security.Cryptography.X509Certificates.X509Certificate;
namespace Emby.Server.Implementations
@@ -141,7 +137,7 @@ namespace Emby.Server.Implementations
return false;
}
- if (StartupOptions.ContainsOption("-service"))
+ if (StartupOptions.IsService)
{
return false;
}
@@ -302,7 +298,7 @@ namespace Emby.Server.Implementations
private ILiveTvManager LiveTvManager { get; set; }
- public ILocalizationManager LocalizationManager { get; set; }
+ public LocalizationManager LocalizationManager { get; set; }
private IEncodingManager EncodingManager { get; set; }
private IChannelManager ChannelManager { get; set; }
@@ -343,12 +339,11 @@ namespace Emby.Server.Implementations
protected IHttpResultFactory HttpResultFactory { get; private set; }
protected IAuthService AuthService { get; private set; }
- public StartupOptions StartupOptions { get; private set; }
+ public IStartupOptions StartupOptions { get; private set; }
internal IImageEncoder ImageEncoder { get; private set; }
protected IProcessFactory ProcessFactory { get; private set; }
- protected ITimerFactory TimerFactory { get; private set; }
protected ICryptoProvider CryptographyProvider = new CryptographyProvider();
protected readonly IXmlSerializer XmlSerializer;
@@ -364,7 +359,7 @@ namespace Emby.Server.Implementations
/// </summary>
public ApplicationHost(ServerApplicationPaths applicationPaths,
ILoggerFactory loggerFactory,
- StartupOptions options,
+ IStartupOptions options,
IFileSystem fileSystem,
IEnvironmentInfo environmentInfo,
IImageEncoder imageEncoder,
@@ -646,8 +641,10 @@ namespace Emby.Server.Implementations
/// <summary>
/// Runs the startup tasks.
/// </summary>
- public Task RunStartupTasks()
+ public async Task RunStartupTasks()
{
+ Logger.LogInformation("Running startup tasks");
+
Resolve<ITaskManager>().AddTasks(GetExports<IScheduledTask>(false));
ConfigurationManager.ConfigurationUpdated += OnConfigurationUpdated;
@@ -666,20 +663,20 @@ namespace Emby.Server.Implementations
Logger.LogInformation("ServerId: {0}", SystemId);
var entryPoints = GetExports<IServerEntryPoint>();
- RunEntryPoints(entryPoints, true);
+
+ var now = DateTime.UtcNow;
+ await Task.WhenAll(StartEntryPoints(entryPoints, true));
+ Logger.LogInformation("Executed all pre-startup entry points in {Elapsed:fff} ms", DateTime.Now - now);
Logger.LogInformation("Core startup complete");
HttpServer.GlobalResponse = null;
- Logger.LogInformation("Post-init migrations complete");
-
- RunEntryPoints(entryPoints, false);
- Logger.LogInformation("All entry points have started");
-
- return Task.CompletedTask;
+ now = DateTime.UtcNow;
+ await Task.WhenAll(StartEntryPoints(entryPoints, false));
+ Logger.LogInformation("Executed all post-startup entry points in {Elapsed:fff} ms", DateTime.Now - now);
}
- private void RunEntryPoints(IEnumerable<IServerEntryPoint> entryPoints, bool isBeforeStartup)
+ private IEnumerable<Task> StartEntryPoints(IEnumerable<IServerEntryPoint> entryPoints, bool isBeforeStartup)
{
foreach (var entryPoint in entryPoints)
{
@@ -688,22 +685,13 @@ namespace Emby.Server.Implementations
continue;
}
- var name = entryPoint.GetType().FullName;
- Logger.LogInformation("Starting entry point {Name}", name);
- var now = DateTime.UtcNow;
- try
- {
- entryPoint.Run();
- }
- catch (Exception ex)
- {
- Logger.LogError(ex, "Error while running entrypoint {Name}", name);
- }
- Logger.LogInformation("Entry point completed: {Name}. Duration: {Duration} seconds", name, (DateTime.UtcNow - now).TotalSeconds.ToString(CultureInfo.InvariantCulture), "ImageInfos");
+ Logger.LogDebug("Starting entry point {Type}", entryPoint.GetType());
+
+ yield return entryPoint.RunAsync();
}
}
- public void Init()
+ public async Task Init()
{
HttpPort = ServerConfigurationManager.Configuration.HttpServerPortNumber;
HttpsPort = ServerConfigurationManager.Configuration.HttpsPortNumber;
@@ -733,7 +721,7 @@ namespace Emby.Server.Implementations
SetHttpLimit();
- RegisterResources();
+ await RegisterResources();
FindParts();
}
@@ -748,7 +736,7 @@ namespace Emby.Server.Implementations
/// <summary>
/// Registers resources that classes will depend on
/// </summary>
- protected void RegisterResources()
+ protected async Task RegisterResources()
{
RegisterSingleInstance(ConfigurationManager);
RegisterSingleInstance<IApplicationHost>(this);
@@ -780,9 +768,6 @@ namespace Emby.Server.Implementations
ProcessFactory = new ProcessFactory();
RegisterSingleInstance(ProcessFactory);
- TimerFactory = new TimerFactory();
- RegisterSingleInstance(TimerFactory);
-
var streamHelper = CreateStreamHelper();
ApplicationHost.StreamHelper = streamHelper;
RegisterSingleInstance(streamHelper);
@@ -809,9 +794,9 @@ namespace Emby.Server.Implementations
IAssemblyInfo assemblyInfo = new AssemblyInfo();
RegisterSingleInstance(assemblyInfo);
- LocalizationManager = new LocalizationManager(ServerConfigurationManager, FileSystemManager, JsonSerializer, LoggerFactory, assemblyInfo, new TextLocalizer());
- StringExtensions.LocalizationManager = LocalizationManager;
- RegisterSingleInstance(LocalizationManager);
+ LocalizationManager = new LocalizationManager(ServerConfigurationManager, FileSystemManager, JsonSerializer, LoggerFactory);
+ await LocalizationManager.LoadAll();
+ RegisterSingleInstance<ILocalizationManager>(LocalizationManager);
BlurayExaminer = new BdInfoExaminer(FileSystemManager);
RegisterSingleInstance(BlurayExaminer);
@@ -845,7 +830,7 @@ namespace Emby.Server.Implementations
var musicManager = new MusicManager(LibraryManager);
RegisterSingleInstance<IMusicManager>(new MusicManager(LibraryManager));
- LibraryMonitor = new LibraryMonitor(LoggerFactory, TaskManager, LibraryManager, ServerConfigurationManager, FileSystemManager, TimerFactory, EnvironmentInfo);
+ LibraryMonitor = new LibraryMonitor(LoggerFactory, TaskManager, LibraryManager, ServerConfigurationManager, FileSystemManager, EnvironmentInfo);
RegisterSingleInstance(LibraryMonitor);
RegisterSingleInstance<ISearchEngine>(() => new SearchEngine(LoggerFactory, LibraryManager, UserManager));
@@ -877,7 +862,7 @@ namespace Emby.Server.Implementations
DeviceManager = new DeviceManager(AuthenticationRepository, JsonSerializer, LibraryManager, LocalizationManager, UserManager, FileSystemManager, LibraryMonitor, ServerConfigurationManager, LoggerFactory, NetworkManager);
RegisterSingleInstance(DeviceManager);
- MediaSourceManager = new MediaSourceManager(ItemRepository, ApplicationPaths, LocalizationManager, UserManager, LibraryManager, LoggerFactory, JsonSerializer, FileSystemManager, UserDataManager, TimerFactory, () => MediaEncoder);
+ MediaSourceManager = new MediaSourceManager(ItemRepository, ApplicationPaths, LocalizationManager, UserManager, LibraryManager, LoggerFactory, JsonSerializer, FileSystemManager, UserDataManager, () => MediaEncoder);
RegisterSingleInstance(MediaSourceManager);
SubtitleManager = new SubtitleManager(LoggerFactory, FileSystemManager, LibraryMonitor, MediaSourceManager, LocalizationManager);
@@ -892,7 +877,7 @@ namespace Emby.Server.Implementations
ChannelManager = new ChannelManager(UserManager, DtoService, LibraryManager, LoggerFactory, ServerConfigurationManager, FileSystemManager, UserDataManager, JsonSerializer, LocalizationManager, HttpClient, ProviderManager);
RegisterSingleInstance(ChannelManager);
- SessionManager = new SessionManager(UserDataManager, LoggerFactory, LibraryManager, UserManager, musicManager, DtoService, ImageProcessor, JsonSerializer, this, HttpClient, AuthenticationRepository, DeviceManager, MediaSourceManager, TimerFactory);
+ SessionManager = new SessionManager(UserDataManager, LoggerFactory, LibraryManager, UserManager, musicManager, DtoService, ImageProcessor, JsonSerializer, this, HttpClient, AuthenticationRepository, DeviceManager, MediaSourceManager);
RegisterSingleInstance(SessionManager);
var dlnaManager = new DlnaManager(XmlSerializer, FileSystemManager, ApplicationPaths, LoggerFactory, JsonSerializer, this, assemblyInfo);
@@ -904,7 +889,7 @@ namespace Emby.Server.Implementations
PlaylistManager = new PlaylistManager(LibraryManager, FileSystemManager, LibraryMonitor, LoggerFactory, UserManager, ProviderManager);
RegisterSingleInstance(PlaylistManager);
- LiveTvManager = new LiveTvManager(this, ServerConfigurationManager, LoggerFactory, ItemRepository, ImageProcessor, UserDataManager, DtoService, UserManager, LibraryManager, TaskManager, LocalizationManager, JsonSerializer, ProviderManager, FileSystemManager, () => ChannelManager);
+ LiveTvManager = new LiveTvManager(this, ServerConfigurationManager, LoggerFactory, ItemRepository, ImageProcessor, UserDataManager, DtoService, UserManager, LibraryManager, TaskManager, LocalizationManager, JsonSerializer, FileSystemManager, () => ChannelManager);
RegisterSingleInstance(LiveTvManager);
UserViewManager = new UserViewManager(LibraryManager, LocalizationManager, UserManager, ChannelManager, LiveTvManager, ServerConfigurationManager);
@@ -913,7 +898,7 @@ namespace Emby.Server.Implementations
NotificationManager = new NotificationManager(LoggerFactory, UserManager, ServerConfigurationManager);
RegisterSingleInstance(NotificationManager);
- RegisterSingleInstance<IDeviceDiscovery>(new DeviceDiscovery(LoggerFactory, ServerConfigurationManager, SocketFactory, TimerFactory));
+ RegisterSingleInstance<IDeviceDiscovery>(new DeviceDiscovery(LoggerFactory, ServerConfigurationManager, SocketFactory));
ChapterManager = new ChapterManager(LibraryManager, LoggerFactory, ServerConfigurationManager, ItemRepository);
RegisterSingleInstance(ChapterManager);
@@ -1671,7 +1656,6 @@ namespace Emby.Server.Implementations
var minRequiredVersions = new Dictionary<string, Version>(StringComparer.OrdinalIgnoreCase)
{
- { "GameBrowser.dll", new Version(3, 1) },
{ "moviethemesongs.dll", new Version(1, 6) },
{ "themesongs.dll", new Version(1, 2) }
};
@@ -1747,7 +1731,7 @@ namespace Emby.Server.Implementations
EncoderLocationType = MediaEncoder.EncoderLocationType,
SystemArchitecture = EnvironmentInfo.SystemArchitecture,
SystemUpdateLevel = SystemUpdateLevel,
- PackageName = StartupOptions.GetOption("-package")
+ PackageName = StartupOptions.PackageName
};
}
diff --git a/Emby.Server.Implementations/Collections/CollectionImageProvider.cs b/Emby.Server.Implementations/Collections/CollectionImageProvider.cs
index 6642d1ef4..6aeadda2f 100644
--- a/Emby.Server.Implementations/Collections/CollectionImageProvider.cs
+++ b/Emby.Server.Implementations/Collections/CollectionImageProvider.cs
@@ -70,7 +70,8 @@ namespace Emby.Server.Implementations.Collections
return null;
})
.Where(i => i != null)
- .DistinctBy(i => i.Id)
+ .GroupBy(x => x.Id)
+ .Select(x => x.First())
.OrderBy(i => Guid.NewGuid())
.ToList();
}
diff --git a/Emby.Server.Implementations/Collections/CollectionManager.cs b/Emby.Server.Implementations/Collections/CollectionManager.cs
index c8b822970..812e48a1f 100644
--- a/Emby.Server.Implementations/Collections/CollectionManager.cs
+++ b/Emby.Server.Implementations/Collections/CollectionManager.cs
@@ -353,7 +353,7 @@ namespace Emby.Server.Implementations.Collections
_logger = logger;
}
- public async void Run()
+ public async Task RunAsync()
{
if (!_config.Configuration.CollectionsUpgraded && _config.Configuration.IsStartupWizardCompleted)
{
diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs
index 3de4da444..3014e482d 100644
--- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs
+++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs
@@ -1239,10 +1239,6 @@ namespace Emby.Server.Implementations.Data
{
return false;
}
- else if (type == typeof(GameGenre))
- {
- return false;
- }
else if (type == typeof(Genre))
{
return false;
@@ -3905,7 +3901,7 @@ namespace Emby.Server.Implementations.Data
// lowercase this because SortName is stored as lowercase
if (statement != null)
{
- statement.TryBind("@NameStartsWithOrGreater", query.NameStartsWithOrGreater.ToLower());
+ statement.TryBind("@NameStartsWithOrGreater", query.NameStartsWithOrGreater.ToLowerInvariant());
}
}
if (!string.IsNullOrWhiteSpace(query.NameLessThan))
@@ -3914,7 +3910,7 @@ namespace Emby.Server.Implementations.Data
// lowercase this because SortName is stored as lowercase
if (statement != null)
{
- statement.TryBind("@NameLessThan", query.NameLessThan.ToLower());
+ statement.TryBind("@NameLessThan", query.NameLessThan.ToLowerInvariant());
}
}
@@ -4789,10 +4785,6 @@ namespace Emby.Server.Implementations.Data
{
list.Add(typeof(MusicGenre).Name);
}
- if (IsTypeInQuery(typeof(GameGenre).Name, query))
- {
- list.Add(typeof(GameGenre).Name);
- }
if (IsTypeInQuery(typeof(MusicArtist).Name, query))
{
list.Add(typeof(MusicArtist).Name);
@@ -4822,7 +4814,7 @@ namespace Emby.Server.Implementations.Data
return value;
}
- return value.RemoveDiacritics().ToLower();
+ return value.RemoveDiacritics().ToLowerInvariant();
}
private bool EnableGroupByPresentationUniqueKey(InternalItemsQuery query)
@@ -4891,9 +4883,6 @@ namespace Emby.Server.Implementations.Data
typeof(Book),
typeof(CollectionFolder),
typeof(Folder),
- typeof(Game),
- typeof(GameGenre),
- typeof(GameSystem),
typeof(Genre),
typeof(Person),
typeof(Photo),
@@ -5251,11 +5240,6 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
return GetItemValues(query, new[] { 2 }, typeof(Genre).FullName);
}
- public QueryResult<Tuple<BaseItem, ItemCounts>> GetGameGenres(InternalItemsQuery query)
- {
- return GetItemValues(query, new[] { 2 }, typeof(GameGenre).FullName);
- }
-
public QueryResult<Tuple<BaseItem, ItemCounts>> GetMusicGenres(InternalItemsQuery query)
{
return GetItemValues(query, new[] { 2 }, typeof(MusicGenre).FullName);
@@ -5276,14 +5260,9 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
return GetItemValueNames(new[] { 2 }, new List<string> { "Audio", "MusicVideo", "MusicAlbum", "MusicArtist" }, new List<string>());
}
- public List<string> GetGameGenreNames()
- {
- return GetItemValueNames(new[] { 2 }, new List<string> { "Game" }, new List<string>());
- }
-
public List<string> GetGenreNames()
{
- return GetItemValueNames(new[] { 2 }, new List<string>(), new List<string> { "Audio", "MusicVideo", "MusicAlbum", "MusicArtist", "Game", "GameSystem" });
+ return GetItemValueNames(new[] { 2 }, new List<string>(), new List<string> { "Audio", "MusicVideo", "MusicAlbum", "MusicArtist" });
}
private List<string> GetItemValueNames(int[] itemValueTypes, List<string> withItemTypes, List<string> excludeItemTypes)
@@ -5652,10 +5631,6 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
{
counts.SongCount = value;
}
- else if (string.Equals(typeName, typeof(Game).FullName, StringComparison.OrdinalIgnoreCase))
- {
- counts.GameCount = value;
- }
else if (string.Equals(typeName, typeof(Trailer).FullName, StringComparison.OrdinalIgnoreCase))
{
counts.TrailerCount = value;
diff --git a/Emby.Server.Implementations/Devices/DeviceManager.cs b/Emby.Server.Implementations/Devices/DeviceManager.cs
index e94a649bf..ec3649bca 100644
--- a/Emby.Server.Implementations/Devices/DeviceManager.cs
+++ b/Emby.Server.Implementations/Devices/DeviceManager.cs
@@ -425,7 +425,7 @@ namespace Emby.Server.Implementations.Devices
_logger = logger;
}
- public async void Run()
+ public async Task RunAsync()
{
if (!_config.Configuration.CameraUploadUpgraded && _config.Configuration.IsStartupWizardCompleted)
{
diff --git a/Emby.Server.Implementations/Diagnostics/CommonProcess.cs b/Emby.Server.Implementations/Diagnostics/CommonProcess.cs
index 55539eafc..78b22bda3 100644
--- a/Emby.Server.Implementations/Diagnostics/CommonProcess.cs
+++ b/Emby.Server.Implementations/Diagnostics/CommonProcess.cs
@@ -105,7 +105,7 @@ namespace Emby.Server.Implementations.Diagnostics
{
return _process.WaitForExit(timeMs);
}
-
+
public Task<bool> WaitForExitAsync(int timeMs)
{
//Note: For this function to work correctly, the option EnableRisingEvents needs to be set to true.
diff --git a/Emby.Server.Implementations/Dto/DtoService.cs b/Emby.Server.Implementations/Dto/DtoService.cs
index d0a7de11d..983eb51e6 100644
--- a/Emby.Server.Implementations/Dto/DtoService.cs
+++ b/Emby.Server.Implementations/Dto/DtoService.cs
@@ -374,10 +374,6 @@ namespace Emby.Server.Implementations.Dto
dto.MusicVideoCount = taggedItems.Count(i => i is MusicVideo);
dto.SongCount = taggedItems.Count(i => i is Audio);
}
- else if (item is GameGenre)
- {
- dto.GameCount = taggedItems.Count(i => i is Game);
- }
else
{
// This populates them all and covers Genre, Person, Studio, Year
@@ -385,7 +381,6 @@ namespace Emby.Server.Implementations.Dto
dto.ArtistCount = taggedItems.Count(i => i is MusicArtist);
dto.AlbumCount = taggedItems.Count(i => i is MusicAlbum);
dto.EpisodeCount = taggedItems.Count(i => i is Episode);
- dto.GameCount = taggedItems.Count(i => i is Game);
dto.MovieCount = taggedItems.Count(i => i is Movie);
dto.TrailerCount = taggedItems.Count(i => i is Trailer);
dto.MusicVideoCount = taggedItems.Count(i => i is MusicVideo);
@@ -532,17 +527,6 @@ namespace Emby.Server.Implementations.Dto
dto.Album = item.Album;
}
- private static void SetGameProperties(BaseItemDto dto, Game item)
- {
- dto.GameSystem = item.GameSystem;
- dto.MultiPartGameFiles = item.MultiPartGameFiles;
- }
-
- private static void SetGameSystemProperties(BaseItemDto dto, GameSystem item)
- {
- dto.GameSystem = item.GameSystemName;
- }
-
private string[] GetImageTags(BaseItem item, List<ItemImageInfo> images)
{
return images
@@ -636,7 +620,8 @@ namespace Emby.Server.Implementations.Dto
}
}).Where(i => i != null)
- .DistinctBy(i => i.Name, StringComparer.OrdinalIgnoreCase)
+ .GroupBy(i => i.Name, StringComparer.OrdinalIgnoreCase)
+ .Select(x => x.First())
.ToDictionary(i => i.Name, StringComparer.OrdinalIgnoreCase);
for (var i = 0; i < people.Count; i++)
@@ -698,11 +683,6 @@ namespace Emby.Server.Implementations.Dto
return _libraryManager.GetMusicGenreId(name);
}
- if (owner is Game || owner is GameSystem)
- {
- return _libraryManager.GetGameGenreId(name);
- }
-
return _libraryManager.GetGenreId(name);
}
@@ -1206,20 +1186,6 @@ namespace Emby.Server.Implementations.Dto
}
}
- var game = item as Game;
-
- if (game != null)
- {
- SetGameProperties(dto, game);
- }
-
- var gameSystem = item as GameSystem;
-
- if (gameSystem != null)
- {
- SetGameSystemProperties(dto, gameSystem);
- }
-
var musicVideo = item as MusicVideo;
if (musicVideo != null)
{
@@ -1452,7 +1418,7 @@ namespace Emby.Server.Implementations.Dto
try
{
- size = _imageProcessor.GetImageSize(item, imageInfo);
+ size = _imageProcessor.GetImageDimensions(item, imageInfo);
if (size.Width <= 0 || size.Height <= 0)
{
diff --git a/Emby.Server.Implementations/Emby.Server.Implementations.csproj b/Emby.Server.Implementations/Emby.Server.Implementations.csproj
index df7963b02..86b2efe54 100644
--- a/Emby.Server.Implementations/Emby.Server.Implementations.csproj
+++ b/Emby.Server.Implementations/Emby.Server.Implementations.csproj
@@ -1,4 +1,4 @@
-<Project Sdk="Microsoft.NET.Sdk">
+<Project Sdk="Microsoft.NET.Sdk">
<ItemGroup>
<ProjectReference Include="..\Emby.Naming\Emby.Naming.csproj" />
@@ -25,8 +25,7 @@
<PackageReference Include="ServiceStack.Text.Core" Version="5.4.0" />
<PackageReference Include="sharpcompress" Version="0.22.0" />
<PackageReference Include="SimpleInjector" Version="4.4.2" />
- <PackageReference Include="SQLitePCL.pretty.core" Version="1.1.8" />
- <PackageReference Include="SQLitePCLRaw.core" Version="1.1.11" />
+ <PackageReference Include="SQLitePCL.pretty.netstandard" Version="1.0.0" />
<PackageReference Include="UTF.Unknown" Version="1.0.0-beta1" />
</ItemGroup>
@@ -43,7 +42,7 @@
<EmbeddedResource Include="Localization\iso6392.txt" />
<EmbeddedResource Include="Localization\countries.json" />
<EmbeddedResource Include="Localization\Core\*.json" />
- <EmbeddedResource Include="Localization\Ratings\*.txt" />
+ <EmbeddedResource Include="Localization\Ratings\*.csv" />
</ItemGroup>
</Project>
diff --git a/Emby.Server.Implementations/EntryPoints/AutomaticRestartEntryPoint.cs b/Emby.Server.Implementations/EntryPoints/AutomaticRestartEntryPoint.cs
index 0fc4c3858..19ea09359 100644
--- a/Emby.Server.Implementations/EntryPoints/AutomaticRestartEntryPoint.cs
+++ b/Emby.Server.Implementations/EntryPoints/AutomaticRestartEntryPoint.cs
@@ -9,7 +9,6 @@ using MediaBrowser.Controller.Plugins;
using MediaBrowser.Controller.Session;
using MediaBrowser.Model.LiveTv;
using MediaBrowser.Model.Tasks;
-using MediaBrowser.Model.Threading;
using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.EntryPoints
@@ -22,11 +21,10 @@ namespace Emby.Server.Implementations.EntryPoints
private readonly ISessionManager _sessionManager;
private readonly IServerConfigurationManager _config;
private readonly ILiveTvManager _liveTvManager;
- private readonly ITimerFactory _timerFactory;
- private ITimer _timer;
+ private Timer _timer;
- public AutomaticRestartEntryPoint(IServerApplicationHost appHost, ILogger logger, ITaskManager iTaskManager, ISessionManager sessionManager, IServerConfigurationManager config, ILiveTvManager liveTvManager, ITimerFactory timerFactory)
+ public AutomaticRestartEntryPoint(IServerApplicationHost appHost, ILogger logger, ITaskManager iTaskManager, ISessionManager sessionManager, IServerConfigurationManager config, ILiveTvManager liveTvManager)
{
_appHost = appHost;
_logger = logger;
@@ -34,15 +32,16 @@ namespace Emby.Server.Implementations.EntryPoints
_sessionManager = sessionManager;
_config = config;
_liveTvManager = liveTvManager;
- _timerFactory = timerFactory;
}
- public void Run()
+ public Task RunAsync()
{
if (_appHost.CanSelfRestart)
{
_appHost.HasPendingRestartChanged += _appHost_HasPendingRestartChanged;
}
+
+ return Task.CompletedTask;
}
void _appHost_HasPendingRestartChanged(object sender, EventArgs e)
@@ -51,7 +50,7 @@ namespace Emby.Server.Implementations.EntryPoints
if (_appHost.HasPendingRestart)
{
- _timer = _timerFactory.Create(TimerCallback, null, TimeSpan.FromMinutes(15), TimeSpan.FromMinutes(15));
+ _timer = new Timer(TimerCallback, null, TimeSpan.FromMinutes(15), TimeSpan.FromMinutes(15));
}
}
diff --git a/Emby.Server.Implementations/EntryPoints/ExternalPortForwarding.cs b/Emby.Server.Implementations/EntryPoints/ExternalPortForwarding.cs
index 8755ee3a7..f26a70586 100644
--- a/Emby.Server.Implementations/EntryPoints/ExternalPortForwarding.cs
+++ b/Emby.Server.Implementations/EntryPoints/ExternalPortForwarding.cs
@@ -10,7 +10,6 @@ using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Plugins;
using MediaBrowser.Model.Dlna;
using MediaBrowser.Model.Events;
-using MediaBrowser.Model.Threading;
using Microsoft.Extensions.Logging;
using Mono.Nat;
@@ -24,19 +23,17 @@ namespace Emby.Server.Implementations.EntryPoints
private readonly IServerConfigurationManager _config;
private readonly IDeviceDiscovery _deviceDiscovery;
- private ITimer _timer;
- private readonly ITimerFactory _timerFactory;
+ private Timer _timer;
private NatManager _natManager;
- public ExternalPortForwarding(ILoggerFactory loggerFactory, IServerApplicationHost appHost, IServerConfigurationManager config, IDeviceDiscovery deviceDiscovery, IHttpClient httpClient, ITimerFactory timerFactory)
+ public ExternalPortForwarding(ILoggerFactory loggerFactory, IServerApplicationHost appHost, IServerConfigurationManager config, IDeviceDiscovery deviceDiscovery, IHttpClient httpClient)
{
_logger = loggerFactory.CreateLogger("PortMapper");
_appHost = appHost;
_config = config;
_deviceDiscovery = deviceDiscovery;
_httpClient = httpClient;
- _timerFactory = timerFactory;
_config.ConfigurationUpdated += _config_ConfigurationUpdated1;
}
@@ -61,17 +58,17 @@ namespace Emby.Server.Implementations.EntryPoints
return string.Join("|", values.ToArray());
}
- void _config_ConfigurationUpdated(object sender, EventArgs e)
+ private async void _config_ConfigurationUpdated(object sender, EventArgs e)
{
if (!string.Equals(_lastConfigIdentifier, GetConfigIdentifier(), StringComparison.OrdinalIgnoreCase))
{
DisposeNat();
- Run();
+ await RunAsync();
}
}
- public void Run()
+ public Task RunAsync()
{
if (_config.Configuration.EnableUPnP && _config.Configuration.EnableRemoteAccess)
{
@@ -80,6 +77,8 @@ namespace Emby.Server.Implementations.EntryPoints
_config.ConfigurationUpdated -= _config_ConfigurationUpdated;
_config.ConfigurationUpdated += _config_ConfigurationUpdated;
+
+ return Task.CompletedTask;
}
private void Start()
@@ -92,7 +91,7 @@ namespace Emby.Server.Implementations.EntryPoints
_natManager.StartDiscovery();
}
- _timer = _timerFactory.Create(ClearCreatedRules, null, TimeSpan.FromMinutes(10), TimeSpan.FromMinutes(10));
+ _timer = new Timer(ClearCreatedRules, null, TimeSpan.FromMinutes(10), TimeSpan.FromMinutes(10));
_deviceDiscovery.DeviceDiscovered += _deviceDiscovery_DeviceDiscovered;
diff --git a/Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs b/Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs
index 7a8b09cf7..038965647 100644
--- a/Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs
+++ b/Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Threading;
+using System.Threading.Tasks;
using MediaBrowser.Controller.Channels;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
@@ -13,7 +14,6 @@ using MediaBrowser.Controller.Session;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Events;
using MediaBrowser.Model.Extensions;
-using MediaBrowser.Model.Threading;
using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.EntryPoints
@@ -28,7 +28,6 @@ namespace Emby.Server.Implementations.EntryPoints
private readonly ISessionManager _sessionManager;
private readonly IUserManager _userManager;
private readonly ILogger _logger;
- private readonly ITimerFactory _timerFactory;
/// <summary>
/// The _library changed sync lock
@@ -46,7 +45,7 @@ namespace Emby.Server.Implementations.EntryPoints
/// Gets or sets the library update timer.
/// </summary>
/// <value>The library update timer.</value>
- private ITimer LibraryUpdateTimer { get; set; }
+ private Timer LibraryUpdateTimer { get; set; }
/// <summary>
/// The library update duration
@@ -55,17 +54,16 @@ namespace Emby.Server.Implementations.EntryPoints
private readonly IProviderManager _providerManager;
- public LibraryChangedNotifier(ILibraryManager libraryManager, ISessionManager sessionManager, IUserManager userManager, ILogger logger, ITimerFactory timerFactory, IProviderManager providerManager)
+ public LibraryChangedNotifier(ILibraryManager libraryManager, ISessionManager sessionManager, IUserManager userManager, ILogger logger, IProviderManager providerManager)
{
_libraryManager = libraryManager;
_sessionManager = sessionManager;
_userManager = userManager;
_logger = logger;
- _timerFactory = timerFactory;
_providerManager = providerManager;
}
- public void Run()
+ public Task RunAsync()
{
_libraryManager.ItemAdded += libraryManager_ItemAdded;
_libraryManager.ItemUpdated += libraryManager_ItemUpdated;
@@ -74,6 +72,8 @@ namespace Emby.Server.Implementations.EntryPoints
_providerManager.RefreshCompleted += _providerManager_RefreshCompleted;
_providerManager.RefreshStarted += _providerManager_RefreshStarted;
_providerManager.RefreshProgress += _providerManager_RefreshProgress;
+
+ return Task.CompletedTask;
}
private Dictionary<Guid, DateTime> _lastProgressMessageTimes = new Dictionary<Guid, DateTime>();
@@ -188,7 +188,7 @@ namespace Emby.Server.Implementations.EntryPoints
{
if (LibraryUpdateTimer == null)
{
- LibraryUpdateTimer = _timerFactory.Create(LibraryUpdateTimerCallback, null, LibraryUpdateDuration,
+ LibraryUpdateTimer = new Timer(LibraryUpdateTimerCallback, null, LibraryUpdateDuration,
Timeout.Infinite);
}
else
@@ -222,7 +222,7 @@ namespace Emby.Server.Implementations.EntryPoints
{
if (LibraryUpdateTimer == null)
{
- LibraryUpdateTimer = _timerFactory.Create(LibraryUpdateTimerCallback, null, LibraryUpdateDuration,
+ LibraryUpdateTimer = new Timer(LibraryUpdateTimerCallback, null, LibraryUpdateDuration,
Timeout.Infinite);
}
else
@@ -250,7 +250,7 @@ namespace Emby.Server.Implementations.EntryPoints
{
if (LibraryUpdateTimer == null)
{
- LibraryUpdateTimer = _timerFactory.Create(LibraryUpdateTimerCallback, null, LibraryUpdateDuration,
+ LibraryUpdateTimer = new Timer(LibraryUpdateTimerCallback, null, LibraryUpdateDuration,
Timeout.Infinite);
}
else
@@ -277,14 +277,21 @@ namespace Emby.Server.Implementations.EntryPoints
lock (_libraryChangedSyncLock)
{
// Remove dupes in case some were saved multiple times
- var foldersAddedTo = _foldersAddedTo.DistinctBy(i => i.Id).ToList();
+ var foldersAddedTo = _foldersAddedTo
+ .GroupBy(x => x.Id)
+ .Select(x => x.First())
+ .ToList();
- var foldersRemovedFrom = _foldersRemovedFrom.DistinctBy(i => i.Id).ToList();
+ var foldersRemovedFrom = _foldersRemovedFrom
+ .GroupBy(x => x.Id)
+ .Select(x => x.First())
+ .ToList();
var itemsUpdated = _itemsUpdated
- .Where(i => !_itemsAdded.Contains(i))
- .DistinctBy(i => i.Id)
- .ToList();
+ .Where(i => !_itemsAdded.Contains(i))
+ .GroupBy(x => x.Id)
+ .Select(x => x.First())
+ .ToList();
SendChangeNotifications(_itemsAdded.ToList(), itemsUpdated, _itemsRemoved.ToList(), foldersAddedTo, foldersRemovedFrom, CancellationToken.None);
diff --git a/Emby.Server.Implementations/EntryPoints/RecordingNotifier.cs b/Emby.Server.Implementations/EntryPoints/RecordingNotifier.cs
index e37ea96a1..0186da9e1 100644
--- a/Emby.Server.Implementations/EntryPoints/RecordingNotifier.cs
+++ b/Emby.Server.Implementations/EntryPoints/RecordingNotifier.cs
@@ -1,6 +1,7 @@
using System;
using System.Linq;
using System.Threading;
+using System.Threading.Tasks;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.LiveTv;
using MediaBrowser.Controller.Plugins;
@@ -24,12 +25,14 @@ namespace Emby.Server.Implementations.EntryPoints
_liveTvManager = liveTvManager;
}
- public void Run()
+ public Task RunAsync()
{
_liveTvManager.TimerCancelled += _liveTvManager_TimerCancelled;
_liveTvManager.SeriesTimerCancelled += _liveTvManager_SeriesTimerCancelled;
_liveTvManager.TimerCreated += _liveTvManager_TimerCreated;
_liveTvManager.SeriesTimerCreated += _liveTvManager_SeriesTimerCreated;
+
+ return Task.CompletedTask;
}
private void _liveTvManager_SeriesTimerCreated(object sender, MediaBrowser.Model.Events.GenericEventArgs<TimerEventInfo> e)
diff --git a/Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs b/Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs
index 92ea3a8f4..091dd6a45 100644
--- a/Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs
+++ b/Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Threading;
+using System.Threading.Tasks;
using MediaBrowser.Common.Plugins;
using MediaBrowser.Common.Updates;
using MediaBrowser.Controller;
@@ -49,7 +50,7 @@ namespace Emby.Server.Implementations.EntryPoints
_sessionManager = sessionManager;
}
- public void Run()
+ public Task RunAsync()
{
_userManager.UserDeleted += userManager_UserDeleted;
_userManager.UserUpdated += userManager_UserUpdated;
@@ -65,6 +66,8 @@ namespace Emby.Server.Implementations.EntryPoints
_installationManager.PackageInstallationFailed += _installationManager_PackageInstallationFailed;
_taskManager.TaskCompleted += _taskManager_TaskCompleted;
+
+ return Task.CompletedTask;
}
void _installationManager_PackageInstalling(object sender, InstallationEventArgs e)
diff --git a/Emby.Server.Implementations/EntryPoints/StartupWizard.cs b/Emby.Server.Implementations/EntryPoints/StartupWizard.cs
index 05c8b07ab..8be6db87d 100644
--- a/Emby.Server.Implementations/EntryPoints/StartupWizard.cs
+++ b/Emby.Server.Implementations/EntryPoints/StartupWizard.cs
@@ -1,3 +1,4 @@
+using System.Threading.Tasks;
using Emby.Server.Implementations.Browser;
using MediaBrowser.Controller;
using MediaBrowser.Controller.Configuration;
@@ -32,11 +33,11 @@ namespace Emby.Server.Implementations.EntryPoints
/// <summary>
/// Runs this instance.
/// </summary>
- public void Run()
+ public Task RunAsync()
{
if (!_appHost.CanLaunchWebBrowser)
{
- return;
+ return Task.CompletedTask;
}
if (!_config.Configuration.IsStartupWizardCompleted)
@@ -47,11 +48,13 @@ namespace Emby.Server.Implementations.EntryPoints
{
var options = ((ApplicationHost)_appHost).StartupOptions;
- if (!options.ContainsOption("-noautorunwebapp"))
+ if (!options.NoAutoRunWebApp)
{
BrowserLauncher.OpenWebApp(_appHost);
}
}
+
+ return Task.CompletedTask;
}
/// <summary>
diff --git a/Emby.Server.Implementations/EntryPoints/UdpServerEntryPoint.cs b/Emby.Server.Implementations/EntryPoints/UdpServerEntryPoint.cs
index 2c8246d13..5b90dc1fb 100644
--- a/Emby.Server.Implementations/EntryPoints/UdpServerEntryPoint.cs
+++ b/Emby.Server.Implementations/EntryPoints/UdpServerEntryPoint.cs
@@ -1,4 +1,5 @@
using System;
+using System.Threading.Tasks;
using Emby.Server.Implementations.Udp;
using MediaBrowser.Controller;
using MediaBrowser.Controller.Plugins;
@@ -43,7 +44,7 @@ namespace Emby.Server.Implementations.EntryPoints
/// <summary>
/// Runs this instance.
/// </summary>
- public void Run()
+ public Task RunAsync()
{
var udpServer = new UdpServer(_logger, _appHost, _json, _socketFactory);
@@ -57,6 +58,8 @@ namespace Emby.Server.Implementations.EntryPoints
{
_logger.LogError(ex, "Failed to start UDP Server");
}
+
+ return Task.CompletedTask;
}
/// <summary>
diff --git a/Emby.Server.Implementations/EntryPoints/UserDataChangeNotifier.cs b/Emby.Server.Implementations/EntryPoints/UserDataChangeNotifier.cs
index 9e71ffceb..774ed09da 100644
--- a/Emby.Server.Implementations/EntryPoints/UserDataChangeNotifier.cs
+++ b/Emby.Server.Implementations/EntryPoints/UserDataChangeNotifier.cs
@@ -10,7 +10,6 @@ using MediaBrowser.Controller.Session;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Extensions;
using MediaBrowser.Model.Session;
-using MediaBrowser.Model.Threading;
using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.EntryPoints
@@ -23,24 +22,24 @@ namespace Emby.Server.Implementations.EntryPoints
private readonly IUserManager _userManager;
private readonly object _syncLock = new object();
- private ITimer UpdateTimer { get; set; }
- private readonly ITimerFactory _timerFactory;
+ private Timer UpdateTimer { get; set; }
private const int UpdateDuration = 500;
private readonly Dictionary<Guid, List<BaseItem>> _changedItems = new Dictionary<Guid, List<BaseItem>>();
- public UserDataChangeNotifier(IUserDataManager userDataManager, ISessionManager sessionManager, ILogger logger, IUserManager userManager, ITimerFactory timerFactory)
+ public UserDataChangeNotifier(IUserDataManager userDataManager, ISessionManager sessionManager, ILogger logger, IUserManager userManager)
{
_userDataManager = userDataManager;
_sessionManager = sessionManager;
_logger = logger;
_userManager = userManager;
- _timerFactory = timerFactory;
}
- public void Run()
+ public Task RunAsync()
{
_userDataManager.UserDataSaved += _userDataManager_UserDataSaved;
+
+ return Task.CompletedTask;
}
void _userDataManager_UserDataSaved(object sender, UserDataSaveEventArgs e)
@@ -54,7 +53,7 @@ namespace Emby.Server.Implementations.EntryPoints
{
if (UpdateTimer == null)
{
- UpdateTimer = _timerFactory.Create(UpdateTimerCallback, null, UpdateDuration,
+ UpdateTimer = new Timer(UpdateTimerCallback, null, UpdateDuration,
Timeout.Infinite);
}
else
@@ -121,7 +120,8 @@ namespace Emby.Server.Implementations.EntryPoints
var user = _userManager.GetUserById(userId);
var dtoList = changedItems
- .DistinctBy(i => i.Id)
+ .GroupBy(x => x.Id)
+ .Select(x => x.First())
.Select(i =>
{
var dto = _userDataManager.GetUserDataDto(i, user);
diff --git a/Emby.Server.Implementations/FFMpeg/FFMpegLoader.cs b/Emby.Server.Implementations/FFMpeg/FFMpegLoader.cs
index 79a42f294..6167d1eaa 100644
--- a/Emby.Server.Implementations/FFMpeg/FFMpegLoader.cs
+++ b/Emby.Server.Implementations/FFMpeg/FFMpegLoader.cs
@@ -28,10 +28,10 @@ namespace Emby.Server.Implementations.FFMpeg
_ffmpegInstallInfo = ffmpegInstallInfo;
}
- public FFMpegInfo GetFFMpegInfo(StartupOptions options)
+ public FFMpegInfo GetFFMpegInfo(IStartupOptions options)
{
- var customffMpegPath = options.GetOption("-ffmpeg");
- var customffProbePath = options.GetOption("-ffprobe");
+ var customffMpegPath = options.FFmpegPath;
+ var customffProbePath = options.FFprobePath;
if (!string.IsNullOrWhiteSpace(customffMpegPath) && !string.IsNullOrWhiteSpace(customffProbePath))
{
diff --git a/Emby.Server.Implementations/HttpClientManager/HttpClientManager.cs b/Emby.Server.Implementations/HttpClientManager/HttpClientManager.cs
index a61247fd1..6ea1bd08e 100644
--- a/Emby.Server.Implementations/HttpClientManager/HttpClientManager.cs
+++ b/Emby.Server.Implementations/HttpClientManager/HttpClientManager.cs
@@ -264,7 +264,7 @@ namespace Emby.Server.Implementations.HttpClientManager
}
var url = options.Url;
- var urlHash = url.ToLower().GetMD5().ToString("N");
+ var urlHash = url.ToLowerInvariant().GetMD5().ToString("N");
var responseCachePath = Path.Combine(_appPaths.CachePath, "httpclient", urlHash);
@@ -374,11 +374,11 @@ namespace Emby.Server.Implementations.HttpClientManager
{
if (options.LogRequestAsDebug)
{
- _logger.LogDebug("HttpClientManager {0}: {1}", httpMethod.ToUpper(), options.Url);
+ _logger.LogDebug("HttpClientManager {0}: {1}", httpMethod.ToUpper(CultureInfo.CurrentCulture), options.Url);
}
else
{
- _logger.LogInformation("HttpClientManager {0}: {1}", httpMethod.ToUpper(), options.Url);
+ _logger.LogInformation("HttpClientManager {0}: {1}", httpMethod.ToUpper(CultureInfo.CurrentCulture), options.Url);
}
}
diff --git a/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs b/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs
index 0ad4d8406..7445fd3c2 100644
--- a/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs
+++ b/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs
@@ -394,7 +394,7 @@ namespace Emby.Server.Implementations.HttpServer
{
return contentType == null
? null
- : contentType.Split(';')[0].ToLower().Trim();
+ : contentType.Split(';')[0].ToLowerInvariant().Trim();
}
private static string SerializeToXmlString(object from)
diff --git a/Emby.Server.Implementations/IO/FileRefresher.cs b/Emby.Server.Implementations/IO/FileRefresher.cs
index 12532a497..3668f6a7a 100644
--- a/Emby.Server.Implementations/IO/FileRefresher.cs
+++ b/Emby.Server.Implementations/IO/FileRefresher.cs
@@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
+using System.Threading;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
@@ -9,7 +10,6 @@ using MediaBrowser.Model.Extensions;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.System;
using MediaBrowser.Model.Tasks;
-using MediaBrowser.Model.Threading;
using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.IO
@@ -22,8 +22,7 @@ namespace Emby.Server.Implementations.IO
private IServerConfigurationManager ConfigurationManager { get; set; }
private readonly IFileSystem _fileSystem;
private readonly List<string> _affectedPaths = new List<string>();
- private ITimer _timer;
- private readonly ITimerFactory _timerFactory;
+ private Timer _timer;
private readonly object _timerLock = new object();
public string Path { get; private set; }
@@ -31,7 +30,7 @@ namespace Emby.Server.Implementations.IO
private readonly IEnvironmentInfo _environmentInfo;
private readonly ILibraryManager _libraryManager;
- public FileRefresher(string path, IFileSystem fileSystem, IServerConfigurationManager configurationManager, ILibraryManager libraryManager, ITaskManager taskManager, ILogger logger, ITimerFactory timerFactory, IEnvironmentInfo environmentInfo, ILibraryManager libraryManager1)
+ public FileRefresher(string path, IFileSystem fileSystem, IServerConfigurationManager configurationManager, ILibraryManager libraryManager, ITaskManager taskManager, ILogger logger, IEnvironmentInfo environmentInfo, ILibraryManager libraryManager1)
{
logger.LogDebug("New file refresher created for {0}", path);
Path = path;
@@ -41,7 +40,6 @@ namespace Emby.Server.Implementations.IO
LibraryManager = libraryManager;
TaskManager = taskManager;
Logger = logger;
- _timerFactory = timerFactory;
_environmentInfo = environmentInfo;
_libraryManager = libraryManager1;
AddPath(path);
@@ -90,7 +88,7 @@ namespace Emby.Server.Implementations.IO
if (_timer == null)
{
- _timer = _timerFactory.Create(OnTimerCallback, null, TimeSpan.FromSeconds(ConfigurationManager.Configuration.LibraryMonitorDelay), TimeSpan.FromMilliseconds(-1));
+ _timer = new Timer(OnTimerCallback, null, TimeSpan.FromSeconds(ConfigurationManager.Configuration.LibraryMonitorDelay), TimeSpan.FromMilliseconds(-1));
}
else
{
@@ -146,8 +144,8 @@ namespace Emby.Server.Implementations.IO
.Distinct(StringComparer.OrdinalIgnoreCase)
.Select(GetAffectedBaseItem)
.Where(item => item != null)
- .DistinctBy(i => i.Id)
- .ToList();
+ .GroupBy(x => x.Id)
+ .Select(x => x.First());
foreach (var item in itemsToRefresh)
{
diff --git a/Emby.Server.Implementations/IO/LibraryMonitor.cs b/Emby.Server.Implementations/IO/LibraryMonitor.cs
index dad81c195..607a4d333 100644
--- a/Emby.Server.Implementations/IO/LibraryMonitor.cs
+++ b/Emby.Server.Implementations/IO/LibraryMonitor.cs
@@ -11,7 +11,6 @@ using MediaBrowser.Controller.Plugins;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.System;
using MediaBrowser.Model.Tasks;
-using MediaBrowser.Model.Threading;
using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.IO
@@ -35,7 +34,7 @@ namespace Emby.Server.Implementations.IO
/// <summary>
/// Any file name ending in any of these will be ignored by the watchers
/// </summary>
- private readonly string[] _alwaysIgnoreFiles = new string[]
+ private readonly HashSet<string> _alwaysIgnoreFiles = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
{
"small.jpg",
"albumart.jpg",
@@ -54,7 +53,7 @@ namespace Emby.Server.Implementations.IO
".actors"
};
- private readonly string[] _alwaysIgnoreExtensions = new string[]
+ private readonly HashSet<string> _alwaysIgnoreExtensions = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
{
// thumbs.db
".db",
@@ -134,7 +133,6 @@ namespace Emby.Server.Implementations.IO
private IServerConfigurationManager ConfigurationManager { get; set; }
private readonly IFileSystem _fileSystem;
- private readonly ITimerFactory _timerFactory;
private readonly IEnvironmentInfo _environmentInfo;
/// <summary>
@@ -146,7 +144,6 @@ namespace Emby.Server.Implementations.IO
ILibraryManager libraryManager,
IServerConfigurationManager configurationManager,
IFileSystem fileSystem,
- ITimerFactory timerFactory,
IEnvironmentInfo environmentInfo)
{
if (taskManager == null)
@@ -159,7 +156,6 @@ namespace Emby.Server.Implementations.IO
Logger = loggerFactory.CreateLogger(GetType().Name);
ConfigurationManager = configurationManager;
_fileSystem = fileSystem;
- _timerFactory = timerFactory;
_environmentInfo = environmentInfo;
}
@@ -460,8 +456,8 @@ namespace Emby.Server.Implementations.IO
var filename = Path.GetFileName(path);
var monitorPath = !string.IsNullOrEmpty(filename) &&
- !_alwaysIgnoreFiles.Contains(filename, StringComparer.OrdinalIgnoreCase) &&
- !_alwaysIgnoreExtensions.Contains(Path.GetExtension(path) ?? string.Empty, StringComparer.OrdinalIgnoreCase) &&
+ !_alwaysIgnoreFiles.Contains(filename) &&
+ !_alwaysIgnoreExtensions.Contains(Path.GetExtension(path)) &&
_alwaysIgnoreSubstrings.All(i => path.IndexOf(i, StringComparison.OrdinalIgnoreCase) == -1);
// Ignore certain files
@@ -545,7 +541,7 @@ namespace Emby.Server.Implementations.IO
}
}
- var newRefresher = new FileRefresher(path, _fileSystem, ConfigurationManager, LibraryManager, TaskManager, Logger, _timerFactory, _environmentInfo, LibraryManager);
+ var newRefresher = new FileRefresher(path, _fileSystem, ConfigurationManager, LibraryManager, TaskManager, Logger, _environmentInfo, LibraryManager);
newRefresher.Completed += NewRefresher_Completed;
_activeRefreshers.Add(newRefresher);
}
@@ -601,20 +597,26 @@ namespace Emby.Server.Implementations.IO
/// </summary>
public void Dispose()
{
- _disposed = true;
Dispose(true);
}
/// <summary>
/// Releases unmanaged and - optionally - managed resources.
/// </summary>
- /// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
- protected virtual void Dispose(bool dispose)
+ /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
+ protected virtual void Dispose(bool disposing)
{
- if (dispose)
+ if (_disposed)
+ {
+ return;
+ }
+
+ if (disposing)
{
Stop();
}
+
+ _disposed = true;
}
}
@@ -627,9 +629,10 @@ namespace Emby.Server.Implementations.IO
_monitor = monitor;
}
- public void Run()
+ public Task RunAsync()
{
_monitor.Start();
+ return Task.CompletedTask;
}
public void Dispose()
diff --git a/Emby.Server.Implementations/IStartupOptions.cs b/Emby.Server.Implementations/IStartupOptions.cs
new file mode 100644
index 000000000..24aaa76c0
--- /dev/null
+++ b/Emby.Server.Implementations/IStartupOptions.cs
@@ -0,0 +1,40 @@
+namespace Emby.Server.Implementations
+{
+ public interface IStartupOptions
+ {
+ /// <summary>
+ /// --ffmpeg
+ /// </summary>
+ string FFmpegPath { get; }
+
+ /// <summary>
+ /// --ffprobe
+ /// </summary>
+ string FFprobePath { get; }
+
+ /// <summary>
+ /// --service
+ /// </summary>
+ bool IsService { get; }
+
+ /// <summary>
+ /// --noautorunwebapp
+ /// </summary>
+ bool NoAutoRunWebApp { get; }
+
+ /// <summary>
+ /// --package-name
+ /// </summary>
+ string PackageName { get; }
+
+ /// <summary>
+ /// --restartpath
+ /// </summary>
+ string RestartPath { get; }
+
+ /// <summary>
+ /// --restartargs
+ /// </summary>
+ string RestartArgs { get; }
+ }
+}
diff --git a/Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs b/Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs
index 9705d54c9..109c21f18 100644
--- a/Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs
+++ b/Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs
@@ -215,7 +215,7 @@ namespace Emby.Server.Implementations.Images
{
return CreateSquareCollage(item, itemsWithImages, outputPath);
}
- if (item is Playlist || item is MusicGenre || item is Genre || item is GameGenre || item is PhotoAlbum)
+ if (item is Playlist || item is MusicGenre || item is Genre || item is PhotoAlbum)
{
return CreateSquareCollage(item, itemsWithImages, outputPath);
}
diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs
index f96a211ec..064006ebd 100644
--- a/Emby.Server.Implementations/Library/LibraryManager.cs
+++ b/Emby.Server.Implementations/Library/LibraryManager.cs
@@ -512,7 +512,7 @@ namespace Emby.Server.Implementations.Library
if (forceCaseInsensitive || !ConfigurationManager.Configuration.EnableCaseSensitiveItemIds)
{
- key = key.ToLower();
+ key = key.ToLowerInvariant();
}
key = type.FullName + key;
@@ -869,11 +869,6 @@ namespace Emby.Server.Implementations.Library
return GetItemByNameId<MusicGenre>(MusicGenre.GetPath, name);
}
- public Guid GetGameGenreId(string name)
- {
- return GetItemByNameId<GameGenre>(GameGenre.GetPath, name);
- }
-
/// <summary>
/// Gets a Genre
/// </summary>
@@ -895,16 +890,6 @@ namespace Emby.Server.Implementations.Library
}
/// <summary>
- /// Gets the game genre.
- /// </summary>
- /// <param name="name">The name.</param>
- /// <returns>Task{GameGenre}.</returns>
- public GameGenre GetGameGenre(string name)
- {
- return CreateItemByName<GameGenre>(GameGenre.GetPath, name, new DtoOptions(true));
- }
-
- /// <summary>
/// Gets a Year
/// </summary>
/// <param name="value">The value.</param>
@@ -1370,17 +1355,6 @@ namespace Emby.Server.Implementations.Library
return ItemRepository.GetGenres(query);
}
- public QueryResult<Tuple<BaseItem, ItemCounts>> GetGameGenres(InternalItemsQuery query)
- {
- if (query.User != null)
- {
- AddUserToQuery(query, query.User);
- }
-
- SetTopParentOrAncestorIds(query);
- return ItemRepository.GetGameGenres(query);
- }
-
public QueryResult<Tuple<BaseItem, ItemCounts>> GetMusicGenres(InternalItemsQuery query)
{
if (query.User != null)
diff --git a/Emby.Server.Implementations/Library/MediaSourceManager.cs b/Emby.Server.Implementations/Library/MediaSourceManager.cs
index b83fb9b39..24ab8e761 100644
--- a/Emby.Server.Implementations/Library/MediaSourceManager.cs
+++ b/Emby.Server.Implementations/Library/MediaSourceManager.cs
@@ -20,7 +20,6 @@ using MediaBrowser.Model.Globalization;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.MediaInfo;
using MediaBrowser.Model.Serialization;
-using MediaBrowser.Model.Threading;
using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.Library
@@ -36,7 +35,6 @@ namespace Emby.Server.Implementations.Library
private IMediaSourceProvider[] _providers;
private readonly ILogger _logger;
private readonly IUserDataManager _userDataManager;
- private readonly ITimerFactory _timerFactory;
private readonly Func<IMediaEncoder> _mediaEncoder;
private ILocalizationManager _localizationManager;
private IApplicationPaths _appPaths;
@@ -51,7 +49,6 @@ namespace Emby.Server.Implementations.Library
IJsonSerializer jsonSerializer,
IFileSystem fileSystem,
IUserDataManager userDataManager,
- ITimerFactory timerFactory,
Func<IMediaEncoder> mediaEncoder)
{
_itemRepo = itemRepo;
@@ -61,7 +58,6 @@ namespace Emby.Server.Implementations.Library
_jsonSerializer = jsonSerializer;
_fileSystem = fileSystem;
_userDataManager = userDataManager;
- _timerFactory = timerFactory;
_mediaEncoder = mediaEncoder;
_localizationManager = localizationManager;
_appPaths = applicationPaths;
@@ -322,18 +318,18 @@ namespace Emby.Server.Implementations.Library
private string[] NormalizeLanguage(string language)
{
- if (language != null)
+ if (language == null)
{
- var culture = _localizationManager.FindLanguageInfo(language);
- if (culture != null)
- {
- return culture.ThreeLetterISOLanguageNames;
- }
+ return Array.Empty<string>();
+ }
- return new string[] { language };
+ var culture = _localizationManager.FindLanguageInfo(language);
+ if (culture != null)
+ {
+ return culture.ThreeLetterISOLanguageNames;
}
- return Array.Empty<string>();
+ return new string[] { language };
}
private void SetDefaultSubtitleStreamIndex(MediaSourceInfo source, UserItemData userData, User user, bool allowRememberingSelection)
diff --git a/Emby.Server.Implementations/Library/Resolvers/PhotoResolver.cs b/Emby.Server.Implementations/Library/Resolvers/PhotoResolver.cs
index 9de766767..a3298c580 100644
--- a/Emby.Server.Implementations/Library/Resolvers/PhotoResolver.cs
+++ b/Emby.Server.Implementations/Library/Resolvers/PhotoResolver.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections.Generic;
using System.IO;
using System.Linq;
using MediaBrowser.Controller.Drawing;
@@ -85,7 +86,7 @@ namespace Emby.Server.Implementations.Library.Resolvers
return false;
}
- private static readonly string[] IgnoreFiles =
+ private static readonly HashSet<string> IgnoreFiles = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
{
"folder",
"thumb",
@@ -102,7 +103,7 @@ namespace Emby.Server.Implementations.Library.Resolvers
{
var filename = Path.GetFileNameWithoutExtension(path) ?? string.Empty;
- if (IgnoreFiles.Contains(filename, StringComparer.OrdinalIgnoreCase))
+ if (IgnoreFiles.Contains(filename))
{
return false;
}
@@ -112,7 +113,7 @@ namespace Emby.Server.Implementations.Library.Resolvers
return false;
}
- return imageProcessor.SupportedInputFormats.Contains((Path.GetExtension(path) ?? string.Empty).TrimStart('.'), StringComparer.OrdinalIgnoreCase);
+ return imageProcessor.SupportedInputFormats.Contains((Path.GetExtension(path) ?? string.Empty).TrimStart('.'));
}
}
diff --git a/Emby.Server.Implementations/Library/SearchEngine.cs b/Emby.Server.Implementations/Library/SearchEngine.cs
index 71638b197..9c7f7dfcb 100644
--- a/Emby.Server.Implementations/Library/SearchEngine.cs
+++ b/Emby.Server.Implementations/Library/SearchEngine.cs
@@ -99,14 +99,12 @@ namespace Emby.Server.Implementations.Library
if (!query.IncludeMedia)
{
AddIfMissing(includeItemTypes, typeof(Genre).Name);
- AddIfMissing(includeItemTypes, typeof(GameGenre).Name);
AddIfMissing(includeItemTypes, typeof(MusicGenre).Name);
}
}
else
{
AddIfMissing(excludeItemTypes, typeof(Genre).Name);
- AddIfMissing(excludeItemTypes, typeof(GameGenre).Name);
AddIfMissing(excludeItemTypes, typeof(MusicGenre).Name);
}
diff --git a/Emby.Server.Implementations/Library/UserManager.cs b/Emby.Server.Implementations/Library/UserManager.cs
index 70639dad5..40eda52c6 100644
--- a/Emby.Server.Implementations/Library/UserManager.cs
+++ b/Emby.Server.Implementations/Library/UserManager.cs
@@ -24,7 +24,6 @@ using MediaBrowser.Controller.Providers;
using MediaBrowser.Controller.Security;
using MediaBrowser.Controller.Session;
using MediaBrowser.Model.Configuration;
-using MediaBrowser.Model.Connect;
using MediaBrowser.Model.Cryptography;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
@@ -212,11 +211,8 @@ namespace Emby.Server.Implementations.Library
{
foreach (var user in users)
{
- if (!user.ConnectLinkType.HasValue || user.ConnectLinkType.Value == UserLinkType.LinkedUser)
- {
- user.Policy.IsAdministrator = true;
- UpdateUserPolicy(user, user.Policy, false);
- }
+ user.Policy.IsAdministrator = true;
+ UpdateUserPolicy(user, user.Policy, false);
}
}
}
@@ -272,13 +268,9 @@ namespace Emby.Server.Implementations.Library
if (user != null)
{
- // Authenticate using local credentials if not a guest
- if (!user.ConnectLinkType.HasValue || user.ConnectLinkType.Value != UserLinkType.Guest)
- {
- var authResult = await AuthenticateLocalUser(username, password, hashedPassword, user, remoteEndPoint).ConfigureAwait(false);
- authenticationProvider = authResult.Item1;
- success = authResult.Item2;
- }
+ var authResult = await AuthenticateLocalUser(username, password, hashedPassword, user, remoteEndPoint).ConfigureAwait(false);
+ authenticationProvider = authResult.Item1;
+ success = authResult.Item2;
}
else
{
@@ -455,30 +447,30 @@ namespace Emby.Server.Implementations.Library
private void UpdateInvalidLoginAttemptCount(User user, int newValue)
{
- if (user.Policy.InvalidLoginAttemptCount != newValue || newValue > 0)
+ if (user.Policy.InvalidLoginAttemptCount == newValue || newValue <= 0)
{
- user.Policy.InvalidLoginAttemptCount = newValue;
+ return;
+ }
- var maxCount = user.Policy.IsAdministrator ? 3 : 5;
+ user.Policy.InvalidLoginAttemptCount = newValue;
- // TODO: Fix
- /*
- var fireLockout = false;
+ var maxCount = user.Policy.IsAdministrator ? 3 : 5;
- if (newValue >= maxCount)
- {
- _logger.LogDebug("Disabling user {0} due to {1} unsuccessful login attempts.", user.Name, newValue.ToString(CultureInfo.InvariantCulture));
- user.Policy.IsDisabled = true;
+ var fireLockout = false;
- fireLockout = true;
- }*/
+ if (newValue >= maxCount)
+ {
+ _logger.LogDebug("Disabling user {0} due to {1} unsuccessful login attempts.", user.Name, newValue);
+ user.Policy.IsDisabled = true;
- UpdateUserPolicy(user, user.Policy, false);
+ fireLockout = true;
+ }
- /* if (fireLockout)
- {
- UserLockedOut?.Invoke(this, new GenericEventArgs<User>(user));
- }*/
+ UpdateUserPolicy(user, user.Policy, false);
+
+ if (fireLockout)
+ {
+ UserLockedOut?.Invoke(this, new GenericEventArgs<User>(user));
}
}
@@ -553,9 +545,6 @@ namespace Emby.Server.Implementations.Library
LastActivityDate = user.LastActivityDate,
LastLoginDate = user.LastLoginDate,
Configuration = user.Configuration,
- ConnectLinkType = user.ConnectLinkType,
- ConnectUserId = user.ConnectUserId,
- ConnectUserName = user.ConnectUserName,
ServerId = _appHost.SystemId,
Policy = user.Policy
};
@@ -814,11 +803,6 @@ namespace Emby.Server.Implementations.Library
throw new ArgumentNullException(nameof(user));
}
- if (user.ConnectLinkType.HasValue && user.ConnectLinkType.Value == UserLinkType.Guest)
- {
- throw new ArgumentException("Passwords for guests cannot be changed.");
- }
-
await GetAuthenticationProvider(user).ChangePassword(user, newPassword).ConfigureAwait(false);
UpdateUser(user);
@@ -925,11 +909,6 @@ namespace Emby.Server.Implementations.Library
null :
GetUserByName(enteredUsername);
- if (user != null && user.ConnectLinkType.HasValue && user.ConnectLinkType.Value == UserLinkType.Guest)
- {
- throw new ArgumentException("Unable to process forgot password request for guests.");
- }
-
var action = ForgotPasswordAction.InNetworkRequired;
string pinFile = null;
DateTime? expirationDate = null;
@@ -974,10 +953,7 @@ namespace Emby.Server.Implementations.Library
_lastPin = null;
_lastPasswordPinCreationResult = null;
- var users = Users.Where(i => !i.ConnectLinkType.HasValue || i.ConnectLinkType.Value != UserLinkType.Guest)
- .ToList();
-
- foreach (var user in users)
+ foreach (var user in Users)
{
await ResetPassword(user).ConfigureAwait(false);
@@ -1205,9 +1181,11 @@ namespace Emby.Server.Implementations.Library
_sessionManager = sessionManager;
}
- public void Run()
+ public Task RunAsync()
{
_userManager.UserPolicyUpdated += _userManager_UserPolicyUpdated;
+
+ return Task.CompletedTask;
}
private void _userManager_UserPolicyUpdated(object sender, GenericEventArgs<User> e)
diff --git a/Emby.Server.Implementations/Library/UserViewManager.cs b/Emby.Server.Implementations/Library/UserViewManager.cs
index 9fa859bde..e9ce682ee 100644
--- a/Emby.Server.Implementations/Library/UserViewManager.cs
+++ b/Emby.Server.Implementations/Library/UserViewManager.cs
@@ -308,9 +308,6 @@ namespace Emby.Server.Implementations.Library
mediaTypes.Add(MediaType.Book);
mediaTypes.Add(MediaType.Audio);
break;
- case CollectionType.Games:
- mediaTypes.Add(MediaType.Game);
- break;
case CollectionType.Music:
mediaTypes.Add(MediaType.Audio);
break;
@@ -336,7 +333,6 @@ namespace Emby.Server.Implementations.Library
typeof(Person).Name,
typeof(Studio).Name,
typeof(Year).Name,
- typeof(GameGenre).Name,
typeof(MusicGenre).Name,
typeof(Genre).Name
diff --git a/Emby.Server.Implementations/Library/Validators/GameGenresPostScanTask.cs b/Emby.Server.Implementations/Library/Validators/GameGenresPostScanTask.cs
deleted file mode 100644
index 2b067951d..000000000
--- a/Emby.Server.Implementations/Library/Validators/GameGenresPostScanTask.cs
+++ /dev/null
@@ -1,45 +0,0 @@
-using System;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.Persistence;
-using Microsoft.Extensions.Logging;
-
-namespace Emby.Server.Implementations.Library.Validators
-{
- /// <summary>
- /// Class GameGenresPostScanTask
- /// </summary>
- public class GameGenresPostScanTask : ILibraryPostScanTask
- {
- /// <summary>
- /// The _library manager
- /// </summary>
- private readonly ILibraryManager _libraryManager;
- private readonly ILogger _logger;
- private readonly IItemRepository _itemRepo;
-
- /// <summary>
- /// Initializes a new instance of the <see cref="GameGenresPostScanTask" /> class.
- /// </summary>
- /// <param name="libraryManager">The library manager.</param>
- /// <param name="logger">The logger.</param>
- public GameGenresPostScanTask(ILibraryManager libraryManager, ILogger logger, IItemRepository itemRepo)
- {
- _libraryManager = libraryManager;
- _logger = logger;
- _itemRepo = itemRepo;
- }
-
- /// <summary>
- /// Runs the specified progress.
- /// </summary>
- /// <param name="progress">The progress.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- public Task Run(IProgress<double> progress, CancellationToken cancellationToken)
- {
- return new GameGenresValidator(_libraryManager, _logger, _itemRepo).Run(progress, cancellationToken);
- }
- }
-}
diff --git a/Emby.Server.Implementations/Library/Validators/GameGenresValidator.cs b/Emby.Server.Implementations/Library/Validators/GameGenresValidator.cs
deleted file mode 100644
index f5ffa1e45..000000000
--- a/Emby.Server.Implementations/Library/Validators/GameGenresValidator.cs
+++ /dev/null
@@ -1,72 +0,0 @@
-using System;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.Persistence;
-using Microsoft.Extensions.Logging;
-
-namespace Emby.Server.Implementations.Library.Validators
-{
- class GameGenresValidator
- {
- /// <summary>
- /// The _library manager
- /// </summary>
- private readonly ILibraryManager _libraryManager;
-
- /// <summary>
- /// The _logger
- /// </summary>
- private readonly ILogger _logger;
- private readonly IItemRepository _itemRepo;
-
- public GameGenresValidator(ILibraryManager libraryManager, ILogger logger, IItemRepository itemRepo)
- {
- _libraryManager = libraryManager;
- _logger = logger;
- _itemRepo = itemRepo;
- }
-
- /// <summary>
- /// Runs the specified progress.
- /// </summary>
- /// <param name="progress">The progress.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- public async Task Run(IProgress<double> progress, CancellationToken cancellationToken)
- {
- var names = _itemRepo.GetGameGenreNames();
-
- var numComplete = 0;
- var count = names.Count;
-
- foreach (var name in names)
- {
- try
- {
- var item = _libraryManager.GetGameGenre(name);
-
- await item.RefreshMetadata(cancellationToken).ConfigureAwait(false);
- }
- catch (OperationCanceledException)
- {
- // Don't clutter the log
- throw;
- }
- catch (Exception ex)
- {
- _logger.LogError(ex, "Error refreshing {GenreName}", name);
- }
-
- numComplete++;
- double percent = numComplete;
- percent /= count;
- percent *= 100;
-
- progress.Report(percent);
- }
-
- progress.Report(100);
- }
- }
-}
diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
index 6a2a46c9f..84ca130b7 100644
--- a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
+++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
@@ -35,8 +35,6 @@ using MediaBrowser.Model.Providers;
using MediaBrowser.Model.Querying;
using MediaBrowser.Model.Reflection;
using MediaBrowser.Model.Serialization;
-using MediaBrowser.Model.System;
-using MediaBrowser.Model.Threading;
using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.LiveTv.EmbyTV
@@ -65,7 +63,6 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
public static EmbyTV Current;
- public event EventHandler DataSourceChanged;
public event EventHandler<GenericEventArgs<TimerInfo>> TimerCreated;
public event EventHandler<GenericEventArgs<string>> TimerCancelled;
@@ -88,7 +85,6 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
ILibraryMonitor libraryMonitor,
IProviderManager providerManager,
IMediaEncoder mediaEncoder,
- ITimerFactory timerFactory,
IProcessFactory processFactory)
{
Current = this;
@@ -110,7 +106,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
_streamHelper = streamHelper;
_seriesTimerProvider = new SeriesTimerManager(fileSystem, jsonSerializer, _logger, Path.Combine(DataPath, "seriestimers"));
- _timerProvider = new TimerManager(fileSystem, jsonSerializer, _logger, Path.Combine(DataPath, "timers"), _logger, timerFactory);
+ _timerProvider = new TimerManager(fileSystem, jsonSerializer, _logger, Path.Combine(DataPath, "timers"), _logger);
_timerProvider.TimerFired += _timerProvider_TimerFired;
_config.NamedConfigurationUpdated += _config_NamedConfigurationUpdated;
@@ -124,7 +120,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
}
}
- public async void Start()
+ public async Task Start()
{
_timerProvider.RestartTimers();
@@ -275,7 +271,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
foreach (var timer in seriesTimers)
{
- await UpdateTimersForSeriesTimer(timer, false, true).ConfigureAwait(false);
+ UpdateTimersForSeriesTimer(timer, false, true);
}
}
@@ -763,12 +759,12 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
_timerProvider.AddOrUpdate(timer, false);
}
- await UpdateTimersForSeriesTimer(info, true, false).ConfigureAwait(false);
+ UpdateTimersForSeriesTimer(info, true, false);
return info.Id;
}
- public async Task UpdateSeriesTimerAsync(SeriesTimerInfo info, CancellationToken cancellationToken)
+ public Task UpdateSeriesTimerAsync(SeriesTimerInfo info, CancellationToken cancellationToken)
{
var instance = _seriesTimerProvider.GetAll().FirstOrDefault(i => string.Equals(i.Id, info.Id, StringComparison.OrdinalIgnoreCase));
@@ -792,8 +788,10 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
_seriesTimerProvider.Update(instance);
- await UpdateTimersForSeriesTimer(instance, true, true).ConfigureAwait(false);
+ UpdateTimersForSeriesTimer(instance, true, true);
}
+
+ return Task.CompletedTask;
}
public Task UpdateTimerAsync(TimerInfo updatedTimer, CancellationToken cancellationToken)
@@ -2193,7 +2191,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
if (lockData)
{
- writer.WriteElementString("lockdata", true.ToString().ToLower());
+ writer.WriteElementString("lockdata", true.ToString(CultureInfo.InvariantCulture).ToLowerInvariant());
}
if (item.CriticRating.HasValue)
@@ -2346,10 +2344,9 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
}
}
- private async Task UpdateTimersForSeriesTimer(SeriesTimerInfo seriesTimer, bool updateTimerSettings, bool deleteInvalidTimers)
+ private void UpdateTimersForSeriesTimer(SeriesTimerInfo seriesTimer, bool updateTimerSettings, bool deleteInvalidTimers)
{
- var allTimers = GetTimersForSeries(seriesTimer)
- .ToList();
+ var allTimers = GetTimersForSeries(seriesTimer).ToList();
var enabledTimersForSeries = new List<TimerInfo>();
diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EntryPoint.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EntryPoint.cs
index 982a54b68..9c9ba09f5 100644
--- a/Emby.Server.Implementations/LiveTv/EmbyTV/EntryPoint.cs
+++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EntryPoint.cs
@@ -1,12 +1,13 @@
+using System.Threading.Tasks;
using MediaBrowser.Controller.Plugins;
namespace Emby.Server.Implementations.LiveTv.EmbyTV
{
public class EntryPoint : IServerEntryPoint
{
- public void Run()
+ public Task RunAsync()
{
- EmbyTV.Current.Start();
+ return EmbyTV.Current.Start();
}
public void Dispose()
diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs
index 7f67d70a9..1dcb02f43 100644
--- a/Emby.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs
+++ b/Emby.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs
@@ -2,29 +2,27 @@ using System;
using System.Collections.Concurrent;
using System.Globalization;
using System.Linq;
+using System.Threading;
using MediaBrowser.Controller.LiveTv;
using MediaBrowser.Model.Events;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.LiveTv;
using MediaBrowser.Model.Serialization;
-using MediaBrowser.Model.Threading;
using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.LiveTv.EmbyTV
{
public class TimerManager : ItemDataProvider<TimerInfo>
{
- private readonly ConcurrentDictionary<string, ITimer> _timers = new ConcurrentDictionary<string, ITimer>(StringComparer.OrdinalIgnoreCase);
+ private readonly ConcurrentDictionary<string, Timer> _timers = new ConcurrentDictionary<string, Timer>(StringComparer.OrdinalIgnoreCase);
private readonly ILogger _logger;
public event EventHandler<GenericEventArgs<TimerInfo>> TimerFired;
- private readonly ITimerFactory _timerFactory;
- public TimerManager(IFileSystem fileSystem, IJsonSerializer jsonSerializer, ILogger logger, string dataPath, ILogger logger1, ITimerFactory timerFactory)
+ public TimerManager(IFileSystem fileSystem, IJsonSerializer jsonSerializer, ILogger logger, string dataPath, ILogger logger1)
: base(fileSystem, jsonSerializer, logger, dataPath, (r1, r2) => string.Equals(r1.Id, r2.Id, StringComparison.OrdinalIgnoreCase))
{
_logger = logger1;
- _timerFactory = timerFactory;
}
public void RestartTimers()
@@ -125,7 +123,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
private void StartTimer(TimerInfo item, TimeSpan dueTime)
{
- var timer = _timerFactory.Create(TimerCallback, item.Id, dueTime, TimeSpan.Zero);
+ var timer = new Timer(TimerCallback, item.Id, dueTime, TimeSpan.Zero);
if (_timers.TryAdd(item.Id, timer))
{
diff --git a/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs b/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs
index f152ac465..69b10e6da 100644
--- a/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs
+++ b/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs
@@ -17,7 +17,7 @@ using MediaBrowser.Model.IO;
using MediaBrowser.Model.LiveTv;
using Microsoft.Extensions.Logging;
-namespace Jellyfin.Server.Implementations.LiveTv.Listings
+namespace Emby.Server.Implementations.LiveTv.Listings
{
public class XmlTvListingsProvider : IListingsProvider
{
diff --git a/Emby.Server.Implementations/LiveTv/LiveTvDtoService.cs b/Emby.Server.Implementations/LiveTv/LiveTvDtoService.cs
index 724e8afdf..1144c9ab1 100644
--- a/Emby.Server.Implementations/LiveTv/LiveTvDtoService.cs
+++ b/Emby.Server.Implementations/LiveTv/LiveTvDtoService.cs
@@ -399,7 +399,7 @@ namespace Emby.Server.Implementations.LiveTv
{
var name = serviceName + externalId + InternalVersionNumber;
- return _libraryManager.GetNewItemId(name.ToLower(), typeof(LiveTvChannel));
+ return _libraryManager.GetNewItemId(name.ToLowerInvariant(), typeof(LiveTvChannel));
}
private const string ServiceName = "Emby";
@@ -407,21 +407,21 @@ namespace Emby.Server.Implementations.LiveTv
{
var name = ServiceName + externalId + InternalVersionNumber;
- return name.ToLower().GetMD5().ToString("N");
+ return name.ToLowerInvariant().GetMD5().ToString("N");
}
public Guid GetInternalSeriesTimerId(string externalId)
{
var name = ServiceName + externalId + InternalVersionNumber;
- return name.ToLower().GetMD5();
+ return name.ToLowerInvariant().GetMD5();
}
public Guid GetInternalProgramId(string externalId)
{
var name = ServiceName + externalId + InternalVersionNumber;
- return _libraryManager.GetNewItemId(name.ToLower(), typeof(LiveTvProgram));
+ return _libraryManager.GetNewItemId(name.ToLowerInvariant(), typeof(LiveTvProgram));
}
public async Task<TimerInfo> GetTimerInfo(TimerInfoDto dto, bool isNew, LiveTvManager liveTv, CancellationToken cancellationToken)
diff --git a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs
index 575cb1c77..a36302876 100644
--- a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs
+++ b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs
@@ -6,7 +6,6 @@ using System.Threading.Tasks;
using Emby.Server.Implementations.Library;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Extensions;
-using MediaBrowser.Common.Net;
using MediaBrowser.Common.Progress;
using MediaBrowser.Controller;
using MediaBrowser.Controller.Channels;
@@ -24,7 +23,6 @@ using MediaBrowser.Controller.Sorting;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Events;
-using MediaBrowser.Model.Extensions;
using MediaBrowser.Model.Globalization;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.LiveTv;
@@ -48,7 +46,6 @@ namespace Emby.Server.Implementations.LiveTv
private readonly ILibraryManager _libraryManager;
private readonly ITaskManager _taskManager;
private readonly IJsonSerializer _jsonSerializer;
- private readonly IProviderManager _providerManager;
private readonly Func<IChannelManager> _channelManager;
private readonly IDtoService _dtoService;
@@ -56,7 +53,7 @@ namespace Emby.Server.Implementations.LiveTv
private readonly LiveTvDtoService _tvDtoService;
- private ILiveTvService[] _services = new ILiveTvService[] { };
+ private ILiveTvService[] _services = Array.Empty<ILiveTvService>();
private ITunerHost[] _tunerHosts = Array.Empty<ITunerHost>();
private IListingsProvider[] _listingProviders = Array.Empty<IListingsProvider>();
@@ -85,7 +82,6 @@ namespace Emby.Server.Implementations.LiveTv
ITaskManager taskManager,
ILocalizationManager localization,
IJsonSerializer jsonSerializer,
- IProviderManager providerManager,
IFileSystem fileSystem,
Func<IChannelManager> channelManager)
{
@@ -97,7 +93,6 @@ namespace Emby.Server.Implementations.LiveTv
_taskManager = taskManager;
_localization = localization;
_jsonSerializer = jsonSerializer;
- _providerManager = providerManager;
_fileSystem = fileSystem;
_dtoService = dtoService;
_userDataManager = userDataManager;
@@ -132,8 +127,6 @@ namespace Emby.Server.Implementations.LiveTv
foreach (var service in _services)
{
- service.DataSourceChanged += service_DataSourceChanged;
-
if (service is EmbyTV.EmbyTV embyTv)
{
embyTv.TimerCreated += EmbyTv_TimerCreated;
@@ -189,14 +182,6 @@ namespace Emby.Server.Implementations.LiveTv
return EmbyTV.EmbyTV.Current.DiscoverTuners(newDevicesOnly, cancellationToken);
}
- void service_DataSourceChanged(object sender, EventArgs e)
- {
- if (!_isDisposed)
- {
- _taskManager.CancelIfRunningAndQueue<RefreshChannelsScheduledTask>();
- }
- }
-
public QueryResult<BaseItem> GetInternalChannels(LiveTvChannelQuery query, DtoOptions dtoOptions, CancellationToken cancellationToken)
{
var user = query.UserId.Equals(Guid.Empty) ? null : _userManager.GetUserById(query.UserId);
@@ -2158,17 +2143,28 @@ namespace Emby.Server.Implementations.LiveTv
Dispose(true);
}
- private bool _isDisposed = false;
+ private bool _disposed = false;
/// <summary>
/// Releases unmanaged and - optionally - managed resources.
/// </summary>
/// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
protected virtual void Dispose(bool dispose)
{
+ if (_disposed)
+ {
+ return;
+ }
+
if (dispose)
{
- _isDisposed = true;
+ // TODO: Dispose stuff
}
+
+ _services = null;
+ _listingProviders = null;
+ _tunerHosts = null;
+
+ _disposed = true;
}
private LiveTvServiceInfo[] GetServiceInfos()
@@ -2469,7 +2465,8 @@ namespace Emby.Server.Implementations.LiveTv
.Where(i => i != null)
.Where(i => i.IsVisibleStandalone(user))
.SelectMany(i => _libraryManager.GetCollectionFolders(i))
- .DistinctBy(i => i.Id)
+ .GroupBy(x => x.Id)
+ .Select(x => x.First())
.OrderBy(i => i.SortName)
.ToList();
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs
index 716417ccb..4eff9252e 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs
@@ -94,7 +94,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
var now = DateTime.UtcNow;
- StartStreaming(response, taskCompletionSource, LiveStreamCancellationTokenSource.Token);
+ var _ = StartStreaming(response, taskCompletionSource, LiveStreamCancellationTokenSource.Token);
//OpenedMediaSource.Protocol = MediaProtocol.File;
//OpenedMediaSource.Path = tempFile;
diff --git a/Emby.Server.Implementations/Localization/Core/ar.json b/Emby.Server.Implementations/Localization/Core/ar.json
index ec2c3f237..eb145b4fe 100644
--- a/Emby.Server.Implementations/Localization/Core/ar.json
+++ b/Emby.Server.Implementations/Localization/Core/ar.json
@@ -14,7 +14,6 @@
"FailedLoginAttemptWithUserName": "عملية تسجيل الدخول فشلت من {0}",
"Favorites": "المفضلات",
"Folders": "المجلدات",
- "Games": "الألعاب",
"Genres": "أنواع الأفلام",
"HeaderAlbumArtists": "فنانو الألبومات",
"HeaderCameraUploads": "Camera Uploads",
@@ -51,8 +50,6 @@
"NotificationOptionAudioPlayback": "بدأ تشغيل المقطع الصوتي",
"NotificationOptionAudioPlaybackStopped": "تم إيقاف تشغيل المقطع الصوتي",
"NotificationOptionCameraImageUploaded": "تم رقع صورة الكاميرا",
- "NotificationOptionGamePlayback": "تم تشغيل اللعبة",
- "NotificationOptionGamePlaybackStopped": "تم إيقاف تشغيل اللعبة",
"NotificationOptionInstallationFailed": "عملية التنصيب فشلت",
"NotificationOptionNewLibraryContent": "تم إضافة محتوى جديد",
"NotificationOptionPluginError": "فشل في الملحق",
diff --git a/Emby.Server.Implementations/Localization/Core/bg-BG.json b/Emby.Server.Implementations/Localization/Core/bg-BG.json
index ba6c98555..a71dc9346 100644
--- a/Emby.Server.Implementations/Localization/Core/bg-BG.json
+++ b/Emby.Server.Implementations/Localization/Core/bg-BG.json
@@ -14,7 +14,6 @@
"FailedLoginAttemptWithUserName": "Failed login attempt from {0}",
"Favorites": "Любими",
"Folders": "Папки",
- "Games": "Игри",
"Genres": "Жанрове",
"HeaderAlbumArtists": "Изпълнители на албуми",
"HeaderCameraUploads": "Camera Uploads",
@@ -51,8 +50,6 @@
"NotificationOptionAudioPlayback": "Възпроизвеждането на звук започна",
"NotificationOptionAudioPlaybackStopped": "Възпроизвеждането на звук е спряно",
"NotificationOptionCameraImageUploaded": "Изображението от фотоапарата е качено",
- "NotificationOptionGamePlayback": "Възпроизвеждането на играта започна",
- "NotificationOptionGamePlaybackStopped": "Възпроизвеждането на играта е спряна",
"NotificationOptionInstallationFailed": "Неуспешно инсталиране",
"NotificationOptionNewLibraryContent": "Добавено е ново съдържание",
"NotificationOptionPluginError": "Грешка в приставка",
diff --git a/Emby.Server.Implementations/Localization/Core/ca.json b/Emby.Server.Implementations/Localization/Core/ca.json
index a818b78de..74406a064 100644
--- a/Emby.Server.Implementations/Localization/Core/ca.json
+++ b/Emby.Server.Implementations/Localization/Core/ca.json
@@ -14,7 +14,6 @@
"FailedLoginAttemptWithUserName": "Intent de connexió fallit des de {0}",
"Favorites": "Preferits",
"Folders": "Directoris",
- "Games": "Jocs",
"Genres": "Gèneres",
"HeaderAlbumArtists": "Album Artists",
"HeaderCameraUploads": "Camera Uploads",
@@ -51,8 +50,6 @@
"NotificationOptionAudioPlayback": "Audio playback started",
"NotificationOptionAudioPlaybackStopped": "Audio playback stopped",
"NotificationOptionCameraImageUploaded": "Camera image uploaded",
- "NotificationOptionGamePlayback": "Game playback started",
- "NotificationOptionGamePlaybackStopped": "Game playback stopped",
"NotificationOptionInstallationFailed": "Installation failure",
"NotificationOptionNewLibraryContent": "New content added",
"NotificationOptionPluginError": "Un component ha fallat",
diff --git a/Emby.Server.Implementations/Localization/Core/cs.json b/Emby.Server.Implementations/Localization/Core/cs.json
index e066051a8..a8b4a4424 100644
--- a/Emby.Server.Implementations/Localization/Core/cs.json
+++ b/Emby.Server.Implementations/Localization/Core/cs.json
@@ -14,7 +14,6 @@
"FailedLoginAttemptWithUserName": "Neúspěšný pokus o přihlášení z {0}",
"Favorites": "Oblíbené",
"Folders": "Složky",
- "Games": "Hry",
"Genres": "Žánry",
"HeaderAlbumArtists": "Umělci alba",
"HeaderCameraUploads": "Camera Uploads",
@@ -51,8 +50,6 @@
"NotificationOptionAudioPlayback": "Přehrávání audia zahájeno",
"NotificationOptionAudioPlaybackStopped": "Přehrávání audia ukončeno",
"NotificationOptionCameraImageUploaded": "Kamerový záznam nahrán",
- "NotificationOptionGamePlayback": "Spuštění hry zahájeno",
- "NotificationOptionGamePlaybackStopped": "Hra ukončena",
"NotificationOptionInstallationFailed": "Chyba instalace",
"NotificationOptionNewLibraryContent": "Přidán nový obsah",
"NotificationOptionPluginError": "Chyba zásuvného modulu",
diff --git a/Emby.Server.Implementations/Localization/Core/da.json b/Emby.Server.Implementations/Localization/Core/da.json
index 30581c389..7004d44db 100644
--- a/Emby.Server.Implementations/Localization/Core/da.json
+++ b/Emby.Server.Implementations/Localization/Core/da.json
@@ -14,7 +14,6 @@
"FailedLoginAttemptWithUserName": "Fejlet loginforsøg fra {0}",
"Favorites": "Favoritter",
"Folders": "Mapper",
- "Games": "Spil",
"Genres": "Genre",
"HeaderAlbumArtists": "Albumkunstnere",
"HeaderCameraUploads": "Camera Uploads",
@@ -51,8 +50,6 @@
"NotificationOptionAudioPlayback": "Audioafspilning påbegyndt",
"NotificationOptionAudioPlaybackStopped": "Audioafspilning stoppet",
"NotificationOptionCameraImageUploaded": "Kamerabillede uploadet",
- "NotificationOptionGamePlayback": "Afspilning af Spil påbegyndt",
- "NotificationOptionGamePlaybackStopped": "Afspilning af Spil stoppet",
"NotificationOptionInstallationFailed": "Installationsfejl",
"NotificationOptionNewLibraryContent": "Nyt indhold tilføjet",
"NotificationOptionPluginError": "Pluginfejl",
diff --git a/Emby.Server.Implementations/Localization/Core/de.json b/Emby.Server.Implementations/Localization/Core/de.json
index 98cb07663..7bd2e90fe 100644
--- a/Emby.Server.Implementations/Localization/Core/de.json
+++ b/Emby.Server.Implementations/Localization/Core/de.json
@@ -14,7 +14,6 @@
"FailedLoginAttemptWithUserName": "Fehlgeschlagener Anmeldeversuch von {0}",
"Favorites": "Favoriten",
"Folders": "Verzeichnisse",
- "Games": "Spiele",
"Genres": "Genres",
"HeaderAlbumArtists": "Album-Künstler",
"HeaderCameraUploads": "Kamera Uploads",
@@ -51,8 +50,6 @@
"NotificationOptionAudioPlayback": "Audiowiedergabe gestartet",
"NotificationOptionAudioPlaybackStopped": "Audiowiedergabe gestoppt",
"NotificationOptionCameraImageUploaded": "Kamera Bild hochgeladen",
- "NotificationOptionGamePlayback": "Spielwiedergabe gestartet",
- "NotificationOptionGamePlaybackStopped": "Spielwiedergabe gestoppt",
"NotificationOptionInstallationFailed": "Installationsfehler",
"NotificationOptionNewLibraryContent": "Neuer Inhalt hinzugefügt",
"NotificationOptionPluginError": "Plugin Fehler",
diff --git a/Emby.Server.Implementations/Localization/Core/el.json b/Emby.Server.Implementations/Localization/Core/el.json
index ba687a089..91ca34edc 100644
--- a/Emby.Server.Implementations/Localization/Core/el.json
+++ b/Emby.Server.Implementations/Localization/Core/el.json
@@ -14,7 +14,6 @@
"FailedLoginAttemptWithUserName": "Αποτυχημένη προσπάθεια σύνδεσης από {0}",
"Favorites": "Αγαπημένα",
"Folders": "Φάκελοι",
- "Games": "Παιχνίδια",
"Genres": "Είδη",
"HeaderAlbumArtists": "Άλμπουμ Καλλιτεχνών",
"HeaderCameraUploads": "Camera Uploads",
@@ -51,8 +50,6 @@
"NotificationOptionAudioPlayback": "Η αναπαραγωγή ήχου ξεκίνησε",
"NotificationOptionAudioPlaybackStopped": "Η αναπαραγωγή ήχου σταμάτησε",
"NotificationOptionCameraImageUploaded": "Camera image uploaded",
- "NotificationOptionGamePlayback": "Η αναπαραγωγή του παιχνιδιού ξεκίνησε",
- "NotificationOptionGamePlaybackStopped": "Η αναπαραγωγή του παιχνιδιού σταμάτησε",
"NotificationOptionInstallationFailed": "Αποτυχία εγκατάστασης",
"NotificationOptionNewLibraryContent": "Προστέθηκε νέο περιεχόμενο",
"NotificationOptionPluginError": "Αποτυχία του plugin",
diff --git a/Emby.Server.Implementations/Localization/Core/en-GB.json b/Emby.Server.Implementations/Localization/Core/en-GB.json
index 20d397a1a..332902292 100644
--- a/Emby.Server.Implementations/Localization/Core/en-GB.json
+++ b/Emby.Server.Implementations/Localization/Core/en-GB.json
@@ -14,7 +14,6 @@
"FailedLoginAttemptWithUserName": "Failed login attempt from {0}",
"Favorites": "Favourites",
"Folders": "Folders",
- "Games": "Games",
"Genres": "Genres",
"HeaderAlbumArtists": "Album Artists",
"HeaderCameraUploads": "Camera Uploads",
@@ -51,8 +50,6 @@
"NotificationOptionAudioPlayback": "Audio playback started",
"NotificationOptionAudioPlaybackStopped": "Audio playback stopped",
"NotificationOptionCameraImageUploaded": "Camera image uploaded",
- "NotificationOptionGamePlayback": "Game playback started",
- "NotificationOptionGamePlaybackStopped": "Game playback stopped",
"NotificationOptionInstallationFailed": "Installation failure",
"NotificationOptionNewLibraryContent": "New content added",
"NotificationOptionPluginError": "Plugin failure",
diff --git a/Emby.Server.Implementations/Localization/Core/en-US.json b/Emby.Server.Implementations/Localization/Core/en-US.json
index 69c8bf03c..f19cd532b 100644
--- a/Emby.Server.Implementations/Localization/Core/en-US.json
+++ b/Emby.Server.Implementations/Localization/Core/en-US.json
@@ -14,7 +14,6 @@
"FailedLoginAttemptWithUserName": "Failed login attempt from {0}",
"Favorites": "Favorites",
"Folders": "Folders",
- "Games": "Games",
"Genres": "Genres",
"HeaderAlbumArtists": "Album Artists",
"HeaderCameraUploads": "Camera Uploads",
@@ -51,8 +50,6 @@
"NotificationOptionAudioPlayback": "Audio playback started",
"NotificationOptionAudioPlaybackStopped": "Audio playback stopped",
"NotificationOptionCameraImageUploaded": "Camera image uploaded",
- "NotificationOptionGamePlayback": "Game playback started",
- "NotificationOptionGamePlaybackStopped": "Game playback stopped",
"NotificationOptionInstallationFailed": "Installation failure",
"NotificationOptionNewLibraryContent": "New content added",
"NotificationOptionPluginError": "Plugin failure",
diff --git a/Emby.Server.Implementations/Localization/Core/es-AR.json b/Emby.Server.Implementations/Localization/Core/es-AR.json
index aaaf09788..c01bb0c50 100644
--- a/Emby.Server.Implementations/Localization/Core/es-AR.json
+++ b/Emby.Server.Implementations/Localization/Core/es-AR.json
@@ -14,7 +14,6 @@
"FailedLoginAttemptWithUserName": "Failed login attempt from {0}",
"Favorites": "Favorites",
"Folders": "Folders",
- "Games": "Games",
"Genres": "Genres",
"HeaderAlbumArtists": "Album Artists",
"HeaderCameraUploads": "Camera Uploads",
@@ -51,8 +50,6 @@
"NotificationOptionAudioPlayback": "Audio playback started",
"NotificationOptionAudioPlaybackStopped": "Audio playback stopped",
"NotificationOptionCameraImageUploaded": "Camera image uploaded",
- "NotificationOptionGamePlayback": "Game playback started",
- "NotificationOptionGamePlaybackStopped": "Game playback stopped",
"NotificationOptionInstallationFailed": "Installation failure",
"NotificationOptionNewLibraryContent": "New content added",
"NotificationOptionPluginError": "Plugin failure",
diff --git a/Emby.Server.Implementations/Localization/Core/es-MX.json b/Emby.Server.Implementations/Localization/Core/es-MX.json
index 2ba9c8c7a..2285f2808 100644
--- a/Emby.Server.Implementations/Localization/Core/es-MX.json
+++ b/Emby.Server.Implementations/Localization/Core/es-MX.json
@@ -14,7 +14,6 @@
"FailedLoginAttemptWithUserName": "Intento fallido de inicio de sesión de {0}",
"Favorites": "Favoritos",
"Folders": "Carpetas",
- "Games": "Juegos",
"Genres": "Géneros",
"HeaderAlbumArtists": "Artistas del Álbum",
"HeaderCameraUploads": "Subidos desde Camara",
@@ -51,8 +50,6 @@
"NotificationOptionAudioPlayback": "Reproducción de audio iniciada",
"NotificationOptionAudioPlaybackStopped": "Reproducción de audio detenida",
"NotificationOptionCameraImageUploaded": "Imagen de la cámara subida",
- "NotificationOptionGamePlayback": "Ejecución de juego iniciada",
- "NotificationOptionGamePlaybackStopped": "Ejecución de juego detenida",
"NotificationOptionInstallationFailed": "Falla de instalación",
"NotificationOptionNewLibraryContent": "Nuevo contenido agregado",
"NotificationOptionPluginError": "Falla de complemento",
diff --git a/Emby.Server.Implementations/Localization/Core/es.json b/Emby.Server.Implementations/Localization/Core/es.json
index 38a282382..5d118d21f 100644
--- a/Emby.Server.Implementations/Localization/Core/es.json
+++ b/Emby.Server.Implementations/Localization/Core/es.json
@@ -14,7 +14,6 @@
"FailedLoginAttemptWithUserName": "Error al intentar iniciar sesión a partir de {0}",
"Favorites": "Favoritos",
"Folders": "Carpetas",
- "Games": "Juegos",
"Genres": "Géneros",
"HeaderAlbumArtists": "Artistas del Álbum",
"HeaderCameraUploads": "Camera Uploads",
@@ -51,8 +50,6 @@
"NotificationOptionAudioPlayback": "Se inició la reproducción de audio",
"NotificationOptionAudioPlaybackStopped": "Se detuvo la reproducción de audio",
"NotificationOptionCameraImageUploaded": "Imagen de la cámara cargada",
- "NotificationOptionGamePlayback": "Se inició la reproducción del juego",
- "NotificationOptionGamePlaybackStopped": "Se detuvo la reproducción del juego",
"NotificationOptionInstallationFailed": "Error de instalación",
"NotificationOptionNewLibraryContent": "Nuevo contenido añadido",
"NotificationOptionPluginError": "Error en plugin",
diff --git a/Emby.Server.Implementations/Localization/Core/fa.json b/Emby.Server.Implementations/Localization/Core/fa.json
index 1d7bc5fe8..0a0c7553b 100644
--- a/Emby.Server.Implementations/Localization/Core/fa.json
+++ b/Emby.Server.Implementations/Localization/Core/fa.json
@@ -14,7 +14,6 @@
"FailedLoginAttemptWithUserName": "تلاش برای ورود از {0} ناموفق بود",
"Favorites": "مورد علاقه ها",
"Folders": "پوشه ها",
- "Games": "بازی ها",
"Genres": "ژانرها",
"HeaderAlbumArtists": "هنرمندان آلبوم",
"HeaderCameraUploads": "آپلودهای دوربین",
@@ -51,8 +50,6 @@
"NotificationOptionAudioPlayback": "پخش صدا آغاز شد",
"NotificationOptionAudioPlaybackStopped": "پخش صدا متوقف شد",
"NotificationOptionCameraImageUploaded": "تصاویر دوربین آپلود شد",
- "NotificationOptionGamePlayback": "پخش بازی آغاز شد",
- "NotificationOptionGamePlaybackStopped": "پخش بازی متوقف شد",
"NotificationOptionInstallationFailed": "شکست نصب",
"NotificationOptionNewLibraryContent": "محتوای جدید افزوده شد",
"NotificationOptionPluginError": "خرابی افزونه",
diff --git a/Emby.Server.Implementations/Localization/Core/fr-CA.json b/Emby.Server.Implementations/Localization/Core/fr-CA.json
index 22cd4cf6d..7202be9f5 100644
--- a/Emby.Server.Implementations/Localization/Core/fr-CA.json
+++ b/Emby.Server.Implementations/Localization/Core/fr-CA.json
@@ -14,7 +14,6 @@
"FailedLoginAttemptWithUserName": "Failed login attempt from {0}",
"Favorites": "Favorites",
"Folders": "Folders",
- "Games": "Games",
"Genres": "Genres",
"HeaderAlbumArtists": "Album Artists",
"HeaderCameraUploads": "Camera Uploads",
@@ -51,8 +50,6 @@
"NotificationOptionAudioPlayback": "Audio playback started",
"NotificationOptionAudioPlaybackStopped": "Audio playback stopped",
"NotificationOptionCameraImageUploaded": "Camera image uploaded",
- "NotificationOptionGamePlayback": "Game playback started",
- "NotificationOptionGamePlaybackStopped": "Game playback stopped",
"NotificationOptionInstallationFailed": "Installation failure",
"NotificationOptionNewLibraryContent": "New content added",
"NotificationOptionPluginError": "Plugin failure",
diff --git a/Emby.Server.Implementations/Localization/Core/fr.json b/Emby.Server.Implementations/Localization/Core/fr.json
index 085e22cf7..aa9a1add3 100644
--- a/Emby.Server.Implementations/Localization/Core/fr.json
+++ b/Emby.Server.Implementations/Localization/Core/fr.json
@@ -14,7 +14,6 @@
"FailedLoginAttemptWithUserName": "Échec d'une tentative de connexion de {0}",
"Favorites": "Favoris",
"Folders": "Dossiers",
- "Games": "Jeux",
"Genres": "Genres",
"HeaderAlbumArtists": "Artistes de l'album",
"HeaderCameraUploads": "Photos transférées",
@@ -51,8 +50,6 @@
"NotificationOptionAudioPlayback": "Lecture audio démarrée",
"NotificationOptionAudioPlaybackStopped": "Lecture audio arrêtée",
"NotificationOptionCameraImageUploaded": "L'image de l'appareil photo a été transférée",
- "NotificationOptionGamePlayback": "Lecture de jeu démarrée",
- "NotificationOptionGamePlaybackStopped": "Lecture de jeu arrêtée",
"NotificationOptionInstallationFailed": "Échec d'installation",
"NotificationOptionNewLibraryContent": "Nouveau contenu ajouté",
"NotificationOptionPluginError": "Erreur d'extension",
diff --git a/Emby.Server.Implementations/Localization/Core/gsw.json b/Emby.Server.Implementations/Localization/Core/gsw.json
index 537fe35d5..728002a56 100644
--- a/Emby.Server.Implementations/Localization/Core/gsw.json
+++ b/Emby.Server.Implementations/Localization/Core/gsw.json
@@ -14,7 +14,6 @@
"FailedLoginAttemptWithUserName": "Failed login attempt from {0}",
"Favorites": "Favorites",
"Folders": "Folders",
- "Games": "Spiel",
"Genres": "Genres",
"HeaderAlbumArtists": "Albuminterprete",
"HeaderCameraUploads": "Camera Uploads",
@@ -51,8 +50,6 @@
"NotificationOptionAudioPlayback": "Audio playback started",
"NotificationOptionAudioPlaybackStopped": "Audio playback stopped",
"NotificationOptionCameraImageUploaded": "Camera image uploaded",
- "NotificationOptionGamePlayback": "Game playback started",
- "NotificationOptionGamePlaybackStopped": "Game playback stopped",
"NotificationOptionInstallationFailed": "Installation failure",
"NotificationOptionNewLibraryContent": "New content added",
"NotificationOptionPluginError": "Plugin failure",
diff --git a/Emby.Server.Implementations/Localization/Core/he.json b/Emby.Server.Implementations/Localization/Core/he.json
index 6fff9d0ab..fff1d1f0e 100644
--- a/Emby.Server.Implementations/Localization/Core/he.json
+++ b/Emby.Server.Implementations/Localization/Core/he.json
@@ -14,7 +14,6 @@
"FailedLoginAttemptWithUserName": "Failed login attempt from {0}",
"Favorites": "Favorites",
"Folders": "Folders",
- "Games": "משחקים",
"Genres": "ז'אנרים",
"HeaderAlbumArtists": "Album Artists",
"HeaderCameraUploads": "Camera Uploads",
@@ -51,8 +50,6 @@
"NotificationOptionAudioPlayback": "Audio playback started",
"NotificationOptionAudioPlaybackStopped": "Audio playback stopped",
"NotificationOptionCameraImageUploaded": "Camera image uploaded",
- "NotificationOptionGamePlayback": "Game playback started",
- "NotificationOptionGamePlaybackStopped": "Game playback stopped",
"NotificationOptionInstallationFailed": "Installation failure",
"NotificationOptionNewLibraryContent": "New content added",
"NotificationOptionPluginError": "Plugin failure",
diff --git a/Emby.Server.Implementations/Localization/Core/hr.json b/Emby.Server.Implementations/Localization/Core/hr.json
index 3232a4ff7..f284b3cd9 100644
--- a/Emby.Server.Implementations/Localization/Core/hr.json
+++ b/Emby.Server.Implementations/Localization/Core/hr.json
@@ -14,7 +14,6 @@
"FailedLoginAttemptWithUserName": "Neuspjeli pokušaj prijave za {0}",
"Favorites": "Omiljeni",
"Folders": "Mape",
- "Games": "Igre",
"Genres": "Žanrovi",
"HeaderAlbumArtists": "Izvođači albuma",
"HeaderCameraUploads": "Camera Uploads",
@@ -51,8 +50,6 @@
"NotificationOptionAudioPlayback": "Reprodukcija glazbe započeta",
"NotificationOptionAudioPlaybackStopped": "Reprodukcija audiozapisa je zaustavljena",
"NotificationOptionCameraImageUploaded": "Slike kamere preuzete",
- "NotificationOptionGamePlayback": "Igrica pokrenuta",
- "NotificationOptionGamePlaybackStopped": "Reprodukcija igre je zaustavljena",
"NotificationOptionInstallationFailed": "Instalacija nije izvršena",
"NotificationOptionNewLibraryContent": "Novi sadržaj je dodan",
"NotificationOptionPluginError": "Dodatak otkazao",
diff --git a/Emby.Server.Implementations/Localization/Core/hu.json b/Emby.Server.Implementations/Localization/Core/hu.json
index 3a0119faf..d2d16b18f 100644
--- a/Emby.Server.Implementations/Localization/Core/hu.json
+++ b/Emby.Server.Implementations/Localization/Core/hu.json
@@ -14,7 +14,6 @@
"FailedLoginAttemptWithUserName": "Failed login attempt from {0}",
"Favorites": "Kedvencek",
"Folders": "Könyvtárak",
- "Games": "Játékok",
"Genres": "Műfajok",
"HeaderAlbumArtists": "Album Előadók",
"HeaderCameraUploads": "Camera Uploads",
@@ -51,8 +50,6 @@
"NotificationOptionAudioPlayback": "Audió lejátszás elkezdve",
"NotificationOptionAudioPlaybackStopped": "Audió lejátszás befejezve",
"NotificationOptionCameraImageUploaded": "Kamera kép feltöltve",
- "NotificationOptionGamePlayback": "Game playback started",
- "NotificationOptionGamePlaybackStopped": "Game playback stopped",
"NotificationOptionInstallationFailed": "Telepítési hiba",
"NotificationOptionNewLibraryContent": "Új tartalom hozzáadva",
"NotificationOptionPluginError": "Bővítmény hiba",
diff --git a/Emby.Server.Implementations/Localization/Core/it.json b/Emby.Server.Implementations/Localization/Core/it.json
index 58b7bb61a..b3d9c16cf 100644
--- a/Emby.Server.Implementations/Localization/Core/it.json
+++ b/Emby.Server.Implementations/Localization/Core/it.json
@@ -14,7 +14,6 @@
"FailedLoginAttemptWithUserName": "Tentativo di accesso fallito da {0}",
"Favorites": "Preferiti",
"Folders": "Cartelle",
- "Games": "Giochi",
"Genres": "Generi",
"HeaderAlbumArtists": "Artisti Album",
"HeaderCameraUploads": "Caricamenti Fotocamera",
@@ -51,8 +50,6 @@
"NotificationOptionAudioPlayback": "La riproduzione audio è iniziata",
"NotificationOptionAudioPlaybackStopped": "La riproduzione audio è stata interrotta",
"NotificationOptionCameraImageUploaded": "Immagine fotocamera caricata",
- "NotificationOptionGamePlayback": "Il gioco è stato avviato",
- "NotificationOptionGamePlaybackStopped": "Il gioco è stato fermato",
"NotificationOptionInstallationFailed": "Installazione fallita",
"NotificationOptionNewLibraryContent": "Nuovo contenuto aggiunto",
"NotificationOptionPluginError": "Errore del Plug-in",
diff --git a/Emby.Server.Implementations/Localization/Core/kk.json b/Emby.Server.Implementations/Localization/Core/kk.json
index 45b8617f1..ae256f79d 100644
--- a/Emby.Server.Implementations/Localization/Core/kk.json
+++ b/Emby.Server.Implementations/Localization/Core/kk.json
@@ -14,7 +14,6 @@
"FailedLoginAttemptWithUserName": "{0} тарапынан кіру әрекеті сәтсіз",
"Favorites": "Таңдаулылар",
"Folders": "Қалталар",
- "Games": "Ойындар",
"Genres": "Жанрлар",
"HeaderAlbumArtists": "Альбом орындаушылары",
"HeaderCameraUploads": "Камерадан жүктелгендер",
@@ -51,8 +50,6 @@
"NotificationOptionAudioPlayback": "Дыбыс ойнатуы басталды",
"NotificationOptionAudioPlaybackStopped": "Дыбыс ойнатуы тоқтатылды",
"NotificationOptionCameraImageUploaded": "Камерадан фотосурет кері қотарылған",
- "NotificationOptionGamePlayback": "Ойын ойнатуы басталды",
- "NotificationOptionGamePlaybackStopped": "Ойын ойнатуы тоқтатылды",
"NotificationOptionInstallationFailed": "Орнату сәтсіздігі",
"NotificationOptionNewLibraryContent": "Жаңа мазмұн үстелген",
"NotificationOptionPluginError": "Плагин сәтсіздігі",
diff --git a/Emby.Server.Implementations/Localization/Core/ko.json b/Emby.Server.Implementations/Localization/Core/ko.json
index 04fc52d6e..21808fd18 100644
--- a/Emby.Server.Implementations/Localization/Core/ko.json
+++ b/Emby.Server.Implementations/Localization/Core/ko.json
@@ -14,7 +14,6 @@
"FailedLoginAttemptWithUserName": "Failed login attempt from {0}",
"Favorites": "Favorites",
"Folders": "Folders",
- "Games": "Games",
"Genres": "Genres",
"HeaderAlbumArtists": "앨범 아티스트",
"HeaderCameraUploads": "Camera Uploads",
@@ -51,8 +50,6 @@
"NotificationOptionAudioPlayback": "Audio playback started",
"NotificationOptionAudioPlaybackStopped": "Audio playback stopped",
"NotificationOptionCameraImageUploaded": "Camera image uploaded",
- "NotificationOptionGamePlayback": "Game playback started",
- "NotificationOptionGamePlaybackStopped": "Game playback stopped",
"NotificationOptionInstallationFailed": "Installation failure",
"NotificationOptionNewLibraryContent": "New content added",
"NotificationOptionPluginError": "Plugin failure",
diff --git a/Emby.Server.Implementations/Localization/Core/lt-LT.json b/Emby.Server.Implementations/Localization/Core/lt-LT.json
index 653565db6..558904f06 100644
--- a/Emby.Server.Implementations/Localization/Core/lt-LT.json
+++ b/Emby.Server.Implementations/Localization/Core/lt-LT.json
@@ -14,7 +14,6 @@
"FailedLoginAttemptWithUserName": "Failed login attempt from {0}",
"Favorites": "Favorites",
"Folders": "Folders",
- "Games": "Games",
"Genres": "Žanrai",
"HeaderAlbumArtists": "Album Artists",
"HeaderCameraUploads": "Camera Uploads",
@@ -51,8 +50,6 @@
"NotificationOptionAudioPlayback": "Audio playback started",
"NotificationOptionAudioPlaybackStopped": "Audio playback stopped",
"NotificationOptionCameraImageUploaded": "Camera image uploaded",
- "NotificationOptionGamePlayback": "Game playback started",
- "NotificationOptionGamePlaybackStopped": "Game playback stopped",
"NotificationOptionInstallationFailed": "Installation failure",
"NotificationOptionNewLibraryContent": "New content added",
"NotificationOptionPluginError": "Plugin failure",
diff --git a/Emby.Server.Implementations/Localization/Core/ms.json b/Emby.Server.Implementations/Localization/Core/ms.json
index aaaf09788..c01bb0c50 100644
--- a/Emby.Server.Implementations/Localization/Core/ms.json
+++ b/Emby.Server.Implementations/Localization/Core/ms.json
@@ -14,7 +14,6 @@
"FailedLoginAttemptWithUserName": "Failed login attempt from {0}",
"Favorites": "Favorites",
"Folders": "Folders",
- "Games": "Games",
"Genres": "Genres",
"HeaderAlbumArtists": "Album Artists",
"HeaderCameraUploads": "Camera Uploads",
@@ -51,8 +50,6 @@
"NotificationOptionAudioPlayback": "Audio playback started",
"NotificationOptionAudioPlaybackStopped": "Audio playback stopped",
"NotificationOptionCameraImageUploaded": "Camera image uploaded",
- "NotificationOptionGamePlayback": "Game playback started",
- "NotificationOptionGamePlaybackStopped": "Game playback stopped",
"NotificationOptionInstallationFailed": "Installation failure",
"NotificationOptionNewLibraryContent": "New content added",
"NotificationOptionPluginError": "Plugin failure",
diff --git a/Emby.Server.Implementations/Localization/Core/nb.json b/Emby.Server.Implementations/Localization/Core/nb.json
index ed63aa29c..dbda794ad 100644
--- a/Emby.Server.Implementations/Localization/Core/nb.json
+++ b/Emby.Server.Implementations/Localization/Core/nb.json
@@ -14,7 +14,6 @@
"FailedLoginAttemptWithUserName": "Mislykket påloggingsforsøk fra {0}",
"Favorites": "Favoritter",
"Folders": "Mapper",
- "Games": "Spill",
"Genres": "Sjanger",
"HeaderAlbumArtists": "Albumartist",
"HeaderCameraUploads": "Camera Uploads",
@@ -51,8 +50,6 @@
"NotificationOptionAudioPlayback": "Lyd tilbakespilling startet",
"NotificationOptionAudioPlaybackStopped": "Lyd avspilling stoppet",
"NotificationOptionCameraImageUploaded": "Kamera bilde lastet opp",
- "NotificationOptionGamePlayback": "Spill avspillingen startet",
- "NotificationOptionGamePlaybackStopped": "Filmer",
"NotificationOptionInstallationFailed": "Installasjon feil",
"NotificationOptionNewLibraryContent": "Ny innhold er lagt til",
"NotificationOptionPluginError": "Plugin feil",
diff --git a/Emby.Server.Implementations/Localization/Core/nl.json b/Emby.Server.Implementations/Localization/Core/nl.json
index 7b8c8765e..589753c44 100644
--- a/Emby.Server.Implementations/Localization/Core/nl.json
+++ b/Emby.Server.Implementations/Localization/Core/nl.json
@@ -14,7 +14,6 @@
"FailedLoginAttemptWithUserName": "Mislukte aanmeld poging van {0}",
"Favorites": "Favorieten",
"Folders": "Mappen",
- "Games": "Spellen",
"Genres": "Genres",
"HeaderAlbumArtists": "Album artiesten",
"HeaderCameraUploads": "Camera uploads",
@@ -51,8 +50,6 @@
"NotificationOptionAudioPlayback": "Geluid gestart",
"NotificationOptionAudioPlaybackStopped": "Geluid gestopt",
"NotificationOptionCameraImageUploaded": "Camera afbeelding geüpload",
- "NotificationOptionGamePlayback": "Spel gestart",
- "NotificationOptionGamePlaybackStopped": "Spel gestopt",
"NotificationOptionInstallationFailed": "Installatie mislukt",
"NotificationOptionNewLibraryContent": "Nieuwe content toegevoegd",
"NotificationOptionPluginError": "Plug-in fout",
diff --git a/Emby.Server.Implementations/Localization/Core/pl.json b/Emby.Server.Implementations/Localization/Core/pl.json
index 5aefa740b..92b12409d 100644
--- a/Emby.Server.Implementations/Localization/Core/pl.json
+++ b/Emby.Server.Implementations/Localization/Core/pl.json
@@ -14,7 +14,6 @@
"FailedLoginAttemptWithUserName": "Próba logowania przez {0} zakończona niepowodzeniem",
"Favorites": "Ulubione",
"Folders": "Foldery",
- "Games": "Gry",
"Genres": "Gatunki",
"HeaderAlbumArtists": "Wykonawcy albumów",
"HeaderCameraUploads": "Przekazane obrazy",
@@ -51,8 +50,6 @@
"NotificationOptionAudioPlayback": "Rozpoczęto odtwarzanie muzyki",
"NotificationOptionAudioPlaybackStopped": "Odtwarzane dźwięku zatrzymane",
"NotificationOptionCameraImageUploaded": "Przekazano obraz z urządzenia mobilnego",
- "NotificationOptionGamePlayback": "Odtwarzanie gry rozpoczęte",
- "NotificationOptionGamePlaybackStopped": "Odtwarzanie gry zatrzymane",
"NotificationOptionInstallationFailed": "Niepowodzenie instalacji",
"NotificationOptionNewLibraryContent": "Dodano nową zawartość",
"NotificationOptionPluginError": "Awaria wtyczki",
diff --git a/Emby.Server.Implementations/Localization/Core/pt-BR.json b/Emby.Server.Implementations/Localization/Core/pt-BR.json
index 9ae25d3ac..aaedf0850 100644
--- a/Emby.Server.Implementations/Localization/Core/pt-BR.json
+++ b/Emby.Server.Implementations/Localization/Core/pt-BR.json
@@ -14,7 +14,6 @@
"FailedLoginAttemptWithUserName": "Falha na tentativa de login de {0}",
"Favorites": "Favoritos",
"Folders": "Pastas",
- "Games": "Jogos",
"Genres": "Gêneros",
"HeaderAlbumArtists": "Artistas do Álbum",
"HeaderCameraUploads": "Uploads da Câmera",
@@ -51,8 +50,6 @@
"NotificationOptionAudioPlayback": "Reprodução de áudio iniciada",
"NotificationOptionAudioPlaybackStopped": "Reprodução de áudio parada",
"NotificationOptionCameraImageUploaded": "Imagem de câmera enviada",
- "NotificationOptionGamePlayback": "Reprodução de jogo iniciada",
- "NotificationOptionGamePlaybackStopped": "Reprodução de jogo parada",
"NotificationOptionInstallationFailed": "Falha na instalação",
"NotificationOptionNewLibraryContent": "Novo conteúdo adicionado",
"NotificationOptionPluginError": "Falha de plugin",
diff --git a/Emby.Server.Implementations/Localization/Core/pt-PT.json b/Emby.Server.Implementations/Localization/Core/pt-PT.json
index 59c25f0e3..dc69d8af2 100644
--- a/Emby.Server.Implementations/Localization/Core/pt-PT.json
+++ b/Emby.Server.Implementations/Localization/Core/pt-PT.json
@@ -14,7 +14,6 @@
"FailedLoginAttemptWithUserName": "Failed login attempt from {0}",
"Favorites": "Favorites",
"Folders": "Folders",
- "Games": "Games",
"Genres": "Genres",
"HeaderAlbumArtists": "Album Artists",
"HeaderCameraUploads": "Camera Uploads",
@@ -51,8 +50,6 @@
"NotificationOptionAudioPlayback": "Audio playback started",
"NotificationOptionAudioPlaybackStopped": "Audio playback stopped",
"NotificationOptionCameraImageUploaded": "Camera image uploaded",
- "NotificationOptionGamePlayback": "Game playback started",
- "NotificationOptionGamePlaybackStopped": "Game playback stopped",
"NotificationOptionInstallationFailed": "Installation failure",
"NotificationOptionNewLibraryContent": "New content added",
"NotificationOptionPluginError": "Plugin failure",
diff --git a/Emby.Server.Implementations/Localization/Core/ru.json b/Emby.Server.Implementations/Localization/Core/ru.json
index 338141294..d799fa50b 100644
--- a/Emby.Server.Implementations/Localization/Core/ru.json
+++ b/Emby.Server.Implementations/Localization/Core/ru.json
@@ -14,7 +14,6 @@
"FailedLoginAttemptWithUserName": "{0} - попытка входа неудачна",
"Favorites": "Избранное",
"Folders": "Папки",
- "Games": "Игры",
"Genres": "Жанры",
"HeaderAlbumArtists": "Исп-ли альбома",
"HeaderCameraUploads": "Камеры",
@@ -51,8 +50,6 @@
"NotificationOptionAudioPlayback": "Воспр-ие аудио зап-но",
"NotificationOptionAudioPlaybackStopped": "Восп-ие аудио ост-но",
"NotificationOptionCameraImageUploaded": "Произведена выкладка отснятого с камеры",
- "NotificationOptionGamePlayback": "Воспр-ие игры зап-но",
- "NotificationOptionGamePlaybackStopped": "Восп-ие игры ост-но",
"NotificationOptionInstallationFailed": "Сбой установки",
"NotificationOptionNewLibraryContent": "Новое содержание добавлено",
"NotificationOptionPluginError": "Сбой плагина",
diff --git a/Emby.Server.Implementations/Localization/Core/sk.json b/Emby.Server.Implementations/Localization/Core/sk.json
index ed0c68952..bc7e7184e 100644
--- a/Emby.Server.Implementations/Localization/Core/sk.json
+++ b/Emby.Server.Implementations/Localization/Core/sk.json
@@ -14,7 +14,6 @@
"FailedLoginAttemptWithUserName": "Neúspešný pokus o prihlásenie z {0}",
"Favorites": "Obľúbené",
"Folders": "Priečinky",
- "Games": "Hry",
"Genres": "Žánre",
"HeaderAlbumArtists": "Album Artists",
"HeaderCameraUploads": "Camera Uploads",
@@ -51,8 +50,6 @@
"NotificationOptionAudioPlayback": "Spustené prehrávanie audia",
"NotificationOptionAudioPlaybackStopped": "Zastavené prehrávanie audia",
"NotificationOptionCameraImageUploaded": "Nahraný obrázok z fotoaparátu",
- "NotificationOptionGamePlayback": "Game playback started",
- "NotificationOptionGamePlaybackStopped": "Hra ukončená",
"NotificationOptionInstallationFailed": "Chyba inštalácie",
"NotificationOptionNewLibraryContent": "Pridaný nový obsah",
"NotificationOptionPluginError": "Chyba rozšírenia",
diff --git a/Emby.Server.Implementations/Localization/Core/sl-SI.json b/Emby.Server.Implementations/Localization/Core/sl-SI.json
index 8fe279836..e850257d4 100644
--- a/Emby.Server.Implementations/Localization/Core/sl-SI.json
+++ b/Emby.Server.Implementations/Localization/Core/sl-SI.json
@@ -14,7 +14,6 @@
"FailedLoginAttemptWithUserName": "Failed login attempt from {0}",
"Favorites": "Favorites",
"Folders": "Folders",
- "Games": "Games",
"Genres": "Genres",
"HeaderAlbumArtists": "Album Artists",
"HeaderCameraUploads": "Camera Uploads",
@@ -51,8 +50,6 @@
"NotificationOptionAudioPlayback": "Audio playback started",
"NotificationOptionAudioPlaybackStopped": "Audio playback stopped",
"NotificationOptionCameraImageUploaded": "Camera image uploaded",
- "NotificationOptionGamePlayback": "Game playback started",
- "NotificationOptionGamePlaybackStopped": "Game playback stopped",
"NotificationOptionInstallationFailed": "Installation failure",
"NotificationOptionNewLibraryContent": "New content added",
"NotificationOptionPluginError": "Plugin failure",
diff --git a/Emby.Server.Implementations/Localization/Core/sv.json b/Emby.Server.Implementations/Localization/Core/sv.json
index 517d648bb..fb2761a7d 100644
--- a/Emby.Server.Implementations/Localization/Core/sv.json
+++ b/Emby.Server.Implementations/Localization/Core/sv.json
@@ -14,7 +14,6 @@
"FailedLoginAttemptWithUserName": "Misslyckat inloggningsförsök från {0}",
"Favorites": "Favoriter",
"Folders": "Mappar",
- "Games": "Spel",
"Genres": "Genrer",
"HeaderAlbumArtists": "Albumartister",
"HeaderCameraUploads": "Camera Uploads",
@@ -51,8 +50,6 @@
"NotificationOptionAudioPlayback": "Ljuduppspelning har påbörjats",
"NotificationOptionAudioPlaybackStopped": "Ljuduppspelning stoppad",
"NotificationOptionCameraImageUploaded": "Kamerabild har laddats upp",
- "NotificationOptionGamePlayback": "Spel har startats",
- "NotificationOptionGamePlaybackStopped": "Spel stoppat",
"NotificationOptionInstallationFailed": "Fel vid installation",
"NotificationOptionNewLibraryContent": "Nytt innehåll har lagts till",
"NotificationOptionPluginError": "Fel uppstod med tillägget",
diff --git a/Emby.Server.Implementations/Localization/Core/tr.json b/Emby.Server.Implementations/Localization/Core/tr.json
index 9e86e2125..495f82db6 100644
--- a/Emby.Server.Implementations/Localization/Core/tr.json
+++ b/Emby.Server.Implementations/Localization/Core/tr.json
@@ -14,7 +14,6 @@
"FailedLoginAttemptWithUserName": "Failed login attempt from {0}",
"Favorites": "Favorites",
"Folders": "Folders",
- "Games": "Games",
"Genres": "Genres",
"HeaderAlbumArtists": "Album Artists",
"HeaderCameraUploads": "Camera Uploads",
@@ -51,8 +50,6 @@
"NotificationOptionAudioPlayback": "Audio playback started",
"NotificationOptionAudioPlaybackStopped": "Audio playback stopped",
"NotificationOptionCameraImageUploaded": "Camera image uploaded",
- "NotificationOptionGamePlayback": "Game playback started",
- "NotificationOptionGamePlaybackStopped": "Game playback stopped",
"NotificationOptionInstallationFailed": "Installation failure",
"NotificationOptionNewLibraryContent": "New content added",
"NotificationOptionPluginError": "Plugin failure",
diff --git a/Emby.Server.Implementations/Localization/Core/zh-CN.json b/Emby.Server.Implementations/Localization/Core/zh-CN.json
index 6d877ec17..8910a6bce 100644
--- a/Emby.Server.Implementations/Localization/Core/zh-CN.json
+++ b/Emby.Server.Implementations/Localization/Core/zh-CN.json
@@ -14,7 +14,6 @@
"FailedLoginAttemptWithUserName": "来自 {0} 的失败登入",
"Favorites": "最爱",
"Folders": "文件夹",
- "Games": "游戏",
"Genres": "风格",
"HeaderAlbumArtists": "专辑作家",
"HeaderCameraUploads": "相机上传",
@@ -51,8 +50,6 @@
"NotificationOptionAudioPlayback": "音频开始播放",
"NotificationOptionAudioPlaybackStopped": "音频播放已停止",
"NotificationOptionCameraImageUploaded": "相机图片已上传",
- "NotificationOptionGamePlayback": "游戏开始",
- "NotificationOptionGamePlaybackStopped": "游戏停止",
"NotificationOptionInstallationFailed": "安装失败",
"NotificationOptionNewLibraryContent": "已添加新内容",
"NotificationOptionPluginError": "插件失败",
diff --git a/Emby.Server.Implementations/Localization/Core/zh-HK.json b/Emby.Server.Implementations/Localization/Core/zh-HK.json
index cad5700fd..387fc2b92 100644
--- a/Emby.Server.Implementations/Localization/Core/zh-HK.json
+++ b/Emby.Server.Implementations/Localization/Core/zh-HK.json
@@ -14,7 +14,6 @@
"FailedLoginAttemptWithUserName": "Failed login attempt from {0}",
"Favorites": "Favorites",
"Folders": "Folders",
- "Games": "Games",
"Genres": "Genres",
"HeaderAlbumArtists": "Album Artists",
"HeaderCameraUploads": "Camera Uploads",
@@ -51,8 +50,6 @@
"NotificationOptionAudioPlayback": "Audio playback started",
"NotificationOptionAudioPlaybackStopped": "Audio playback stopped",
"NotificationOptionCameraImageUploaded": "Camera image uploaded",
- "NotificationOptionGamePlayback": "Game playback started",
- "NotificationOptionGamePlaybackStopped": "Game playback stopped",
"NotificationOptionInstallationFailed": "Installation failure",
"NotificationOptionNewLibraryContent": "New content added",
"NotificationOptionPluginError": "Plugin failure",
diff --git a/Emby.Server.Implementations/Localization/LocalizationManager.cs b/Emby.Server.Implementations/Localization/LocalizationManager.cs
index 7af8cf18c..31217730b 100644
--- a/Emby.Server.Implementations/Localization/LocalizationManager.cs
+++ b/Emby.Server.Implementations/Localization/LocalizationManager.cs
@@ -4,12 +4,14 @@ using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
+using System.Reflection;
+using System.Text;
+using System.Threading.Tasks;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Extensions;
using MediaBrowser.Model.Globalization;
using MediaBrowser.Model.IO;
-using MediaBrowser.Model.Reflection;
using MediaBrowser.Model.Serialization;
using Microsoft.Extensions.Logging;
@@ -36,8 +38,7 @@ namespace Emby.Server.Implementations.Localization
private readonly IFileSystem _fileSystem;
private readonly IJsonSerializer _jsonSerializer;
private readonly ILogger _logger;
- private readonly IAssemblyInfo _assemblyInfo;
- private readonly ITextLocalizer _textLocalizer;
+ private static readonly Assembly _assembly = typeof(LocalizationManager).Assembly;
/// <summary>
/// Initializes a new instance of the <see cref="LocalizationManager" /> class.
@@ -49,67 +50,63 @@ namespace Emby.Server.Implementations.Localization
IServerConfigurationManager configurationManager,
IFileSystem fileSystem,
IJsonSerializer jsonSerializer,
- ILoggerFactory loggerFactory,
- IAssemblyInfo assemblyInfo,
- ITextLocalizer textLocalizer)
+ ILoggerFactory loggerFactory)
{
_configurationManager = configurationManager;
_fileSystem = fileSystem;
_jsonSerializer = jsonSerializer;
_logger = loggerFactory.CreateLogger(nameof(LocalizationManager));
- _assemblyInfo = assemblyInfo;
- _textLocalizer = textLocalizer;
-
- ExtractAll();
}
- private void ExtractAll()
+ public async Task LoadAll()
{
- var type = GetType();
- var resourcePath = type.Namespace + ".Ratings.";
-
- var localizationPath = LocalizationPath;
+ const string ratingsResource = "Emby.Server.Implementations.Localization.Ratings.";
- Directory.CreateDirectory(localizationPath);
+ Directory.CreateDirectory(LocalizationPath);
- var existingFiles = GetRatingsFiles(localizationPath)
- .Select(Path.GetFileName)
- .ToList();
+ var existingFiles = GetRatingsFiles(LocalizationPath).Select(Path.GetFileName);
// Extract from the assembly
- foreach (var resource in _assemblyInfo
- .GetManifestResourceNames(type)
- .Where(i => i.StartsWith(resourcePath)))
+ foreach (var resource in _assembly.GetManifestResourceNames())
{
- var filename = "ratings-" + resource.Substring(resourcePath.Length);
+ if (!resource.StartsWith(ratingsResource))
+ {
+ continue;
+ }
+
+ string filename = "ratings-" + resource.Substring(ratingsResource.Length);
- if (!existingFiles.Contains(filename))
+ if (existingFiles.Contains(filename))
{
- using (var stream = _assemblyInfo.GetManifestResourceStream(type, resource))
- {
- var target = Path.Combine(localizationPath, filename);
- _logger.LogInformation("Extracting ratings to {0}", target);
+ continue;
+ }
- using (var fs = _fileSystem.GetFileStream(target, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read))
- {
- stream.CopyTo(fs);
- }
+ using (var stream = _assembly.GetManifestResourceStream(resource))
+ {
+ string target = Path.Combine(LocalizationPath, filename);
+ _logger.LogInformation("Extracting ratings to {0}", target);
+
+ using (var fs = _fileSystem.GetFileStream(target, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read))
+ {
+ await stream.CopyToAsync(fs);
}
}
}
- foreach (var file in GetRatingsFiles(localizationPath))
+ foreach (var file in GetRatingsFiles(LocalizationPath))
{
- LoadRatings(file);
+ await LoadRatings(file);
}
LoadAdditionalRatings();
+
+ await LoadCultures();
}
private void LoadAdditionalRatings()
{
- LoadRatings("au", new[] {
-
+ LoadRatings("au", new[]
+ {
new ParentalRating("AU-G", 1),
new ParentalRating("AU-PG", 5),
new ParentalRating("AU-M", 6),
@@ -120,8 +117,8 @@ namespace Emby.Server.Implementations.Localization
new ParentalRating("AU-RC", 11)
});
- LoadRatings("be", new[] {
-
+ LoadRatings("be", new[]
+ {
new ParentalRating("BE-AL", 1),
new ParentalRating("BE-MG6", 2),
new ParentalRating("BE-6", 3),
@@ -130,8 +127,8 @@ namespace Emby.Server.Implementations.Localization
new ParentalRating("BE-16", 8)
});
- LoadRatings("de", new[] {
-
+ LoadRatings("de", new[]
+ {
new ParentalRating("DE-0", 1),
new ParentalRating("FSK-0", 1),
new ParentalRating("DE-6", 5),
@@ -144,8 +141,8 @@ namespace Emby.Server.Implementations.Localization
new ParentalRating("FSK-18", 9)
});
- LoadRatings("ru", new[] {
-
+ LoadRatings("ru", new[]
+ {
new ParentalRating("RU-0+", 1),
new ParentalRating("RU-6+", 3),
new ParentalRating("RU-12+", 7),
@@ -159,29 +156,20 @@ namespace Emby.Server.Implementations.Localization
_allParentalRatings[country] = ratings.ToDictionary(i => i.Name);
}
- private List<string> GetRatingsFiles(string directory)
- {
- return _fileSystem.GetFilePaths(directory, false)
- .Where(i => string.Equals(Path.GetExtension(i), ".txt", StringComparison.OrdinalIgnoreCase))
- .Where(i => Path.GetFileName(i).StartsWith("ratings-", StringComparison.OrdinalIgnoreCase))
- .ToList();
- }
+ private IEnumerable<string> GetRatingsFiles(string directory)
+ => _fileSystem.GetFilePaths(directory, false)
+ .Where(i => string.Equals(Path.GetExtension(i), ".csv", StringComparison.OrdinalIgnoreCase))
+ .Where(i => Path.GetFileName(i).StartsWith("ratings-", StringComparison.OrdinalIgnoreCase));
/// <summary>
/// Gets the localization path.
/// </summary>
/// <value>The localization path.</value>
- public string LocalizationPath => Path.Combine(_configurationManager.ApplicationPaths.ProgramDataPath, "localization");
-
- public string RemoveDiacritics(string text)
- {
- return _textLocalizer.RemoveDiacritics(text);
- }
+ public string LocalizationPath
+ => Path.Combine(_configurationManager.ApplicationPaths.ProgramDataPath, "localization");
public string NormalizeFormKD(string text)
- {
- return _textLocalizer.NormalizeFormKD(text);
- }
+ => text.Normalize(NormalizationForm.FormKD);
private CultureDto[] _cultures;
@@ -190,90 +178,88 @@ namespace Emby.Server.Implementations.Localization
/// </summary>
/// <returns>IEnumerable{CultureDto}.</returns>
public CultureDto[] GetCultures()
- {
- var result = _cultures;
- if (result != null)
- {
- return result;
- }
+ => _cultures;
- var type = GetType();
- var path = type.Namespace + ".iso6392.txt";
+ private async Task LoadCultures()
+ {
+ List<CultureDto> list = new List<CultureDto>();
- var list = new List<CultureDto>();
+ const string path = "Emby.Server.Implementations.Localization.iso6392.txt";
- using (var stream = _assemblyInfo.GetManifestResourceStream(type, path))
+ using (var stream = _assembly.GetManifestResourceStream(path))
+ using (var reader = new StreamReader(stream))
{
- using (var reader = new StreamReader(stream))
+ while (!reader.EndOfStream)
{
- while (!reader.EndOfStream)
+ var line = await reader.ReadLineAsync();
+
+ if (string.IsNullOrWhiteSpace(line))
{
- var line = reader.ReadLine();
+ continue;
+ }
+
+ var parts = line.Split('|');
+
+ if (parts.Length == 5)
+ {
+ string name = parts[3];
+ if (string.IsNullOrWhiteSpace(name))
+ {
+ continue;
+ }
- if (!string.IsNullOrWhiteSpace(line))
+ string twoCharName = parts[2];
+ if (string.IsNullOrWhiteSpace(twoCharName))
+ {
+ continue;
+ }
+
+ string[] threeletterNames;
+ if (string.IsNullOrWhiteSpace(parts[1]))
+ {
+ threeletterNames = new [] { parts[0] };
+ }
+ else
{
- var parts = line.Split('|');
-
- if (parts.Length == 5)
- {
- var threeletterNames = new List<string> { parts[0] };
- if (!string.IsNullOrWhiteSpace(parts[1]))
- {
- threeletterNames.Add(parts[1]);
- }
-
- list.Add(new CultureDto
- {
- DisplayName = parts[3],
- Name = parts[3],
- ThreeLetterISOLanguageNames = threeletterNames.ToArray(),
- TwoLetterISOLanguageName = parts[2]
- });
- }
+ threeletterNames = new [] { parts[0], parts[1] };
}
+
+ list.Add(new CultureDto
+ {
+ DisplayName = name,
+ Name = name,
+ ThreeLetterISOLanguageNames = threeletterNames,
+ TwoLetterISOLanguageName = twoCharName
+ });
}
}
}
- result = list.Where(i => !string.IsNullOrWhiteSpace(i.Name) &&
- !string.IsNullOrWhiteSpace(i.DisplayName) &&
- i.ThreeLetterISOLanguageNames.Length > 0 &&
- !string.IsNullOrWhiteSpace(i.TwoLetterISOLanguageName)).ToArray();
-
- _cultures = result;
-
- return result;
+ _cultures = list.ToArray();
}
public CultureDto FindLanguageInfo(string language)
- {
- return GetCultures()
- .FirstOrDefault(i => string.Equals(i.DisplayName, language, StringComparison.OrdinalIgnoreCase) ||
- string.Equals(i.Name, language, StringComparison.OrdinalIgnoreCase) ||
- i.ThreeLetterISOLanguageNames.Contains(language, StringComparer.OrdinalIgnoreCase) ||
- string.Equals(i.TwoLetterISOLanguageName, language, StringComparison.OrdinalIgnoreCase));
- }
+ => GetCultures()
+ .FirstOrDefault(i =>
+ string.Equals(i.DisplayName, language, StringComparison.OrdinalIgnoreCase)
+ || string.Equals(i.Name, language, StringComparison.OrdinalIgnoreCase)
+ || i.ThreeLetterISOLanguageNames.Contains(language, StringComparer.OrdinalIgnoreCase)
+ || string.Equals(i.TwoLetterISOLanguageName, language, StringComparison.OrdinalIgnoreCase));
/// <summary>
/// Gets the countries.
/// </summary>
/// <returns>IEnumerable{CountryInfo}.</returns>
- public CountryInfo[] GetCountries()
- {
- // ToDo: DeserializeFromStream seems broken in this case
- string jsonCountries = "[{\"Name\":\"AF\",\"DisplayName\":\"Afghanistan\",\"TwoLetterISORegionName\":\"AF\",\"ThreeLetterISORegionName\":\"AFG\"},{\"Name\":\"AL\",\"DisplayName\":\"Albania\",\"TwoLetterISORegionName\":\"AL\",\"ThreeLetterISORegionName\":\"ALB\"},{\"Name\":\"DZ\",\"DisplayName\":\"Algeria\",\"TwoLetterISORegionName\":\"DZ\",\"ThreeLetterISORegionName\":\"DZA\"},{\"Name\":\"AR\",\"DisplayName\":\"Argentina\",\"TwoLetterISORegionName\":\"AR\",\"ThreeLetterISORegionName\":\"ARG\"},{\"Name\":\"AM\",\"DisplayName\":\"Armenia\",\"TwoLetterISORegionName\":\"AM\",\"ThreeLetterISORegionName\":\"ARM\"},{\"Name\":\"AU\",\"DisplayName\":\"Australia\",\"TwoLetterISORegionName\":\"AU\",\"ThreeLetterISORegionName\":\"AUS\"},{\"Name\":\"AT\",\"DisplayName\":\"Austria\",\"TwoLetterISORegionName\":\"AT\",\"ThreeLetterISORegionName\":\"AUT\"},{\"Name\":\"AZ\",\"DisplayName\":\"Azerbaijan\",\"TwoLetterISORegionName\":\"AZ\",\"ThreeLetterISORegionName\":\"AZE\"},{\"Name\":\"BH\",\"DisplayName\":\"Bahrain\",\"TwoLetterISORegionName\":\"BH\",\"ThreeLetterISORegionName\":\"BHR\"},{\"Name\":\"BD\",\"DisplayName\":\"Bangladesh\",\"TwoLetterISORegionName\":\"BD\",\"ThreeLetterISORegionName\":\"BGD\"},{\"Name\":\"BY\",\"DisplayName\":\"Belarus\",\"TwoLetterISORegionName\":\"BY\",\"ThreeLetterISORegionName\":\"BLR\"},{\"Name\":\"BE\",\"DisplayName\":\"Belgium\",\"TwoLetterISORegionName\":\"BE\",\"ThreeLetterISORegionName\":\"BEL\"},{\"Name\":\"BZ\",\"DisplayName\":\"Belize\",\"TwoLetterISORegionName\":\"BZ\",\"ThreeLetterISORegionName\":\"BLZ\"},{\"Name\":\"VE\",\"DisplayName\":\"Bolivarian Republic of Venezuela\",\"TwoLetterISORegionName\":\"VE\",\"ThreeLetterISORegionName\":\"VEN\"},{\"Name\":\"BO\",\"DisplayName\":\"Bolivia\",\"TwoLetterISORegionName\":\"BO\",\"ThreeLetterISORegionName\":\"BOL\"},{\"Name\":\"BA\",\"DisplayName\":\"Bosnia and Herzegovina\",\"TwoLetterISORegionName\":\"BA\",\"ThreeLetterISORegionName\":\"BIH\"},{\"Name\":\"BW\",\"DisplayName\":\"Botswana\",\"TwoLetterISORegionName\":\"BW\",\"ThreeLetterISORegionName\":\"BWA\"},{\"Name\":\"BR\",\"DisplayName\":\"Brazil\",\"TwoLetterISORegionName\":\"BR\",\"ThreeLetterISORegionName\":\"BRA\"},{\"Name\":\"BN\",\"DisplayName\":\"Brunei Darussalam\",\"TwoLetterISORegionName\":\"BN\",\"ThreeLetterISORegionName\":\"BRN\"},{\"Name\":\"BG\",\"DisplayName\":\"Bulgaria\",\"TwoLetterISORegionName\":\"BG\",\"ThreeLetterISORegionName\":\"BGR\"},{\"Name\":\"KH\",\"DisplayName\":\"Cambodia\",\"TwoLetterISORegionName\":\"KH\",\"ThreeLetterISORegionName\":\"KHM\"},{\"Name\":\"CM\",\"DisplayName\":\"Cameroon\",\"TwoLetterISORegionName\":\"CM\",\"ThreeLetterISORegionName\":\"CMR\"},{\"Name\":\"CA\",\"DisplayName\":\"Canada\",\"TwoLetterISORegionName\":\"CA\",\"ThreeLetterISORegionName\":\"CAN\"},{\"Name\":\"029\",\"DisplayName\":\"Caribbean\",\"TwoLetterISORegionName\":\"029\",\"ThreeLetterISORegionName\":\"029\"},{\"Name\":\"CL\",\"DisplayName\":\"Chile\",\"TwoLetterISORegionName\":\"CL\",\"ThreeLetterISORegionName\":\"CHL\"},{\"Name\":\"CO\",\"DisplayName\":\"Colombia\",\"TwoLetterISORegionName\":\"CO\",\"ThreeLetterISORegionName\":\"COL\"},{\"Name\":\"CD\",\"DisplayName\":\"Congo [DRC]\",\"TwoLetterISORegionName\":\"CD\",\"ThreeLetterISORegionName\":\"COD\"},{\"Name\":\"CR\",\"DisplayName\":\"Costa Rica\",\"TwoLetterISORegionName\":\"CR\",\"ThreeLetterISORegionName\":\"CRI\"},{\"Name\":\"HR\",\"DisplayName\":\"Croatia\",\"TwoLetterISORegionName\":\"HR\",\"ThreeLetterISORegionName\":\"HRV\"},{\"Name\":\"CZ\",\"DisplayName\":\"Czech Republic\",\"TwoLetterISORegionName\":\"CZ\",\"ThreeLetterISORegionName\":\"CZE\"},{\"Name\":\"DK\",\"DisplayName\":\"Denmark\",\"TwoLetterISORegionName\":\"DK\",\"ThreeLetterISORegionName\":\"DNK\"},{\"Name\":\"DO\",\"DisplayName\":\"Dominican Republic\",\"TwoLetterISORegionName\":\"DO\",\"ThreeLetterISORegionName\":\"DOM\"},{\"Name\":\"EC\",\"DisplayName\":\"Ecuador\",\"TwoLetterISORegionName\":\"EC\",\"ThreeLetterISORegionName\":\"ECU\"},{\"Name\":\"EG\",\"DisplayName\":\"Egypt\",\"TwoLetterISORegionName\":\"EG\",\"ThreeLetterISORegionName\":\"EGY\"},{\"Name\":\"SV\",\"DisplayName\":\"El Salvador\",\"TwoLetterISORegionName\":\"SV\",\"ThreeLetterISORegionName\":\"SLV\"},{\"Name\":\"ER\",\"DisplayName\":\"Eritrea\",\"TwoLetterISORegionName\":\"ER\",\"ThreeLetterISORegionName\":\"ERI\"},{\"Name\":\"EE\",\"DisplayName\":\"Estonia\",\"TwoLetterISORegionName\":\"EE\",\"ThreeLetterISORegionName\":\"EST\"},{\"Name\":\"ET\",\"DisplayName\":\"Ethiopia\",\"TwoLetterISORegionName\":\"ET\",\"ThreeLetterISORegionName\":\"ETH\"},{\"Name\":\"FO\",\"DisplayName\":\"Faroe Islands\",\"TwoLetterISORegionName\":\"FO\",\"ThreeLetterISORegionName\":\"FRO\"},{\"Name\":\"FI\",\"DisplayName\":\"Finland\",\"TwoLetterISORegionName\":\"FI\",\"ThreeLetterISORegionName\":\"FIN\"},{\"Name\":\"FR\",\"DisplayName\":\"France\",\"TwoLetterISORegionName\":\"FR\",\"ThreeLetterISORegionName\":\"FRA\"},{\"Name\":\"GE\",\"DisplayName\":\"Georgia\",\"TwoLetterISORegionName\":\"GE\",\"ThreeLetterISORegionName\":\"GEO\"},{\"Name\":\"DE\",\"DisplayName\":\"Germany\",\"TwoLetterISORegionName\":\"DE\",\"ThreeLetterISORegionName\":\"DEU\"},{\"Name\":\"GR\",\"DisplayName\":\"Greece\",\"TwoLetterISORegionName\":\"GR\",\"ThreeLetterISORegionName\":\"GRC\"},{\"Name\":\"GL\",\"DisplayName\":\"Greenland\",\"TwoLetterISORegionName\":\"GL\",\"ThreeLetterISORegionName\":\"GRL\"},{\"Name\":\"GT\",\"DisplayName\":\"Guatemala\",\"TwoLetterISORegionName\":\"GT\",\"ThreeLetterISORegionName\":\"GTM\"},{\"Name\":\"HT\",\"DisplayName\":\"Haiti\",\"TwoLetterISORegionName\":\"HT\",\"ThreeLetterISORegionName\":\"HTI\"},{\"Name\":\"HN\",\"DisplayName\":\"Honduras\",\"TwoLetterISORegionName\":\"HN\",\"ThreeLetterISORegionName\":\"HND\"},{\"Name\":\"HK\",\"DisplayName\":\"Hong Kong S.A.R.\",\"TwoLetterISORegionName\":\"HK\",\"ThreeLetterISORegionName\":\"HKG\"},{\"Name\":\"HU\",\"DisplayName\":\"Hungary\",\"TwoLetterISORegionName\":\"HU\",\"ThreeLetterISORegionName\":\"HUN\"},{\"Name\":\"IS\",\"DisplayName\":\"Iceland\",\"TwoLetterISORegionName\":\"IS\",\"ThreeLetterISORegionName\":\"ISL\"},{\"Name\":\"IN\",\"DisplayName\":\"India\",\"TwoLetterISORegionName\":\"IN\",\"ThreeLetterISORegionName\":\"IND\"},{\"Name\":\"ID\",\"DisplayName\":\"Indonesia\",\"TwoLetterISORegionName\":\"ID\",\"ThreeLetterISORegionName\":\"IDN\"},{\"Name\":\"IR\",\"DisplayName\":\"Iran\",\"TwoLetterISORegionName\":\"IR\",\"ThreeLetterISORegionName\":\"IRN\"},{\"Name\":\"IQ\",\"DisplayName\":\"Iraq\",\"TwoLetterISORegionName\":\"IQ\",\"ThreeLetterISORegionName\":\"IRQ\"},{\"Name\":\"IE\",\"DisplayName\":\"Ireland\",\"TwoLetterISORegionName\":\"IE\",\"ThreeLetterISORegionName\":\"IRL\"},{\"Name\":\"PK\",\"DisplayName\":\"Islamic Republic of Pakistan\",\"TwoLetterISORegionName\":\"PK\",\"ThreeLetterISORegionName\":\"PAK\"},{\"Name\":\"IL\",\"DisplayName\":\"Israel\",\"TwoLetterISORegionName\":\"IL\",\"ThreeLetterISORegionName\":\"ISR\"},{\"Name\":\"IT\",\"DisplayName\":\"Italy\",\"TwoLetterISORegionName\":\"IT\",\"ThreeLetterISORegionName\":\"ITA\"},{\"Name\":\"CI\",\"DisplayName\":\"Ivory Coast\",\"TwoLetterISORegionName\":\"CI\",\"ThreeLetterISORegionName\":\"CIV\"},{\"Name\":\"JM\",\"DisplayName\":\"Jamaica\",\"TwoLetterISORegionName\":\"JM\",\"ThreeLetterISORegionName\":\"JAM\"},{\"Name\":\"JP\",\"DisplayName\":\"Japan\",\"TwoLetterISORegionName\":\"JP\",\"ThreeLetterISORegionName\":\"JPN\"},{\"Name\":\"JO\",\"DisplayName\":\"Jordan\",\"TwoLetterISORegionName\":\"JO\",\"ThreeLetterISORegionName\":\"JOR\"},{\"Name\":\"KZ\",\"DisplayName\":\"Kazakhstan\",\"TwoLetterISORegionName\":\"KZ\",\"ThreeLetterISORegionName\":\"KAZ\"},{\"Name\":\"KE\",\"DisplayName\":\"Kenya\",\"TwoLetterISORegionName\":\"KE\",\"ThreeLetterISORegionName\":\"KEN\"},{\"Name\":\"KR\",\"DisplayName\":\"Korea\",\"TwoLetterISORegionName\":\"KR\",\"ThreeLetterISORegionName\":\"KOR\"},{\"Name\":\"KW\",\"DisplayName\":\"Kuwait\",\"TwoLetterISORegionName\":\"KW\",\"ThreeLetterISORegionName\":\"KWT\"},{\"Name\":\"KG\",\"DisplayName\":\"Kyrgyzstan\",\"TwoLetterISORegionName\":\"KG\",\"ThreeLetterISORegionName\":\"KGZ\"},{\"Name\":\"LA\",\"DisplayName\":\"Lao P.D.R.\",\"TwoLetterISORegionName\":\"LA\",\"ThreeLetterISORegionName\":\"LAO\"},{\"Name\":\"419\",\"DisplayName\":\"Latin America\",\"TwoLetterISORegionName\":\"419\",\"ThreeLetterISORegionName\":\"419\"},{\"Name\":\"LV\",\"DisplayName\":\"Latvia\",\"TwoLetterISORegionName\":\"LV\",\"ThreeLetterISORegionName\":\"LVA\"},{\"Name\":\"LB\",\"DisplayName\":\"Lebanon\",\"TwoLetterISORegionName\":\"LB\",\"ThreeLetterISORegionName\":\"LBN\"},{\"Name\":\"LY\",\"DisplayName\":\"Libya\",\"TwoLetterISORegionName\":\"LY\",\"ThreeLetterISORegionName\":\"LBY\"},{\"Name\":\"LI\",\"DisplayName\":\"Liechtenstein\",\"TwoLetterISORegionName\":\"LI\",\"ThreeLetterISORegionName\":\"LIE\"},{\"Name\":\"LT\",\"DisplayName\":\"Lithuania\",\"TwoLetterISORegionName\":\"LT\",\"ThreeLetterISORegionName\":\"LTU\"},{\"Name\":\"LU\",\"DisplayName\":\"Luxembourg\",\"TwoLetterISORegionName\":\"LU\",\"ThreeLetterISORegionName\":\"LUX\"},{\"Name\":\"MO\",\"DisplayName\":\"Macao S.A.R.\",\"TwoLetterISORegionName\":\"MO\",\"ThreeLetterISORegionName\":\"MAC\"},{\"Name\":\"MK\",\"DisplayName\":\"Macedonia (FYROM)\",\"TwoLetterISORegionName\":\"MK\",\"ThreeLetterISORegionName\":\"MKD\"},{\"Name\":\"MY\",\"DisplayName\":\"Malaysia\",\"TwoLetterISORegionName\":\"MY\",\"ThreeLetterISORegionName\":\"MYS\"},{\"Name\":\"MV\",\"DisplayName\":\"Maldives\",\"TwoLetterISORegionName\":\"MV\",\"ThreeLetterISORegionName\":\"MDV\"},{\"Name\":\"ML\",\"DisplayName\":\"Mali\",\"TwoLetterISORegionName\":\"ML\",\"ThreeLetterISORegionName\":\"MLI\"},{\"Name\":\"MT\",\"DisplayName\":\"Malta\",\"TwoLetterISORegionName\":\"MT\",\"ThreeLetterISORegionName\":\"MLT\"},{\"Name\":\"MX\",\"DisplayName\":\"Mexico\",\"TwoLetterISORegionName\":\"MX\",\"ThreeLetterISORegionName\":\"MEX\"},{\"Name\":\"MN\",\"DisplayName\":\"Mongolia\",\"TwoLetterISORegionName\":\"MN\",\"ThreeLetterISORegionName\":\"MNG\"},{\"Name\":\"ME\",\"DisplayName\":\"Montenegro\",\"TwoLetterISORegionName\":\"ME\",\"ThreeLetterISORegionName\":\"MNE\"},{\"Name\":\"MA\",\"DisplayName\":\"Morocco\",\"TwoLetterISORegionName\":\"MA\",\"ThreeLetterISORegionName\":\"MAR\"},{\"Name\":\"NP\",\"DisplayName\":\"Nepal\",\"TwoLetterISORegionName\":\"NP\",\"ThreeLetterISORegionName\":\"NPL\"},{\"Name\":\"NL\",\"DisplayName\":\"Netherlands\",\"TwoLetterISORegionName\":\"NL\",\"ThreeLetterISORegionName\":\"NLD\"},{\"Name\":\"NZ\",\"DisplayName\":\"New Zealand\",\"TwoLetterISORegionName\":\"NZ\",\"ThreeLetterISORegionName\":\"NZL\"},{\"Name\":\"NI\",\"DisplayName\":\"Nicaragua\",\"TwoLetterISORegionName\":\"NI\",\"ThreeLetterISORegionName\":\"NIC\"},{\"Name\":\"NG\",\"DisplayName\":\"Nigeria\",\"TwoLetterISORegionName\":\"NG\",\"ThreeLetterISORegionName\":\"NGA\"},{\"Name\":\"NO\",\"DisplayName\":\"Norway\",\"TwoLetterISORegionName\":\"NO\",\"ThreeLetterISORegionName\":\"NOR\"},{\"Name\":\"OM\",\"DisplayName\":\"Oman\",\"TwoLetterISORegionName\":\"OM\",\"ThreeLetterISORegionName\":\"OMN\"},{\"Name\":\"PA\",\"DisplayName\":\"Panama\",\"TwoLetterISORegionName\":\"PA\",\"ThreeLetterISORegionName\":\"PAN\"},{\"Name\":\"PY\",\"DisplayName\":\"Paraguay\",\"TwoLetterISORegionName\":\"PY\",\"ThreeLetterISORegionName\":\"PRY\"},{\"Name\":\"CN\",\"DisplayName\":\"People's Republic of China\",\"TwoLetterISORegionName\":\"CN\",\"ThreeLetterISORegionName\":\"CHN\"},{\"Name\":\"PE\",\"DisplayName\":\"Peru\",\"TwoLetterISORegionName\":\"PE\",\"ThreeLetterISORegionName\":\"PER\"},{\"Name\":\"PH\",\"DisplayName\":\"Philippines\",\"TwoLetterISORegionName\":\"PH\",\"ThreeLetterISORegionName\":\"PHL\"},{\"Name\":\"PL\",\"DisplayName\":\"Poland\",\"TwoLetterISORegionName\":\"PL\",\"ThreeLetterISORegionName\":\"POL\"},{\"Name\":\"PT\",\"DisplayName\":\"Portugal\",\"TwoLetterISORegionName\":\"PT\",\"ThreeLetterISORegionName\":\"PRT\"},{\"Name\":\"MC\",\"DisplayName\":\"Principality of Monaco\",\"TwoLetterISORegionName\":\"MC\",\"ThreeLetterISORegionName\":\"MCO\"},{\"Name\":\"PR\",\"DisplayName\":\"Puerto Rico\",\"TwoLetterISORegionName\":\"PR\",\"ThreeLetterISORegionName\":\"PRI\"},{\"Name\":\"QA\",\"DisplayName\":\"Qatar\",\"TwoLetterISORegionName\":\"QA\",\"ThreeLetterISORegionName\":\"QAT\"},{\"Name\":\"MD\",\"DisplayName\":\"Republica Moldova\",\"TwoLetterISORegionName\":\"MD\",\"ThreeLetterISORegionName\":\"MDA\"},{\"Name\":\"RE\",\"DisplayName\":\"Réunion\",\"TwoLetterISORegionName\":\"RE\",\"ThreeLetterISORegionName\":\"REU\"},{\"Name\":\"RO\",\"DisplayName\":\"Romania\",\"TwoLetterISORegionName\":\"RO\",\"ThreeLetterISORegionName\":\"ROU\"},{\"Name\":\"RU\",\"DisplayName\":\"Russia\",\"TwoLetterISORegionName\":\"RU\",\"ThreeLetterISORegionName\":\"RUS\"},{\"Name\":\"RW\",\"DisplayName\":\"Rwanda\",\"TwoLetterISORegionName\":\"RW\",\"ThreeLetterISORegionName\":\"RWA\"},{\"Name\":\"SA\",\"DisplayName\":\"Saudi Arabia\",\"TwoLetterISORegionName\":\"SA\",\"ThreeLetterISORegionName\":\"SAU\"},{\"Name\":\"SN\",\"DisplayName\":\"Senegal\",\"TwoLetterISORegionName\":\"SN\",\"ThreeLetterISORegionName\":\"SEN\"},{\"Name\":\"RS\",\"DisplayName\":\"Serbia\",\"TwoLetterISORegionName\":\"RS\",\"ThreeLetterISORegionName\":\"SRB\"},{\"Name\":\"CS\",\"DisplayName\":\"Serbia and Montenegro (Former)\",\"TwoLetterISORegionName\":\"CS\",\"ThreeLetterISORegionName\":\"SCG\"},{\"Name\":\"SG\",\"DisplayName\":\"Singapore\",\"TwoLetterISORegionName\":\"SG\",\"ThreeLetterISORegionName\":\"SGP\"},{\"Name\":\"SK\",\"DisplayName\":\"Slovakia\",\"TwoLetterISORegionName\":\"SK\",\"ThreeLetterISORegionName\":\"SVK\"},{\"Name\":\"SI\",\"DisplayName\":\"Slovenia\",\"TwoLetterISORegionName\":\"SI\",\"ThreeLetterISORegionName\":\"SVN\"},{\"Name\":\"SO\",\"DisplayName\":\"Soomaaliya\",\"TwoLetterISORegionName\":\"SO\",\"ThreeLetterISORegionName\":\"SOM\"},{\"Name\":\"ZA\",\"DisplayName\":\"South Africa\",\"TwoLetterISORegionName\":\"ZA\",\"ThreeLetterISORegionName\":\"ZAF\"},{\"Name\":\"ES\",\"DisplayName\":\"Spain\",\"TwoLetterISORegionName\":\"ES\",\"ThreeLetterISORegionName\":\"ESP\"},{\"Name\":\"LK\",\"DisplayName\":\"Sri Lanka\",\"TwoLetterISORegionName\":\"LK\",\"ThreeLetterISORegionName\":\"LKA\"},{\"Name\":\"SE\",\"DisplayName\":\"Sweden\",\"TwoLetterISORegionName\":\"SE\",\"ThreeLetterISORegionName\":\"SWE\"},{\"Name\":\"CH\",\"DisplayName\":\"Switzerland\",\"TwoLetterISORegionName\":\"CH\",\"ThreeLetterISORegionName\":\"CHE\"},{\"Name\":\"SY\",\"DisplayName\":\"Syria\",\"TwoLetterISORegionName\":\"SY\",\"ThreeLetterISORegionName\":\"SYR\"},{\"Name\":\"TW\",\"DisplayName\":\"Taiwan\",\"TwoLetterISORegionName\":\"TW\",\"ThreeLetterISORegionName\":\"TWN\"},{\"Name\":\"TJ\",\"DisplayName\":\"Tajikistan\",\"TwoLetterISORegionName\":\"TJ\",\"ThreeLetterISORegionName\":\"TAJ\"},{\"Name\":\"TH\",\"DisplayName\":\"Thailand\",\"TwoLetterISORegionName\":\"TH\",\"ThreeLetterISORegionName\":\"THA\"},{\"Name\":\"TT\",\"DisplayName\":\"Trinidad and Tobago\",\"TwoLetterISORegionName\":\"TT\",\"ThreeLetterISORegionName\":\"TTO\"},{\"Name\":\"TN\",\"DisplayName\":\"Tunisia\",\"TwoLetterISORegionName\":\"TN\",\"ThreeLetterISORegionName\":\"TUN\"},{\"Name\":\"TR\",\"DisplayName\":\"Turkey\",\"TwoLetterISORegionName\":\"TR\",\"ThreeLetterISORegionName\":\"TUR\"},{\"Name\":\"TM\",\"DisplayName\":\"Turkmenistan\",\"TwoLetterISORegionName\":\"TM\",\"ThreeLetterISORegionName\":\"TKM\"},{\"Name\":\"AE\",\"DisplayName\":\"U.A.E.\",\"TwoLetterISORegionName\":\"AE\",\"ThreeLetterISORegionName\":\"ARE\"},{\"Name\":\"UA\",\"DisplayName\":\"Ukraine\",\"TwoLetterISORegionName\":\"UA\",\"ThreeLetterISORegionName\":\"UKR\"},{\"Name\":\"GB\",\"DisplayName\":\"United Kingdom\",\"TwoLetterISORegionName\":\"GB\",\"ThreeLetterISORegionName\":\"GBR\"},{\"Name\":\"US\",\"DisplayName\":\"United States\",\"TwoLetterISORegionName\":\"US\",\"ThreeLetterISORegionName\":\"USA\"},{\"Name\":\"UY\",\"DisplayName\":\"Uruguay\",\"TwoLetterISORegionName\":\"UY\",\"ThreeLetterISORegionName\":\"URY\"},{\"Name\":\"UZ\",\"DisplayName\":\"Uzbekistan\",\"TwoLetterISORegionName\":\"UZ\",\"ThreeLetterISORegionName\":\"UZB\"},{\"Name\":\"VN\",\"DisplayName\":\"Vietnam\",\"TwoLetterISORegionName\":\"VN\",\"ThreeLetterISORegionName\":\"VNM\"},{\"Name\":\"YE\",\"DisplayName\":\"Yemen\",\"TwoLetterISORegionName\":\"YE\",\"ThreeLetterISORegionName\":\"YEM\"},{\"Name\":\"ZW\",\"DisplayName\":\"Zimbabwe\",\"TwoLetterISORegionName\":\"ZW\",\"ThreeLetterISORegionName\":\"ZWE\"}]";
-
- return _jsonSerializer.DeserializeFromString<CountryInfo[]>(jsonCountries);
- }
+ public Task<CountryInfo[]> GetCountries()
+ => _jsonSerializer.DeserializeFromStreamAsync<CountryInfo[]>(
+ _assembly.GetManifestResourceStream("Emby.Server.Implementations.Localization.countries.json"));
/// <summary>
/// Gets the parental ratings.
/// </summary>
/// <returns>IEnumerable{ParentalRating}.</returns>
- public ParentalRating[] GetParentalRatings()
- {
- return GetParentalRatingsDictionary().Values.ToArray();
- }
+ public IEnumerable<ParentalRating> GetParentalRatings()
+ => GetParentalRatingsDictionary().Values;
/// <summary>
/// Gets the parental ratings dictionary.
@@ -288,14 +274,7 @@ namespace Emby.Server.Implementations.Localization
countryCode = "us";
}
- var ratings = GetRatings(countryCode);
-
- if (ratings == null)
- {
- ratings = GetRatings("us");
- }
-
- return ratings;
+ return GetRatings(countryCode) ?? GetRatings("us");
}
/// <summary>
@@ -314,37 +293,43 @@ namespace Emby.Server.Implementations.Localization
/// </summary>
/// <param name="file">The file.</param>
/// <returns>Dictionary{System.StringParentalRating}.</returns>
- private void LoadRatings(string file)
+ private async Task LoadRatings(string file)
{
- var dict = File.ReadAllLines(file).Select(i =>
+ Dictionary<string, ParentalRating> dict
+ = new Dictionary<string, ParentalRating>(StringComparer.OrdinalIgnoreCase);
+
+ using (var str = File.OpenRead(file))
+ using (var reader = new StreamReader(str))
{
- if (!string.IsNullOrWhiteSpace(i))
+ string line;
+ while ((line = await reader.ReadLineAsync()) != null)
{
- var parts = i.Split(',');
+ if (string.IsNullOrWhiteSpace(line))
+ {
+ continue;
+ }
- if (parts.Length == 2)
+ string[] parts = line.Split(',');
+ if (parts.Length == 2
+ && int.TryParse(parts[1], NumberStyles.Integer, UsCulture, out var value))
{
- if (int.TryParse(parts[1], NumberStyles.Integer, UsCulture, out var value))
- {
- return new ParentalRating { Name = parts[0], Value = value };
- }
+ dict.Add(parts[0], (new ParentalRating { Name = parts[0], Value = value }));
}
+#if DEBUG
+ else
+ {
+ _logger.LogWarning("Misformed line in {Path}", file);
+ }
+#endif
}
+ }
- return null;
-
- })
- .Where(i => i != null)
- .ToDictionary(i => i.Name, StringComparer.OrdinalIgnoreCase);
-
- var countryCode = Path.GetFileNameWithoutExtension(file)
- .Split('-')
- .Last();
+ var countryCode = Path.GetFileNameWithoutExtension(file).Split('-')[1];
_allParentalRatings[countryCode] = dict;
}
- private readonly string[] _unratedValues = { "n/a", "unrated", "not rated" };
+ private static readonly string[] _unratedValues = { "n/a", "unrated", "not rated" };
/// <summary>
/// Gets the rating level.
@@ -435,7 +420,7 @@ namespace Emby.Server.Implementations.Localization
return phrase;
}
- const string DefaultCulture = "en-US";
+ private const string DefaultCulture = "en-US";
private readonly ConcurrentDictionary<string, Dictionary<string, string>> _dictionaries =
new ConcurrentDictionary<string, Dictionary<string, string>>(StringComparer.OrdinalIgnoreCase);
@@ -450,10 +435,11 @@ namespace Emby.Server.Implementations.Localization
const string prefix = "Core";
var key = prefix + culture;
- return _dictionaries.GetOrAdd(key, k => GetDictionary(prefix, culture, DefaultCulture + ".json"));
+ return _dictionaries.GetOrAdd(key,
+ f => GetDictionary(prefix, culture, DefaultCulture + ".json").GetAwaiter().GetResult());
}
- private Dictionary<string, string> GetDictionary(string prefix, string culture, string baseFilename)
+ private async Task<Dictionary<string, string>> GetDictionary(string prefix, string culture, string baseFilename)
{
if (string.IsNullOrEmpty(culture))
{
@@ -464,25 +450,30 @@ namespace Emby.Server.Implementations.Localization
var namespaceName = GetType().Namespace + "." + prefix;
- CopyInto(dictionary, namespaceName + "." + baseFilename);
- CopyInto(dictionary, namespaceName + "." + GetResourceFilename(culture));
+ await CopyInto(dictionary, namespaceName + "." + baseFilename);
+ await CopyInto(dictionary, namespaceName + "." + GetResourceFilename(culture));
return dictionary;
}
- private void CopyInto(IDictionary<string, string> dictionary, string resourcePath)
+ private async Task CopyInto(IDictionary<string, string> dictionary, string resourcePath)
{
- using (var stream = _assemblyInfo.GetManifestResourceStream(GetType(), resourcePath))
+ using (var stream = _assembly.GetManifestResourceStream(resourcePath))
{
+ // If a Culture doesn't have a translation the stream will be null and it defaults to en-us further up the chain
if (stream != null)
{
- var dict = _jsonSerializer.DeserializeFromStream<Dictionary<string, string>>(stream);
+ var dict = await _jsonSerializer.DeserializeFromStreamAsync<Dictionary<string, string>>(stream);
foreach (var key in dict.Keys)
{
dictionary[key] = dict[key];
}
}
+ else
+ {
+ _logger.LogError("Missing translation/culture resource: {ResourcePath}", resourcePath);
+ }
}
}
@@ -492,11 +483,11 @@ namespace Emby.Server.Implementations.Localization
if (parts.Length == 2)
{
- culture = parts[0].ToLower() + "-" + parts[1].ToUpper();
+ culture = parts[0].ToLowerInvariant() + "-" + parts[1].ToUpperInvariant();
}
else
{
- culture = culture.ToLower();
+ culture = culture.ToLowerInvariant();
}
return culture + ".json";
@@ -506,29 +497,23 @@ namespace Emby.Server.Implementations.Localization
=> new LocalizationOption[]
{
new LocalizationOption("Arabic", "ar"),
- new LocalizationOption("Belarusian (Belarus)", "be-BY"),
new LocalizationOption("Bulgarian (Bulgaria)", "bg-BG"),
new LocalizationOption("Catalan", "ca"),
new LocalizationOption("Chinese Simplified", "zh-CN"),
new LocalizationOption("Chinese Traditional", "zh-TW"),
- new LocalizationOption("Chinese Traditional (Hong Kong)", "zh-HK"),
new LocalizationOption("Croatian", "hr"),
new LocalizationOption("Czech", "cs"),
new LocalizationOption("Danish", "da"),
new LocalizationOption("Dutch", "nl"),
new LocalizationOption("English (United Kingdom)", "en-GB"),
new LocalizationOption("English (United States)", "en-US"),
- new LocalizationOption("Finnish", "fi"),
new LocalizationOption("French", "fr"),
new LocalizationOption("French (Canada)", "fr-CA"),
new LocalizationOption("German", "de"),
new LocalizationOption("Greek", "el"),
new LocalizationOption("Hebrew", "he"),
- new LocalizationOption("Hindi (India)", "hi-IN"),
new LocalizationOption("Hungarian", "hu"),
- new LocalizationOption("Indonesian", "id"),
new LocalizationOption("Italian", "it"),
- new LocalizationOption("Japanese", "ja"),
new LocalizationOption("Kazakh", "kk"),
new LocalizationOption("Korean", "ko"),
new LocalizationOption("Lithuanian", "lt-LT"),
@@ -538,25 +523,15 @@ namespace Emby.Server.Implementations.Localization
new LocalizationOption("Polish", "pl"),
new LocalizationOption("Portuguese (Brazil)", "pt-BR"),
new LocalizationOption("Portuguese (Portugal)", "pt-PT"),
- new LocalizationOption("Romanian", "ro"),
new LocalizationOption("Russian", "ru"),
new LocalizationOption("Slovak", "sk"),
new LocalizationOption("Slovenian (Slovenia)", "sl-SI"),
new LocalizationOption("Spanish", "es"),
- new LocalizationOption("Spanish (Latin America)", "es-419"),
+ new LocalizationOption("Spanish (Argentina)", "es-AR"),
new LocalizationOption("Spanish (Mexico)", "es-MX"),
new LocalizationOption("Swedish", "sv"),
new LocalizationOption("Swiss German", "gsw"),
- new LocalizationOption("Turkish", "tr"),
- new LocalizationOption("Ukrainian", "uk"),
- new LocalizationOption("Vietnamese", "vi")
+ new LocalizationOption("Turkish", "tr")
};
}
-
- public interface ITextLocalizer
- {
- string RemoveDiacritics(string text);
-
- string NormalizeFormKD(string text);
- }
}
diff --git a/Emby.Server.Implementations/Localization/Ratings/br.txt b/Emby.Server.Implementations/Localization/Ratings/br.csv
index e5edaf62c..e5edaf62c 100644
--- a/Emby.Server.Implementations/Localization/Ratings/br.txt
+++ b/Emby.Server.Implementations/Localization/Ratings/br.csv
diff --git a/Emby.Server.Implementations/Localization/Ratings/ca.txt b/Emby.Server.Implementations/Localization/Ratings/ca.csv
index 5aef0580f..5aef0580f 100644
--- a/Emby.Server.Implementations/Localization/Ratings/ca.txt
+++ b/Emby.Server.Implementations/Localization/Ratings/ca.csv
diff --git a/Emby.Server.Implementations/Localization/Ratings/co.txt b/Emby.Server.Implementations/Localization/Ratings/co.csv
index 9684fa052..9684fa052 100644
--- a/Emby.Server.Implementations/Localization/Ratings/co.txt
+++ b/Emby.Server.Implementations/Localization/Ratings/co.csv
diff --git a/Emby.Server.Implementations/Localization/Ratings/dk.txt b/Emby.Server.Implementations/Localization/Ratings/dk.csv
index 5364ae1f2..5364ae1f2 100644
--- a/Emby.Server.Implementations/Localization/Ratings/dk.txt
+++ b/Emby.Server.Implementations/Localization/Ratings/dk.csv
diff --git a/Emby.Server.Implementations/Localization/Ratings/es.txt b/Emby.Server.Implementations/Localization/Ratings/es.csv
index 887d91ba6..887d91ba6 100644
--- a/Emby.Server.Implementations/Localization/Ratings/es.txt
+++ b/Emby.Server.Implementations/Localization/Ratings/es.csv
diff --git a/Emby.Server.Implementations/Localization/Ratings/fr.txt b/Emby.Server.Implementations/Localization/Ratings/fr.csv
index f586a3fa9..f586a3fa9 100644
--- a/Emby.Server.Implementations/Localization/Ratings/fr.txt
+++ b/Emby.Server.Implementations/Localization/Ratings/fr.csv
diff --git a/Emby.Server.Implementations/Localization/Ratings/gb.txt b/Emby.Server.Implementations/Localization/Ratings/gb.csv
index c1f7d0452..c1f7d0452 100644
--- a/Emby.Server.Implementations/Localization/Ratings/gb.txt
+++ b/Emby.Server.Implementations/Localization/Ratings/gb.csv
diff --git a/Emby.Server.Implementations/Localization/Ratings/ie.txt b/Emby.Server.Implementations/Localization/Ratings/ie.csv
index e42be5cd4..e42be5cd4 100644
--- a/Emby.Server.Implementations/Localization/Ratings/ie.txt
+++ b/Emby.Server.Implementations/Localization/Ratings/ie.csv
diff --git a/Emby.Server.Implementations/Localization/Ratings/jp.txt b/Emby.Server.Implementations/Localization/Ratings/jp.csv
index a8fc2d143..a8fc2d143 100644
--- a/Emby.Server.Implementations/Localization/Ratings/jp.txt
+++ b/Emby.Server.Implementations/Localization/Ratings/jp.csv
diff --git a/Emby.Server.Implementations/Localization/Ratings/kz.txt b/Emby.Server.Implementations/Localization/Ratings/kz.csv
index 4441c5650..4441c5650 100644
--- a/Emby.Server.Implementations/Localization/Ratings/kz.txt
+++ b/Emby.Server.Implementations/Localization/Ratings/kz.csv
diff --git a/Emby.Server.Implementations/Localization/Ratings/mx.txt b/Emby.Server.Implementations/Localization/Ratings/mx.csv
index 785a8ba22..785a8ba22 100644
--- a/Emby.Server.Implementations/Localization/Ratings/mx.txt
+++ b/Emby.Server.Implementations/Localization/Ratings/mx.csv
diff --git a/Emby.Server.Implementations/Localization/Ratings/nl.txt b/Emby.Server.Implementations/Localization/Ratings/nl.csv
index 8c005092e..8c005092e 100644
--- a/Emby.Server.Implementations/Localization/Ratings/nl.txt
+++ b/Emby.Server.Implementations/Localization/Ratings/nl.csv
diff --git a/Emby.Server.Implementations/Localization/Ratings/nz.txt b/Emby.Server.Implementations/Localization/Ratings/nz.csv
index bba99b764..bba99b764 100644
--- a/Emby.Server.Implementations/Localization/Ratings/nz.txt
+++ b/Emby.Server.Implementations/Localization/Ratings/nz.csv
diff --git a/Emby.Server.Implementations/Localization/Ratings/ro.txt b/Emby.Server.Implementations/Localization/Ratings/ro.csv
index 4089b282f..4089b282f 100644
--- a/Emby.Server.Implementations/Localization/Ratings/ro.txt
+++ b/Emby.Server.Implementations/Localization/Ratings/ro.csv
diff --git a/Emby.Server.Implementations/Localization/Ratings/uk.txt b/Emby.Server.Implementations/Localization/Ratings/uk.csv
index 6c8005b3f..6c8005b3f 100644
--- a/Emby.Server.Implementations/Localization/Ratings/uk.txt
+++ b/Emby.Server.Implementations/Localization/Ratings/uk.csv
diff --git a/Emby.Server.Implementations/Localization/Ratings/us.txt b/Emby.Server.Implementations/Localization/Ratings/us.csv
index 34c897fe3..34c897fe3 100644
--- a/Emby.Server.Implementations/Localization/Ratings/us.txt
+++ b/Emby.Server.Implementations/Localization/Ratings/us.csv
diff --git a/Emby.Server.Implementations/Localization/TextLocalizer.cs b/Emby.Server.Implementations/Localization/TextLocalizer.cs
deleted file mode 100644
index 96591e5e6..000000000
--- a/Emby.Server.Implementations/Localization/TextLocalizer.cs
+++ /dev/null
@@ -1,63 +0,0 @@
-using System;
-using System.Globalization;
-using System.Linq;
-using System.Text;
-using System.Text.RegularExpressions;
-
-namespace Emby.Server.Implementations.Localization
-{
- public class TextLocalizer : ITextLocalizer
- {
- public string RemoveDiacritics(string text)
- {
- if (text == null)
- {
- throw new ArgumentNullException(nameof(text));
- }
-
- var chars = Normalize(text, NormalizationForm.FormD)
- .Where(ch => CharUnicodeInfo.GetUnicodeCategory(ch) != UnicodeCategory.NonSpacingMark);
-
- return Normalize(string.Concat(chars), NormalizationForm.FormC);
- }
-
- private static string Normalize(string text, NormalizationForm form, bool stripStringOnFailure = true)
- {
- if (stripStringOnFailure)
- {
- try
- {
- return text.Normalize(form);
- }
- catch (ArgumentException)
- {
- // will throw if input contains invalid unicode chars
- // https://mnaoumov.wordpress.com/2014/06/14/stripping-invalid-characters-from-utf-16-strings/
- text = StripInvalidUnicodeCharacters(text);
- return Normalize(text, form, false);
- }
- }
-
- try
- {
- return text.Normalize(form);
- }
- catch (ArgumentException)
- {
- // if it still fails, return the original text
- return text;
- }
- }
-
- private static string StripInvalidUnicodeCharacters(string str)
- {
- var invalidCharactersRegex = new Regex("([\ud800-\udbff](?![\udc00-\udfff]))|((?<![\ud800-\udbff])[\udc00-\udfff])");
- return invalidCharactersRegex.Replace(str, "");
- }
-
- public string NormalizeFormKD(string text)
- {
- return text.Normalize(NormalizationForm.FormKD);
- }
- }
-}
diff --git a/Emby.Server.Implementations/Localization/iso6392.txt b/Emby.Server.Implementations/Localization/iso6392.txt
index f2cea78b6..40f8614f1 100644
--- a/Emby.Server.Implementations/Localization/iso6392.txt
+++ b/Emby.Server.Implementations/Localization/iso6392.txt
@@ -400,6 +400,7 @@ sog|||Sogdian|sogdien
som||so|Somali|somali
son|||Songhai languages|songhai, langues
sot||st|Sotho, Southern|sotho du Sud
+spa||es-mx|Spanish; Latin|espagnol; Latin
spa||es|Spanish; Castilian|espagnol; castillan
srd||sc|Sardinian|sarde
srn|||Sranan Tongo|sranan tongo
diff --git a/Emby.Server.Implementations/Networking/IPNetwork/BigIntegerExt.cs b/Emby.Server.Implementations/Networking/IPNetwork/BigIntegerExt.cs
index 447cbf403..e4e944839 100644
--- a/Emby.Server.Implementations/Networking/IPNetwork/BigIntegerExt.cs
+++ b/Emby.Server.Implementations/Networking/IPNetwork/BigIntegerExt.cs
@@ -1,11 +1,10 @@
+using System;
using System.Collections.Generic;
+using System.Numerics;
+using System.Text;
-namespace System.Net
+namespace Emby.Server.Implementations.Networking.IPNetwork
{
- using System;
- using System.Numerics;
- using System.Text;
-
/// <summary>
/// Extension methods to convert <see cref="BigInteger"/>
/// instances to hexadecimal, octal, and binary strings.
diff --git a/Emby.Server.Implementations/Networking/IPNetwork/IPAddressCollection.cs b/Emby.Server.Implementations/Networking/IPNetwork/IPAddressCollection.cs
index c5853135c..a0c5f73af 100644
--- a/Emby.Server.Implementations/Networking/IPNetwork/IPAddressCollection.cs
+++ b/Emby.Server.Implementations/Networking/IPNetwork/IPAddressCollection.cs
@@ -1,8 +1,10 @@
+using System;
using System.Collections;
using System.Collections.Generic;
+using System.Net;
using System.Numerics;
-namespace System.Net
+namespace Emby.Server.Implementations.Networking.IPNetwork
{
public class IPAddressCollection : IEnumerable<IPAddress>, IEnumerator<IPAddress>
{
@@ -29,7 +31,7 @@ namespace System.Net
{
throw new ArgumentOutOfRangeException(nameof(i));
}
- byte width = this._ipnetwork.AddressFamily == Sockets.AddressFamily.InterNetwork ? (byte)32 : (byte)128;
+ byte width = this._ipnetwork.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork ? (byte)32 : (byte)128;
var ipn = this._ipnetwork.Subnet(width);
return ipn[i].Network;
}
diff --git a/Emby.Server.Implementations/Networking/IPNetwork/IPNetwork.cs b/Emby.Server.Implementations/Networking/IPNetwork/IPNetwork.cs
index 16f39daf7..d6de61c0c 100644
--- a/Emby.Server.Implementations/Networking/IPNetwork/IPNetwork.cs
+++ b/Emby.Server.Implementations/Networking/IPNetwork/IPNetwork.cs
@@ -1,10 +1,12 @@
+using System;
using System.Collections.Generic;
using System.IO;
+using System.Net;
using System.Net.Sockets;
using System.Numerics;
using System.Text.RegularExpressions;
-namespace System.Net
+namespace Emby.Server.Implementations.Networking.IPNetwork
{
/// <summary>
/// IP Network utility class.
@@ -60,7 +62,7 @@ namespace System.Net
get
{
- int width = this._family == Sockets.AddressFamily.InterNetwork ? 4 : 16;
+ int width = this._family == System.Net.Sockets.AddressFamily.InterNetwork ? 4 : 16;
var uintBroadcast = this._network + this._netmask.PositiveReverse(width);
return uintBroadcast;
}
@@ -73,7 +75,7 @@ namespace System.Net
{
get
{
- if (this._family == Sockets.AddressFamily.InterNetworkV6)
+ if (this._family == System.Net.Sockets.AddressFamily.InterNetworkV6)
{
return null;
}
@@ -88,7 +90,7 @@ namespace System.Net
{
get
{
- var fisrt = this._family == Sockets.AddressFamily.InterNetworkV6
+ var fisrt = this._family == System.Net.Sockets.AddressFamily.InterNetworkV6
? this._network
: (this.Usable <= 0) ? this._network : this._network + 1;
return IPNetwork.ToIPAddress(fisrt, this._family);
@@ -102,7 +104,7 @@ namespace System.Net
{
get
{
- var last = this._family == Sockets.AddressFamily.InterNetworkV6
+ var last = this._family == System.Net.Sockets.AddressFamily.InterNetworkV6
? this._broadcast
: (this.Usable <= 0) ? this._network : this._broadcast - 1;
return IPNetwork.ToIPAddress(last, this._family);
@@ -117,7 +119,7 @@ namespace System.Net
get
{
- if (this._family == Sockets.AddressFamily.InterNetworkV6)
+ if (this._family == System.Net.Sockets.AddressFamily.InterNetworkV6)
{
return this.Total;
}
@@ -136,7 +138,7 @@ namespace System.Net
get
{
- int max = this._family == Sockets.AddressFamily.InterNetwork ? 32 : 128;
+ int max = this._family == System.Net.Sockets.AddressFamily.InterNetwork ? 32 : 128;
var count = BigInteger.Pow(2, (max - _cidr));
return count;
}
@@ -161,7 +163,7 @@ namespace System.Net
IPNetwork(BigInteger ipaddress, AddressFamily family, byte cidr)
{
- int maxCidr = family == Sockets.AddressFamily.InterNetwork ? 32 : 128;
+ int maxCidr = family == System.Net.Sockets.AddressFamily.InterNetwork ? 32 : 128;
if (cidr > maxCidr)
{
throw new ArgumentOutOfRangeException(nameof(cidr));
@@ -930,7 +932,7 @@ namespace System.Net
/// return;
/// }
- int maxCidr = family == Sockets.AddressFamily.InterNetwork ? 32 : 128;
+ int maxCidr = family == System.Net.Sockets.AddressFamily.InterNetwork ? 32 : 128;
if (cidr > maxCidr)
{
if (tryParse == false)
@@ -1303,7 +1305,7 @@ namespace System.Net
return;
}
- int maxCidr = network._family == Sockets.AddressFamily.InterNetwork ? 32 : 128;
+ int maxCidr = network._family == System.Net.Sockets.AddressFamily.InterNetwork ? 32 : 128;
if (cidr > maxCidr)
{
if (trySubnet == false)
diff --git a/Emby.Server.Implementations/Networking/IPNetwork/IPNetworkCollection.cs b/Emby.Server.Implementations/Networking/IPNetwork/IPNetworkCollection.cs
index 7d3106624..4cda421e5 100644
--- a/Emby.Server.Implementations/Networking/IPNetwork/IPNetworkCollection.cs
+++ b/Emby.Server.Implementations/Networking/IPNetwork/IPNetworkCollection.cs
@@ -1,8 +1,9 @@
+using System;
using System.Collections;
using System.Collections.Generic;
using System.Numerics;
-namespace System.Net
+namespace Emby.Server.Implementations.Networking.IPNetwork
{
public class IPNetworkCollection : IEnumerable<IPNetwork>, IEnumerator<IPNetwork>
{
@@ -25,7 +26,7 @@ namespace System.Net
IPNetworkCollection(IPNetwork ipnetwork, byte cidrSubnet)
{
- int maxCidr = ipnetwork.AddressFamily == Sockets.AddressFamily.InterNetwork ? 32 : 128;
+ int maxCidr = ipnetwork.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork ? 32 : 128;
if (cidrSubnet > maxCidr)
{
throw new ArgumentOutOfRangeException(nameof(cidrSubnet));
@@ -61,7 +62,7 @@ namespace System.Net
throw new ArgumentOutOfRangeException(nameof(i));
}
- var last = this._ipnetwork.AddressFamily == Sockets.AddressFamily.InterNetworkV6
+ var last = this._ipnetwork.AddressFamily == System.Net.Sockets.AddressFamily.InterNetworkV6
? this._lastUsable : this._broadcast;
var increment = (last - this._network) / this.Count;
var uintNetwork = this._network + ((increment + 1) * i);
diff --git a/Emby.Server.Implementations/Networking/NetworkManager.cs b/Emby.Server.Implementations/Networking/NetworkManager.cs
index f4b9f84dc..60cc9b88e 100644
--- a/Emby.Server.Implementations/Networking/NetworkManager.cs
+++ b/Emby.Server.Implementations/Networking/NetworkManager.cs
@@ -111,7 +111,8 @@ namespace Emby.Server.Implementations.Networking
.OrderBy(i => i.AddressFamily == AddressFamily.InterNetwork ? 0 : 1)
.ThenBy(i => listClone.IndexOf(i))
.Where(FilterIpAddress)
- .DistinctBy(i => i.ToString())
+ .GroupBy(i => i.ToString())
+ .Select(x => x.First())
.ToList();
}
@@ -280,7 +281,7 @@ namespace Emby.Server.Implementations.Networking
if (normalizedSubnet.IndexOf('/') != -1)
{
- var ipnetwork = IPNetwork.Parse(normalizedSubnet);
+ var ipnetwork = IPNetwork.IPNetwork.Parse(normalizedSubnet);
if (ipnetwork.Contains(address))
{
return true;
@@ -429,7 +430,8 @@ namespace Emby.Server.Implementations.Networking
return new List<IPAddress>();
}
- }).DistinctBy(i => i.ToString())
+ }).GroupBy(i => i.ToString())
+ .Select(x => x.First())
.ToList();
}
diff --git a/Emby.Server.Implementations/Playlists/PlaylistImageProvider.cs b/Emby.Server.Implementations/Playlists/PlaylistImageProvider.cs
index 223153164..8a7c1492d 100644
--- a/Emby.Server.Implementations/Playlists/PlaylistImageProvider.cs
+++ b/Emby.Server.Implementations/Playlists/PlaylistImageProvider.cs
@@ -13,7 +13,6 @@ using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Playlists;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Extensions;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Querying;
@@ -64,7 +63,8 @@ namespace Emby.Server.Implementations.Playlists
})
.Where(i => i != null)
.OrderBy(i => Guid.NewGuid())
- .DistinctBy(i => i.Id)
+ .GroupBy(x => x.Id)
+ .Select(x => x.First())
.ToList();
}
}
diff --git a/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs b/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs
index 2b648b04b..08bb39578 100644
--- a/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs
+++ b/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs
@@ -10,7 +10,6 @@ using MediaBrowser.Common.Progress;
using MediaBrowser.Model.Events;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Serialization;
-using MediaBrowser.Model.System;
using MediaBrowser.Model.Tasks;
using Microsoft.Extensions.Logging;
diff --git a/Emby.Server.Implementations/ScheduledTasks/TaskManager.cs b/Emby.Server.Implementations/ScheduledTasks/TaskManager.cs
index b8479fd26..595c3037d 100644
--- a/Emby.Server.Implementations/ScheduledTasks/TaskManager.cs
+++ b/Emby.Server.Implementations/ScheduledTasks/TaskManager.cs
@@ -1,14 +1,12 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
-using System.IO;
using System.Linq;
using System.Threading.Tasks;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Model.Events;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Serialization;
-using MediaBrowser.Model.System;
using MediaBrowser.Model.Tasks;
using Microsoft.Extensions.Logging;
@@ -74,38 +72,6 @@ namespace Emby.Server.Implementations.ScheduledTasks
ScheduledTasks = new IScheduledTaskWorker[] { };
}
- private void RunStartupTasks()
- {
- var path = Path.Combine(ApplicationPaths.CachePath, "startuptasks.txt");
-
- // ToDo: Fix this shit
- if (!File.Exists(path))
- return;
-
- List<string> lines;
-
- try
- {
- lines = File.ReadAllLines(path).Where(i => !string.IsNullOrWhiteSpace(i)).Distinct(StringComparer.OrdinalIgnoreCase).ToList();
-
- foreach (var key in lines)
- {
- var task = ScheduledTasks.FirstOrDefault(i => string.Equals(i.ScheduledTask.Key, key, StringComparison.OrdinalIgnoreCase));
-
- if (task != null)
- {
- QueueScheduledTask(task, new TaskOptions());
- }
- }
-
- _fileSystem.DeleteFile(path);
- }
- catch
- {
- return;
- }
- }
-
/// <summary>
/// Cancels if running and queue.
/// </summary>
@@ -247,14 +213,9 @@ namespace Emby.Server.Implementations.ScheduledTasks
/// <param name="tasks">The tasks.</param>
public void AddTasks(IEnumerable<IScheduledTask> tasks)
{
- var myTasks = ScheduledTasks.ToList();
-
- var list = tasks.ToList();
- myTasks.AddRange(list.Select(t => new ScheduledTaskWorker(t, ApplicationPaths, this, JsonSerializer, Logger, _fileSystem)));
-
- ScheduledTasks = myTasks.ToArray();
+ var list = tasks.Select(t => new ScheduledTaskWorker(t, ApplicationPaths, this, JsonSerializer, Logger, _fileSystem));
- RunStartupTasks();
+ ScheduledTasks = ScheduledTasks.Concat(list).ToArray();
}
/// <summary>
diff --git a/Emby.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs b/Emby.Server.Implementations/ScheduledTasks/Tasks/ChapterImagesTask.cs
index 5373b4392..81fdb96d2 100644
--- a/Emby.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs
+++ b/Emby.Server.Implementations/ScheduledTasks/Tasks/ChapterImagesTask.cs
@@ -68,8 +68,6 @@ namespace Emby.Server.Implementations.ScheduledTasks
};
}
- public string Key => "RefreshChapterImages";
-
/// <summary>
/// Returns the task to be executed
/// </summary>
@@ -161,22 +159,18 @@ namespace Emby.Server.Implementations.ScheduledTasks
}
}
- /// <summary>
- /// Gets the name of the task
- /// </summary>
- /// <value>The name.</value>
public string Name => "Chapter image extraction";
- /// <summary>
- /// Gets the description.
- /// </summary>
- /// <value>The description.</value>
public string Description => "Creates thumbnails for videos that have chapters.";
- /// <summary>
- /// Gets the category.
- /// </summary>
- /// <value>The category.</value>
public string Category => "Library";
+
+ public string Key => "RefreshChapterImages";
+
+ public bool IsHidden => false;
+
+ public bool IsEnabled => true;
+
+ public bool IsLogged => true;
}
}
diff --git a/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs b/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs
index 52077b242..6ec83b5c0 100644
--- a/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs
+++ b/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs
@@ -158,31 +158,15 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks
}
}
- /// <summary>
- /// Gets the name of the task
- /// </summary>
- /// <value>The name.</value>
public string Name => "Cache file cleanup";
- public string Key => "DeleteCacheFiles";
-
- /// <summary>
- /// Gets the description.
- /// </summary>
- /// <value>The description.</value>
public string Description => "Deletes cache files no longer needed by the system";
- /// <summary>
- /// Gets the category.
- /// </summary>
- /// <value>The category.</value>
public string Category => "Maintenance";
- /// <summary>
- /// Gets a value indicating whether this instance is hidden.
- /// </summary>
- /// <value><c>true</c> if this instance is hidden; otherwise, <c>false</c>.</value>
- public bool IsHidden => true;
+ public string Key => "DeleteCacheFiles";
+
+ public bool IsHidden => false;
public bool IsEnabled => true;
diff --git a/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteLogFileTask.cs b/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteLogFileTask.cs
index a57fe4945..e468c301a 100644
--- a/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteLogFileTask.cs
+++ b/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteLogFileTask.cs
@@ -81,31 +81,15 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks
return Task.CompletedTask;
}
- public string Key => "CleanLogFiles";
-
- /// <summary>
- /// Gets the name of the task
- /// </summary>
- /// <value>The name.</value>
public string Name => "Log file cleanup";
- /// <summary>
- /// Gets the description.
- /// </summary>
- /// <value>The description.</value>
public string Description => string.Format("Deletes log files that are more than {0} days old.", ConfigurationManager.CommonConfiguration.LogFileRetentionDays);
- /// <summary>
- /// Gets the category.
- /// </summary>
- /// <value>The category.</value>
public string Category => "Maintenance";
- /// <summary>
- /// Gets a value indicating whether this instance is hidden.
- /// </summary>
- /// <value><c>true</c> if this instance is hidden; otherwise, <c>false</c>.</value>
- public bool IsHidden => true;
+ public string Key => "CleanLogFiles";
+
+ public bool IsHidden => false;
public bool IsEnabled => true;
diff --git a/Emby.Server.Implementations/ScheduledTasks/PeopleValidationTask.cs b/Emby.Server.Implementations/ScheduledTasks/Tasks/PeopleValidationTask.cs
index 68031170f..d70799c47 100644
--- a/Emby.Server.Implementations/ScheduledTasks/PeopleValidationTask.cs
+++ b/Emby.Server.Implementations/ScheduledTasks/Tasks/PeopleValidationTask.cs
@@ -47,8 +47,6 @@ namespace Emby.Server.Implementations.ScheduledTasks
};
}
- public string Key => "RefreshPeople";
-
/// <summary>
/// Returns the task to be executed
/// </summary>
@@ -60,22 +58,18 @@ namespace Emby.Server.Implementations.ScheduledTasks
return _libraryManager.ValidatePeople(cancellationToken, progress);
}
- /// <summary>
- /// Gets the name of the task
- /// </summary>
- /// <value>The name.</value>
public string Name => "Refresh people";
- /// <summary>
- /// Gets the description.
- /// </summary>
- /// <value>The description.</value>
public string Description => "Updates metadata for actors and directors in your media library.";
- /// <summary>
- /// Gets the category.
- /// </summary>
- /// <value>The category.</value>
public string Category => "Library";
+
+ public string Key => "RefreshPeople";
+
+ public bool IsHidden => false;
+
+ public bool IsEnabled => true;
+
+ public bool IsLogged => true;
}
}
diff --git a/Emby.Server.Implementations/ScheduledTasks/Tasks/PluginUpdateTask.cs b/Emby.Server.Implementations/ScheduledTasks/Tasks/PluginUpdateTask.cs
new file mode 100644
index 000000000..c6431c311
--- /dev/null
+++ b/Emby.Server.Implementations/ScheduledTasks/Tasks/PluginUpdateTask.cs
@@ -0,0 +1,119 @@
+using MediaBrowser.Common;
+using MediaBrowser.Common.Updates;
+using MediaBrowser.Model.Net;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using MediaBrowser.Common.Progress;
+using MediaBrowser.Model.Tasks;
+using Microsoft.Extensions.Logging;
+
+namespace Emby.Server.Implementations.ScheduledTasks
+{
+ /// <summary>
+ /// Plugin Update Task
+ /// </summary>
+ public class PluginUpdateTask : IScheduledTask, IConfigurableScheduledTask
+ {
+ /// <summary>
+ /// The _logger
+ /// </summary>
+ private readonly ILogger _logger;
+
+ private readonly IInstallationManager _installationManager;
+
+ private readonly IApplicationHost _appHost;
+
+ public PluginUpdateTask(ILogger logger, IInstallationManager installationManager, IApplicationHost appHost)
+ {
+ _logger = logger;
+ _installationManager = installationManager;
+ _appHost = appHost;
+ }
+
+ /// <summary>
+ /// Creates the triggers that define when the task will run
+ /// </summary>
+ /// <returns>IEnumerable{BaseTaskTrigger}.</returns>
+ public IEnumerable<TaskTriggerInfo> GetDefaultTriggers()
+ {
+ return new[] {
+
+ // At startup
+ new TaskTriggerInfo {Type = TaskTriggerInfo.TriggerStartup},
+
+ // Every so often
+ new TaskTriggerInfo { Type = TaskTriggerInfo.TriggerInterval, IntervalTicks = TimeSpan.FromHours(24).Ticks}
+ };
+ }
+
+ /// <summary>
+ /// Update installed plugins
+ /// </summary>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <param name="progress">The progress.</param>
+ /// <returns>Task.</returns>
+ public async Task Execute(CancellationToken cancellationToken, IProgress<double> progress)
+ {
+ progress.Report(0);
+
+ var packagesToInstall = (await _installationManager.GetAvailablePluginUpdates(typeof(PluginUpdateTask).Assembly.GetName().Version, true, cancellationToken).ConfigureAwait(false)).ToList();
+
+ progress.Report(10);
+
+ var numComplete = 0;
+
+ foreach (var package in packagesToInstall)
+ {
+ cancellationToken.ThrowIfCancellationRequested();
+
+ try
+ {
+ await _installationManager.InstallPackage(package, true, new SimpleProgress<double>(), cancellationToken).ConfigureAwait(false);
+ }
+ catch (OperationCanceledException)
+ {
+ // InstallPackage has it's own inner cancellation token, so only throw this if it's ours
+ if (cancellationToken.IsCancellationRequested)
+ {
+ throw;
+ }
+ }
+ catch (HttpException ex)
+ {
+ _logger.LogError(ex, "Error downloading {0}", package.name);
+ }
+ catch (IOException ex)
+ {
+ _logger.LogError(ex, "Error updating {0}", package.name);
+ }
+
+ // Update progress
+ lock (progress)
+ {
+ numComplete++;
+ progress.Report(90.0 * numComplete / packagesToInstall.Count + 10);
+ }
+ }
+
+ progress.Report(100);
+ }
+
+ public string Name => "Check for plugin updates";
+
+ public string Description => "Downloads and installs updates for plugins that are configured to update automatically.";
+
+ public string Category => "Application";
+
+ public string Key => "PluginUpdates";
+
+ public bool IsHidden => false;
+
+ public bool IsEnabled => true;
+
+ public bool IsLogged => true;
+ }
+}
diff --git a/Emby.Server.Implementations/ScheduledTasks/RefreshMediaLibraryTask.cs b/Emby.Server.Implementations/ScheduledTasks/Tasks/RefreshMediaLibraryTask.cs
index f6fa64d13..1a3d85ad7 100644
--- a/Emby.Server.Implementations/ScheduledTasks/RefreshMediaLibraryTask.cs
+++ b/Emby.Server.Implementations/ScheduledTasks/Tasks/RefreshMediaLibraryTask.cs
@@ -58,24 +58,18 @@ namespace Emby.Server.Implementations.ScheduledTasks
return ((LibraryManager)_libraryManager).ValidateMediaLibraryInternal(progress, cancellationToken);
}
- /// <summary>
- /// Gets the name.
- /// </summary>
- /// <value>The name.</value>
public string Name => "Scan media library";
- /// <summary>
- /// Gets the description.
- /// </summary>
- /// <value>The description.</value>
public string Description => "Scans your media library and refreshes metatata based on configuration.";
- /// <summary>
- /// Gets the category.
- /// </summary>
- /// <value>The category.</value>
public string Category => "Library";
public string Key => "RefreshLibrary";
+
+ public bool IsHidden => false;
+
+ public bool IsEnabled => true;
+
+ public bool IsLogged => true;
}
}
diff --git a/Emby.Server.Implementations/ScheduledTasks/DailyTrigger.cs b/Emby.Server.Implementations/ScheduledTasks/Triggers/DailyTrigger.cs
index 98685cebe..98685cebe 100644
--- a/Emby.Server.Implementations/ScheduledTasks/DailyTrigger.cs
+++ b/Emby.Server.Implementations/ScheduledTasks/Triggers/DailyTrigger.cs
diff --git a/Emby.Server.Implementations/ScheduledTasks/IntervalTrigger.cs b/Emby.Server.Implementations/ScheduledTasks/Triggers/IntervalTrigger.cs
index 3a34da3af..3a34da3af 100644
--- a/Emby.Server.Implementations/ScheduledTasks/IntervalTrigger.cs
+++ b/Emby.Server.Implementations/ScheduledTasks/Triggers/IntervalTrigger.cs
diff --git a/Emby.Server.Implementations/ScheduledTasks/StartupTrigger.cs b/Emby.Server.Implementations/ScheduledTasks/Triggers/StartupTrigger.cs
index 08ff4f55f..08ff4f55f 100644
--- a/Emby.Server.Implementations/ScheduledTasks/StartupTrigger.cs
+++ b/Emby.Server.Implementations/ScheduledTasks/Triggers/StartupTrigger.cs
diff --git a/Emby.Server.Implementations/ScheduledTasks/WeeklyTrigger.cs b/Emby.Server.Implementations/ScheduledTasks/Triggers/WeeklyTrigger.cs
index 2a6a7b13c..2a6a7b13c 100644
--- a/Emby.Server.Implementations/ScheduledTasks/WeeklyTrigger.cs
+++ b/Emby.Server.Implementations/ScheduledTasks/Triggers/WeeklyTrigger.cs
diff --git a/Emby.Server.Implementations/Serialization/JsonSerializer.cs b/Emby.Server.Implementations/Serialization/JsonSerializer.cs
index 53ef5d60c..44898d498 100644
--- a/Emby.Server.Implementations/Serialization/JsonSerializer.cs
+++ b/Emby.Server.Implementations/Serialization/JsonSerializer.cs
@@ -3,9 +3,8 @@ using System.IO;
using System.Threading.Tasks;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Serialization;
-using Microsoft.Extensions.Logging;
-namespace Emby.Common.Implementations.Serialization
+namespace Emby.Server.Implementations.Serialization
{
/// <summary>
/// Provides a wrapper around third party json serialization.
diff --git a/Emby.Server.Implementations/ServerApplicationPaths.cs b/Emby.Server.Implementations/ServerApplicationPaths.cs
index edea10a07..36975df50 100644
--- a/Emby.Server.Implementations/ServerApplicationPaths.cs
+++ b/Emby.Server.Implementations/ServerApplicationPaths.cs
@@ -18,8 +18,13 @@ namespace Emby.Server.Implementations
string appFolderPath,
string applicationResourcesPath,
string logDirectoryPath = null,
- string configurationDirectoryPath = null)
- : base(programDataPath, appFolderPath, logDirectoryPath, configurationDirectoryPath)
+ string configurationDirectoryPath = null,
+ string cacheDirectoryPath = null)
+ : base(programDataPath,
+ appFolderPath,
+ logDirectoryPath,
+ configurationDirectoryPath,
+ cacheDirectoryPath)
{
ApplicationResourcesPath = applicationResourcesPath;
}
@@ -136,12 +141,6 @@ namespace Emby.Server.Implementations
return path;
}
- /// <summary>
- /// Gets the game genre path.
- /// </summary>
- /// <value>The game genre path.</value>
- public string GameGenrePath => Path.Combine(InternalMetadataPath, "GameGenre");
-
private string _internalMetadataPath;
public string InternalMetadataPath
{
diff --git a/Emby.Server.Implementations/Services/RequestHelper.cs b/Emby.Server.Implementations/Services/RequestHelper.cs
index 24e9cbfa4..2563cac99 100644
--- a/Emby.Server.Implementations/Services/RequestHelper.cs
+++ b/Emby.Server.Implementations/Services/RequestHelper.cs
@@ -45,7 +45,7 @@ namespace Emby.Server.Implementations.Services
{
return contentType == null
? null
- : contentType.Split(';')[0].ToLower().Trim();
+ : contentType.Split(';')[0].ToLowerInvariant().Trim();
}
}
diff --git a/Emby.Server.Implementations/Services/ResponseHelper.cs b/Emby.Server.Implementations/Services/ResponseHelper.cs
index 16de1a083..dc9975347 100644
--- a/Emby.Server.Implementations/Services/ResponseHelper.cs
+++ b/Emby.Server.Implementations/Services/ResponseHelper.cs
@@ -70,7 +70,7 @@ namespace Emby.Server.Implementations.Services
response.ContentType = defaultContentType;
}
- if (new HashSet<string> { "application/json", }.Contains(response.ContentType))
+ if (response.ContentType == "application/json")
{
response.ContentType += "; charset=utf-8";
}
diff --git a/Emby.Server.Implementations/Services/ServiceExec.cs b/Emby.Server.Implementations/Services/ServiceExec.cs
index 45c918fa1..79f5c59e6 100644
--- a/Emby.Server.Implementations/Services/ServiceExec.cs
+++ b/Emby.Server.Implementations/Services/ServiceExec.cs
@@ -23,8 +23,6 @@ namespace Emby.Server.Implementations.Services
"POLL", "SUBSCRIBE", "UNSUBSCRIBE"
};
- public static HashSet<string> AllVerbsSet = new HashSet<string>(AllVerbs);
-
public static List<MethodInfo> GetActions(this Type serviceType)
{
var list = new List<MethodInfo>();
@@ -98,7 +96,7 @@ namespace Emby.Server.Implementations.Services
return Task.FromResult(response);
}
- var expectedMethodName = actionName.Substring(0, 1) + actionName.Substring(1).ToLower();
+ var expectedMethodName = actionName.Substring(0, 1) + actionName.Substring(1).ToLowerInvariant();
throw new NotImplementedException(string.Format("Could not find method named {1}({0}) or Any({0}) on Service {2}", requestDto.GetType().GetMethodName(), expectedMethodName, serviceType.GetMethodName()));
}
diff --git a/Emby.Server.Implementations/Services/ServiceMethod.cs b/Emby.Server.Implementations/Services/ServiceMethod.cs
index 7add72815..5018bf4a2 100644
--- a/Emby.Server.Implementations/Services/ServiceMethod.cs
+++ b/Emby.Server.Implementations/Services/ServiceMethod.cs
@@ -11,7 +11,7 @@ namespace Emby.Server.Implementations.Services
public static string Key(Type serviceType, string method, string requestDtoName)
{
- return serviceType.FullName + " " + method.ToUpper() + " " + requestDtoName;
+ return serviceType.FullName + " " + method.ToUpperInvariant() + " " + requestDtoName;
}
}
}
diff --git a/Emby.Server.Implementations/Services/ServicePath.cs b/Emby.Server.Implementations/Services/ServicePath.cs
index 7e1993b71..f575baca3 100644
--- a/Emby.Server.Implementations/Services/ServicePath.cs
+++ b/Emby.Server.Implementations/Services/ServicePath.cs
@@ -60,7 +60,7 @@ namespace Emby.Server.Implementations.Services
public static string[] GetPathPartsForMatching(string pathInfo)
{
- return pathInfo.ToLower().Split(new[] { PathSeperatorChar }, StringSplitOptions.RemoveEmptyEntries);
+ return pathInfo.ToLowerInvariant().Split(new[] { PathSeperatorChar }, StringSplitOptions.RemoveEmptyEntries);
}
public static List<string> GetFirstMatchHashKeys(string[] pathPartsForMatching)
@@ -104,7 +104,7 @@ namespace Emby.Server.Implementations.Services
this.Description = description;
this.restPath = path;
- this.Verbs = string.IsNullOrWhiteSpace(verbs) ? ServiceExecExtensions.AllVerbs : verbs.ToUpper().Split(new[] { ' ', ',' }, StringSplitOptions.RemoveEmptyEntries);
+ this.Verbs = string.IsNullOrWhiteSpace(verbs) ? ServiceExecExtensions.AllVerbs : verbs.ToUpperInvariant().Split(new[] { ' ', ',' }, StringSplitOptions.RemoveEmptyEntries);
var componentsList = new List<string>();
@@ -154,7 +154,7 @@ namespace Emby.Server.Implementations.Services
}
else
{
- this.literalsToMatch[i] = component.ToLower();
+ this.literalsToMatch[i] = component.ToLowerInvariant();
if (firstLiteralMatch == null)
{
@@ -189,7 +189,7 @@ namespace Emby.Server.Implementations.Services
foreach (var propertyInfo in GetSerializableProperties(RequestType))
{
var propertyName = propertyInfo.Name;
- propertyNamesMap.Add(propertyName.ToLower(), propertyName);
+ propertyNamesMap.Add(propertyName.ToLowerInvariant(), propertyName);
}
}
@@ -483,7 +483,7 @@ namespace Emby.Server.Implementations.Services
continue;
}
- if (!this.propertyNamesMap.TryGetValue(variableName.ToLower(), out var propertyNameOnRequest))
+ if (!this.propertyNamesMap.TryGetValue(variableName.ToLowerInvariant(), out var propertyNameOnRequest))
{
if (string.Equals("ignore", variableName, StringComparison.OrdinalIgnoreCase))
{
diff --git a/Emby.Server.Implementations/Services/SwaggerService.cs b/Emby.Server.Implementations/Services/SwaggerService.cs
index 9bceeabec..3e6970eef 100644
--- a/Emby.Server.Implementations/Services/SwaggerService.cs
+++ b/Emby.Server.Implementations/Services/SwaggerService.cs
@@ -216,40 +216,28 @@ namespace Emby.Server.Implementations.Services
{
var responses = new Dictionary<string, SwaggerResponse>
{
+ { "200", new SwaggerResponse { description = "OK" } }
};
- responses["200"] = new SwaggerResponse
+ var apiKeySecurity = new Dictionary<string, string[]>
{
- description = "OK"
+ { "api_key", Array.Empty<string>() }
};
- var security = new List<Dictionary<string, string[]>>();
-
- var apiKeySecurity = new Dictionary<string, string[]>();
- apiKeySecurity["api_key"] = Array.Empty<string>();
-
- security.Add(apiKeySecurity);
-
- result[verb.ToLower()] = new SwaggerMethod
+ result[verb.ToLowerInvariant()] = new SwaggerMethod
{
summary = info.Summary,
description = info.Description,
- produces = new[]
- {
- "application/json"
- },
- consumes = new[]
- {
- "application/json"
- },
+ produces = new[] { "application/json" },
+ consumes = new[] { "application/json" },
operationId = info.RequestType.Name,
tags = Array.Empty<string>(),
- parameters = new SwaggerParam[] { },
+ parameters = Array.Empty<SwaggerParam>(),
responses = responses,
- security = security.ToArray()
+ security = new [] { apiKeySecurity }
};
}
diff --git a/Emby.Server.Implementations/Session/SessionManager.cs b/Emby.Server.Implementations/Session/SessionManager.cs
index b03345e03..fa0ab62d3 100644
--- a/Emby.Server.Implementations/Session/SessionManager.cs
+++ b/Emby.Server.Implementations/Session/SessionManager.cs
@@ -27,7 +27,6 @@ using MediaBrowser.Model.Library;
using MediaBrowser.Model.Querying;
using MediaBrowser.Model.Serialization;
using MediaBrowser.Model.Session;
-using MediaBrowser.Model.Threading;
using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.Session
@@ -60,7 +59,6 @@ namespace Emby.Server.Implementations.Session
private readonly IAuthenticationRepository _authRepo;
private readonly IDeviceManager _deviceManager;
- private readonly ITimerFactory _timerFactory;
/// <summary>
/// The _active connections
@@ -103,8 +101,7 @@ namespace Emby.Server.Implementations.Session
IHttpClient httpClient,
IAuthenticationRepository authRepo,
IDeviceManager deviceManager,
- IMediaSourceManager mediaSourceManager,
- ITimerFactory timerFactory)
+ IMediaSourceManager mediaSourceManager)
{
_userDataManager = userDataManager;
_logger = loggerFactory.CreateLogger(nameof(SessionManager));
@@ -119,7 +116,6 @@ namespace Emby.Server.Implementations.Session
_authRepo = authRepo;
_deviceManager = deviceManager;
_mediaSourceManager = mediaSourceManager;
- _timerFactory = timerFactory;
_deviceManager.DeviceOptionsUpdated += _deviceManager_DeviceOptionsUpdated;
}
@@ -503,13 +499,13 @@ namespace Emby.Server.Implementations.Session
return users;
}
- private ITimer _idleTimer;
+ private Timer _idleTimer;
private void StartIdleCheckTimer()
{
if (_idleTimer == null)
{
- _idleTimer = _timerFactory.Create(CheckForIdlePlayback, null, TimeSpan.FromMinutes(5), TimeSpan.FromMinutes(5));
+ _idleTimer = new Timer(CheckForIdlePlayback, null, TimeSpan.FromMinutes(5), TimeSpan.FromMinutes(5));
}
}
private void StopIdleCheckTimer()
@@ -606,7 +602,7 @@ namespace Emby.Server.Implementations.Session
ClearTranscodingInfo(session.DeviceId);
}
- session.StartAutomaticProgress(_timerFactory, info);
+ session.StartAutomaticProgress(info);
var users = GetUsers(session);
@@ -717,7 +713,7 @@ namespace Emby.Server.Implementations.Session
if (!isAutomated)
{
- session.StartAutomaticProgress(_timerFactory, info);
+ session.StartAutomaticProgress(info);
}
StartIdleCheckTimer();
diff --git a/Emby.Server.Implementations/Sorting/GameSystemComparer.cs b/Emby.Server.Implementations/Sorting/GameSystemComparer.cs
deleted file mode 100644
index 2a04bae3c..000000000
--- a/Emby.Server.Implementations/Sorting/GameSystemComparer.cs
+++ /dev/null
@@ -1,51 +0,0 @@
-using System;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Sorting;
-using MediaBrowser.Model.Querying;
-
-namespace Emby.Server.Implementations.Sorting
-{
- public class GameSystemComparer : IBaseItemComparer
- {
- /// <summary>
- /// Compares the specified x.
- /// </summary>
- /// <param name="x">The x.</param>
- /// <param name="y">The y.</param>
- /// <returns>System.Int32.</returns>
- public int Compare(BaseItem x, BaseItem y)
- {
- return string.Compare(GetValue(x), GetValue(y), StringComparison.CurrentCultureIgnoreCase);
- }
-
- /// <summary>
- /// Gets the value.
- /// </summary>
- /// <param name="x">The x.</param>
- /// <returns>System.String.</returns>
- private static string GetValue(BaseItem x)
- {
- var game = x as Game;
-
- if (game != null)
- {
- return game.GameSystem;
- }
-
- var system = x as GameSystem;
-
- if (system != null)
- {
- return system.GameSystemName;
- }
-
- return string.Empty;
- }
-
- /// <summary>
- /// Gets the name.
- /// </summary>
- /// <value>The name.</value>
- public string Name => ItemSortBy.GameSystem;
- }
-}
diff --git a/Emby.Server.Implementations/Sorting/PlayersComparer.cs b/Emby.Server.Implementations/Sorting/PlayersComparer.cs
deleted file mode 100644
index e3652f36b..000000000
--- a/Emby.Server.Implementations/Sorting/PlayersComparer.cs
+++ /dev/null
@@ -1,43 +0,0 @@
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Sorting;
-using MediaBrowser.Model.Querying;
-
-namespace Emby.Server.Implementations.Sorting
-{
- public class PlayersComparer : IBaseItemComparer
- {
- /// <summary>
- /// Compares the specified x.
- /// </summary>
- /// <param name="x">The x.</param>
- /// <param name="y">The y.</param>
- /// <returns>System.Int32.</returns>
- public int Compare(BaseItem x, BaseItem y)
- {
- return GetValue(x).CompareTo(GetValue(y));
- }
-
- /// <summary>
- /// Gets the value.
- /// </summary>
- /// <param name="x">The x.</param>
- /// <returns>System.String.</returns>
- private static int GetValue(BaseItem x)
- {
- var game = x as Game;
-
- if (game != null)
- {
- return game.PlayersSupported ?? 0;
- }
-
- return 0;
- }
-
- /// <summary>
- /// Gets the name.
- /// </summary>
- /// <value>The name.</value>
- public string Name => ItemSortBy.Players;
- }
-}
diff --git a/Emby.Server.Implementations/StartupOptions.cs b/Emby.Server.Implementations/StartupOptions.cs
deleted file mode 100644
index 221263634..000000000
--- a/Emby.Server.Implementations/StartupOptions.cs
+++ /dev/null
@@ -1,30 +0,0 @@
-using System;
-using System.Linq;
-
-namespace Emby.Server.Implementations
-{
- public class StartupOptions
- {
- private readonly string[] _options;
-
- public StartupOptions(string[] commandLineArgs)
- {
- _options = commandLineArgs;
- }
-
- public bool ContainsOption(string option)
- => _options.Contains(option, StringComparer.OrdinalIgnoreCase);
-
- public string GetOption(string name)
- {
- int index = Array.IndexOf(_options, name);
-
- if (index == -1)
- {
- return null;
- }
-
- return _options.ElementAtOrDefault(index + 1);
- }
- }
-}
diff --git a/Emby.Server.Implementations/Threading/CommonTimer.cs b/Emby.Server.Implementations/Threading/CommonTimer.cs
deleted file mode 100644
index 5a05da564..000000000
--- a/Emby.Server.Implementations/Threading/CommonTimer.cs
+++ /dev/null
@@ -1,36 +0,0 @@
-using System;
-using System.Threading;
-using MediaBrowser.Model.Threading;
-
-namespace Emby.Server.Implementations.Threading
-{
- public class CommonTimer : ITimer
- {
- private readonly Timer _timer;
-
- public CommonTimer(Action<object> callback, object state, TimeSpan dueTime, TimeSpan period)
- {
- _timer = new Timer(new TimerCallback(callback), state, dueTime, period);
- }
-
- public CommonTimer(Action<object> callback, object state, int dueTimeMs, int periodMs)
- {
- _timer = new Timer(new TimerCallback(callback), state, dueTimeMs, periodMs);
- }
-
- public void Change(TimeSpan dueTime, TimeSpan period)
- {
- _timer.Change(dueTime, period);
- }
-
- public void Change(int dueTimeMs, int periodMs)
- {
- _timer.Change(dueTimeMs, periodMs);
- }
-
- public void Dispose()
- {
- _timer.Dispose();
- }
- }
-}
diff --git a/Emby.Server.Implementations/Threading/TimerFactory.cs b/Emby.Server.Implementations/Threading/TimerFactory.cs
deleted file mode 100644
index ca50064c7..000000000
--- a/Emby.Server.Implementations/Threading/TimerFactory.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-using System;
-using MediaBrowser.Model.Threading;
-
-namespace Emby.Server.Implementations.Threading
-{
- public class TimerFactory : ITimerFactory
- {
- public ITimer Create(Action<object> callback, object state, TimeSpan dueTime, TimeSpan period)
- {
- return new CommonTimer(callback, state, dueTime, period);
- }
-
- public ITimer Create(Action<object> callback, object state, int dueTimeMs, int periodMs)
- {
- return new CommonTimer(callback, state, dueTimeMs, periodMs);
- }
- }
-}
diff --git a/Emby.Server.Implementations/Updates/InstallationManager.cs b/Emby.Server.Implementations/Updates/InstallationManager.cs
index 552155635..dc7f57f27 100644
--- a/Emby.Server.Implementations/Updates/InstallationManager.cs
+++ b/Emby.Server.Implementations/Updates/InstallationManager.cs
@@ -169,10 +169,8 @@ namespace Emby.Server.Implementations.Updates
string packageType = null,
Version applicationVersion = null)
{
- // TODO cvium: when plugins get back this would need to be fixed
- // var packages = await GetAvailablePackagesWithoutRegistrationInfo(cancellationToken).ConfigureAwait(false);
-
- return new List<PackageInfo>(); //FilterPackages(packages, packageType, applicationVersion);
+ var packages = await GetAvailablePackagesWithoutRegistrationInfo(cancellationToken).ConfigureAwait(false);
+ return FilterPackages(packages, packageType, applicationVersion);
}
/// <summary>
@@ -184,12 +182,10 @@ namespace Emby.Server.Implementations.Updates
{
using (var response = await _httpClient.SendAsync(new HttpRequestOptions
{
- Url = "https://www.mb3admin.local/admin/service/EmbyPackages.json",
+ Url = "https://repo.jellyfin.org/releases/plugin/manifest.json",
CancellationToken = cancellationToken,
Progress = new SimpleProgress<double>(),
- CacheLength = GetCacheLength(),
- CacheMode = CacheMode.Unconditional
-
+ CacheLength = GetCacheLength()
}, "GET").ConfigureAwait(false))
{
using (var stream = response.Content)
diff --git a/Emby.Server.Implementations/UserViews/CollectionFolderImageProvider.cs b/Emby.Server.Implementations/UserViews/CollectionFolderImageProvider.cs
index 8788cfc26..ce6c2cd87 100644
--- a/Emby.Server.Implementations/UserViews/CollectionFolderImageProvider.cs
+++ b/Emby.Server.Implementations/UserViews/CollectionFolderImageProvider.cs
@@ -43,10 +43,6 @@ namespace Emby.Server.Implementations.UserViews
{
includeItemTypes = new string[] { "Book", "AudioBook" };
}
- else if (string.Equals(viewType, CollectionType.Games))
- {
- includeItemTypes = new string[] { "Game" };
- }
else if (string.Equals(viewType, CollectionType.BoxSets))
{
includeItemTypes = new string[] { "BoxSet" };
diff --git a/Emby.Server.Implementations/UserViews/DynamicImageProvider.cs b/Emby.Server.Implementations/UserViews/DynamicImageProvider.cs
index 937db3f23..4ec68e550 100644
--- a/Emby.Server.Implementations/UserViews/DynamicImageProvider.cs
+++ b/Emby.Server.Implementations/UserViews/DynamicImageProvider.cs
@@ -12,7 +12,6 @@ using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Extensions;
using MediaBrowser.Model.IO;
namespace Emby.Server.Implementations.UserViews
@@ -83,7 +82,8 @@ namespace Emby.Server.Implementations.UserViews
return i;
- }).DistinctBy(i => i.Id);
+ }).GroupBy(x => x.Id)
+ .Select(x => x.First());
if (isUsingCollectionStrip)
{
diff --git a/Emby.Server.Implementations/UserViews/FolderImageProvider.cs b/Emby.Server.Implementations/UserViews/FolderImageProvider.cs
index 7629f6039..c810004ab 100644
--- a/Emby.Server.Implementations/UserViews/FolderImageProvider.cs
+++ b/Emby.Server.Implementations/UserViews/FolderImageProvider.cs
@@ -11,7 +11,7 @@ using MediaBrowser.Model.Entities;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Querying;
-namespace Emby.Server.Implementations.Photos
+namespace Emby.Server.Implementations.UserViews
{
public abstract class BaseFolderImageProvider<T> : BaseDynamicImageProvider<T>
where T : Folder, new()
diff --git a/Jellyfin.Drawing.Skia/SkiaEncoder.cs b/Jellyfin.Drawing.Skia/SkiaEncoder.cs
index f1b886ec6..dc714ed18 100644
--- a/Jellyfin.Drawing.Skia/SkiaEncoder.cs
+++ b/Jellyfin.Drawing.Skia/SkiaEncoder.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
@@ -35,8 +36,8 @@ namespace Jellyfin.Drawing.Skia
LogVersion();
}
- public string[] SupportedInputFormats =>
- new[]
+ public IReadOnlyCollection<string> SupportedInputFormats =>
+ new HashSet<string>(StringComparer.OrdinalIgnoreCase)
{
"jpeg",
"jpg",
@@ -62,7 +63,8 @@ namespace Jellyfin.Drawing.Skia
"arw"
};
- public ImageFormat[] SupportedOutputFormats => new[] { ImageFormat.Webp, ImageFormat.Jpg, ImageFormat.Png };
+ public IReadOnlyCollection<ImageFormat> SupportedOutputFormats
+ => new HashSet<ImageFormat>() { ImageFormat.Webp, ImageFormat.Jpg, ImageFormat.Png };
private void LogVersion()
{
@@ -253,7 +255,8 @@ namespace Jellyfin.Drawing.Skia
}
}
- private static string[] TransparentImageTypes = new string[] { ".png", ".gif", ".webp" };
+ private static readonly HashSet<string> TransparentImageTypes
+ = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { ".png", ".gif", ".webp" };
internal static SKBitmap Decode(string path, bool forceCleanBitmap, IFileSystem fileSystem, ImageOrientation? orientation, out SKEncodedOrigin origin)
{
@@ -262,7 +265,7 @@ namespace Jellyfin.Drawing.Skia
throw new FileNotFoundException("File not found", path);
}
- var requiresTransparencyHack = TransparentImageTypes.Contains(Path.GetExtension(path) ?? string.Empty);
+ var requiresTransparencyHack = TransparentImageTypes.Contains(Path.GetExtension(path));
if (requiresTransparencyHack || forceCleanBitmap)
{
diff --git a/Jellyfin.Drawing.Skia/StripCollageBuilder.cs b/Jellyfin.Drawing.Skia/StripCollageBuilder.cs
index 92115047c..dfdf39871 100644
--- a/Jellyfin.Drawing.Skia/StripCollageBuilder.cs
+++ b/Jellyfin.Drawing.Skia/StripCollageBuilder.cs
@@ -25,7 +25,7 @@ namespace Jellyfin.Drawing.Skia
throw new ArgumentNullException(nameof(outputPath));
}
- var ext = Path.GetExtension(outputPath).ToLower();
+ var ext = Path.GetExtension(outputPath).ToLowerInvariant();
if (ext == ".jpg" || ext == ".jpeg")
return SKEncodedImageFormat.Jpeg;
diff --git a/Jellyfin.Server/CoreAppHost.cs b/Jellyfin.Server/CoreAppHost.cs
index b580f45ca..315e34a04 100644
--- a/Jellyfin.Server/CoreAppHost.cs
+++ b/Jellyfin.Server/CoreAppHost.cs
@@ -2,7 +2,7 @@ using System.Collections.Generic;
using System.Reflection;
using Emby.Server.Implementations;
using Emby.Server.Implementations.HttpServer;
-using Jellyfin.SocketSharp;
+using Jellyfin.Server.SocketSharp;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.System;
using Microsoft.Extensions.Logging;
@@ -16,7 +16,7 @@ namespace Jellyfin.Server
{
}
- public override bool CanSelfRestart => StartupOptions.ContainsOption("-restartpath");
+ public override bool CanSelfRestart => StartupOptions.RestartPath != null;
protected override void RestartInternal() => Program.Restart();
diff --git a/Jellyfin.Server/Jellyfin.Server.csproj b/Jellyfin.Server/Jellyfin.Server.csproj
index 5a4bf5149..b1515df43 100644
--- a/Jellyfin.Server/Jellyfin.Server.csproj
+++ b/Jellyfin.Server/Jellyfin.Server.csproj
@@ -32,6 +32,7 @@
</PropertyGroup>
<ItemGroup>
+ <PackageReference Include="CommandLineParser" Version="2.4.3" />
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="2.2.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="2.2.0" />
<PackageReference Include="Serilog.AspNetCore" Version="2.1.1" />
@@ -40,9 +41,8 @@
<PackageReference Include="Serilog.Sinks.Console" Version="3.1.1" />
<PackageReference Include="Serilog.Sinks.File" Version="4.0.0" />
<PackageReference Include="SkiaSharp" Version="1.68.0" />
- <PackageReference Include="SQLitePCLRaw.bundle_e_sqlite3" Version="1.1.12" />
- <PackageReference Include="SQLitePCLRaw.core" Version="1.1.12" />
- <PackageReference Include="SQLitePCLRaw.provider.sqlite3.netstandard11" Version="1.1.12" />
+ <PackageReference Include="SQLitePCLRaw.bundle_e_sqlite3" Version="1.1.13" />
+ <PackageReference Include="SQLitePCLRaw.provider.sqlite3.netstandard11" Version="1.1.13" />
</ItemGroup>
<ItemGroup>
diff --git a/Jellyfin.Server/Program.cs b/Jellyfin.Server/Program.cs
index 66586d4e4..7826fde35 100644
--- a/Jellyfin.Server/Program.cs
+++ b/Jellyfin.Server/Program.cs
@@ -6,8 +6,10 @@ using System.Net;
using System.Net.Security;
using System.Reflection;
using System.Runtime.InteropServices;
+using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
+using CommandLine;
using Emby.Drawing;
using Emby.Server.Implementations;
using Emby.Server.Implementations.EnvironmentInfo;
@@ -35,19 +37,32 @@ namespace Jellyfin.Server
public static async Task Main(string[] args)
{
- StartupOptions options = new StartupOptions(args);
- Version version = Assembly.GetEntryAssembly().GetName().Version;
-
- if (options.ContainsOption("-v") || options.ContainsOption("--version"))
+ // For backwards compatibility.
+ // Modify any input arguments now which start with single-hyphen to POSIX standard
+ // double-hyphen to allow parsing by CommandLineParser package.
+ const string pattern = @"^(-[^-\s]{2})"; // Match -xx, not -x, not --xx, not xx
+ const string substitution = @"-$1"; // Prepend with additional single-hyphen
+ var regex = new Regex(pattern);
+
+ for (var i = 0; i < args.Length; i++)
{
- Console.WriteLine(version.ToString());
+ args[i] = regex.Replace(args[i], substitution);
}
+ // Parse the command line arguments and either start the app or exit indicating error
+ await Parser.Default.ParseArguments<StartupOptions>(args)
+ .MapResult(
+ options => StartApp(options),
+ errs => Task.FromResult(0)).ConfigureAwait(false);
+ }
+
+ private static async Task StartApp(StartupOptions options)
+ {
ServerApplicationPaths appPaths = CreateApplicationPaths(options);
// $JELLYFIN_LOG_DIR needs to be set for the logger configuration manager
Environment.SetEnvironmentVariable("JELLYFIN_LOG_DIR", appPaths.LogDirectoryPath);
- await createLogger(appPaths);
+ await CreateLogger(appPaths);
_logger = _loggerFactory.CreateLogger("Main");
AppDomain.CurrentDomain.UnhandledException += (sender, e)
@@ -78,9 +93,9 @@ namespace Jellyfin.Server
Shutdown();
};
- _logger.LogInformation("Jellyfin version: {Version}", version);
+ _logger.LogInformation("Jellyfin version: {Version}", Assembly.GetEntryAssembly().GetName().Version);
- EnvironmentInfo environmentInfo = new EnvironmentInfo(getOperatingSystem());
+ EnvironmentInfo environmentInfo = new EnvironmentInfo(GetOperatingSystem());
ApplicationHost.LogEnvironmentInfo(_logger, appPaths, environmentInfo);
SQLitePCL.Batteries_V2.Init();
@@ -99,12 +114,10 @@ namespace Jellyfin.Server
new NullImageEncoder(),
new NetworkManager(_loggerFactory, environmentInfo)))
{
- appHost.Init();
+ await appHost.Init();
appHost.ImageProcessor.ImageEncoder = GetImageEncoder(fileSystem, appPaths, appHost.LocalizationManager);
- _logger.LogInformation("Running startup tasks");
-
await appHost.RunStartupTasks();
// TODO: read input for a stop command
@@ -118,8 +131,6 @@ namespace Jellyfin.Server
{
// Don't throw on cancellation
}
-
- _logger.LogInformation("Disposing app host");
}
if (_restartOnShutdown)
@@ -133,9 +144,9 @@ namespace Jellyfin.Server
string programDataPath = Environment.GetEnvironmentVariable("JELLYFIN_DATA_PATH");
if (string.IsNullOrEmpty(programDataPath))
{
- if (options.ContainsOption("-programdata"))
+ if (options.DataDir != null)
{
- programDataPath = options.GetOption("-programdata");
+ programDataPath = options.DataDir;
}
else
{
@@ -171,9 +182,9 @@ namespace Jellyfin.Server
string configDir = Environment.GetEnvironmentVariable("JELLYFIN_CONFIG_DIR");
if (string.IsNullOrEmpty(configDir))
{
- if (options.ContainsOption("-configdir"))
+ if (options.ConfigDir != null)
{
- configDir = options.GetOption("-configdir");
+ configDir = options.ConfigDir;
}
else
{
@@ -187,12 +198,37 @@ namespace Jellyfin.Server
Directory.CreateDirectory(configDir);
}
+ string cacheDir = Environment.GetEnvironmentVariable("JELLYFIN_CACHE_DIR");
+ if (string.IsNullOrEmpty(cacheDir))
+ {
+ if (options.CacheDir != null)
+ {
+ cacheDir = options.CacheDir;
+ }
+ else if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+ {
+ // $XDG_CACHE_HOME defines the base directory relative to which user specific non-essential data files should be stored.
+ cacheDir = Environment.GetEnvironmentVariable("XDG_CACHE_HOME");
+ // If $XDG_CACHE_HOME is either not set or empty, $HOME/.cache should be used.
+ if (string.IsNullOrEmpty(cacheDir))
+ {
+ cacheDir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".cache");
+ }
+ cacheDir = Path.Combine(cacheDir, "jellyfin");
+ }
+ }
+
+ if (cacheDir != null)
+ {
+ Directory.CreateDirectory(cacheDir);
+ }
+
string logDir = Environment.GetEnvironmentVariable("JELLYFIN_LOG_DIR");
if (string.IsNullOrEmpty(logDir))
{
- if (options.ContainsOption("-logdir"))
+ if (options.LogDir != null)
{
- logDir = options.GetOption("-logdir");
+ logDir = options.LogDir;
}
else
{
@@ -208,10 +244,10 @@ namespace Jellyfin.Server
string appPath = AppContext.BaseDirectory;
- return new ServerApplicationPaths(programDataPath, appPath, appPath, logDir, configDir);
+ return new ServerApplicationPaths(programDataPath, appPath, appPath, logDir, configDir, cacheDir);
}
- private static async Task createLogger(IApplicationPaths appPaths)
+ private static async Task CreateLogger(IApplicationPaths appPaths)
{
try
{
@@ -271,7 +307,7 @@ namespace Jellyfin.Server
return new NullImageEncoder();
}
- private static MediaBrowser.Model.System.OperatingSystem getOperatingSystem()
+ private static MediaBrowser.Model.System.OperatingSystem GetOperatingSystem()
{
switch (Environment.OSVersion.Platform)
{
@@ -315,11 +351,11 @@ namespace Jellyfin.Server
Shutdown();
}
- private static void StartNewInstance(StartupOptions startupOptions)
+ private static void StartNewInstance(StartupOptions options)
{
_logger.LogInformation("Starting new instance");
- string module = startupOptions.GetOption("-restartpath");
+ string module = options.RestartPath;
if (string.IsNullOrWhiteSpace(module))
{
@@ -328,9 +364,9 @@ namespace Jellyfin.Server
string commandLineArgsString;
- if (startupOptions.ContainsOption("-restartargs"))
+ if (options.RestartArgs != null)
{
- commandLineArgsString = startupOptions.GetOption("-restartargs") ?? string.Empty;
+ commandLineArgsString = options.RestartArgs ?? string.Empty;
}
else
{
diff --git a/Jellyfin.Server/SocketSharp/HttpFile.cs b/Jellyfin.Server/SocketSharp/HttpFile.cs
index 77ce03510..89c75e536 100644
--- a/Jellyfin.Server/SocketSharp/HttpFile.cs
+++ b/Jellyfin.Server/SocketSharp/HttpFile.cs
@@ -1,7 +1,7 @@
using System.IO;
using MediaBrowser.Model.Services;
-namespace Jellyfin.SocketSharp
+namespace Jellyfin.Server.SocketSharp
{
public class HttpFile : IHttpFile
{
diff --git a/Jellyfin.Server/SocketSharp/RequestMono.cs b/Jellyfin.Server/SocketSharp/RequestMono.cs
index 017690062..a8ba4cdb5 100644
--- a/Jellyfin.Server/SocketSharp/RequestMono.cs
+++ b/Jellyfin.Server/SocketSharp/RequestMono.cs
@@ -7,11 +7,11 @@ using System.Text;
using System.Threading.Tasks;
using MediaBrowser.Model.Services;
-namespace Jellyfin.SocketSharp
+namespace Jellyfin.Server.SocketSharp
{
public partial class WebSocketSharpRequest : IHttpRequest
{
- static internal string GetParameter(string header, string attr)
+ internal static string GetParameter(string header, string attr)
{
int ap = header.IndexOf(attr);
if (ap == -1)
@@ -40,7 +40,7 @@ namespace Jellyfin.SocketSharp
return header.Substring(ap + 1, end - ap - 1);
}
- async Task LoadMultiPart(WebROCollection form)
+ private async Task LoadMultiPart(WebROCollection form)
{
string boundary = GetParameter(ContentType, "; boundary=");
if (boundary == null)
@@ -50,8 +50,8 @@ namespace Jellyfin.SocketSharp
using (var requestStream = InputStream)
{
- //DB: 30/01/11 - Hack to get around non-seekable stream and received HTTP request
- //Not ending with \r\n?
+ // DB: 30/01/11 - Hack to get around non-seekable stream and received HTTP request
+ // Not ending with \r\n?
var ms = new MemoryStream(32 * 1024);
await requestStream.CopyToAsync(ms).ConfigureAwait(false);
@@ -62,9 +62,9 @@ namespace Jellyfin.SocketSharp
input.Position = 0;
// Uncomment to debug
- //var content = new StreamReader(ms).ReadToEnd();
- //Console.WriteLine(boundary + "::" + content);
- //input.Position = 0;
+ // var content = new StreamReader(ms).ReadToEnd();
+ // Console.WriteLine(boundary + "::" + content);
+ // input.Position = 0;
var multi_part = new HttpMultipart(input, boundary, ContentEncoding);
@@ -111,7 +111,7 @@ namespace Jellyfin.SocketSharp
// Setting this before calling the validator prevents
// possible endless recursion
checked_form = true;
- ValidateNameValueCollection ("Form", query_string_nvc, RequestValidationSource.Form);
+ ValidateNameValueCollection("Form", query_string_nvc, RequestValidationSource.Form);
} else
#endif
if (validate_form && !checked_form)
@@ -130,7 +130,7 @@ namespace Jellyfin.SocketSharp
protected bool validate_cookies, validate_query_string, validate_form;
protected bool checked_cookies, checked_query_string, checked_form;
- static void ThrowValidationException(string name, string key, string value)
+ private static void ThrowValidationException(string name, string key, string value)
{
string v = "\"" + value + "\"";
if (v.Length > 20)
@@ -144,7 +144,7 @@ namespace Jellyfin.SocketSharp
throw new Exception(msg);
}
- static void ValidateNameValueCollection(string name, QueryParamCollection coll)
+ private static void ValidateNameValueCollection(string name, QueryParamCollection coll)
{
if (coll == null)
{
@@ -209,7 +209,7 @@ namespace Jellyfin.SocketSharp
validate_form = true;
}
- bool IsContentType(string ct, bool starts_with)
+ private bool IsContentType(string ct, bool starts_with)
{
if (ct == null || ContentType == null)
{
@@ -224,7 +224,7 @@ namespace Jellyfin.SocketSharp
return string.Equals(ContentType, ct, StringComparison.OrdinalIgnoreCase);
}
- async Task LoadWwwForm(WebROCollection form)
+ private async Task LoadWwwForm(WebROCollection form)
{
using (var input = InputStream)
{
@@ -280,7 +280,7 @@ namespace Jellyfin.SocketSharp
}
}
- static void AddRawKeyValue(WebROCollection form, StringBuilder key, StringBuilder value)
+ private static void AddRawKeyValue(WebROCollection form, StringBuilder key, StringBuilder value)
{
form.Add(WebUtility.UrlDecode(key.ToString()), WebUtility.UrlDecode(value.ToString()));
@@ -288,9 +288,9 @@ namespace Jellyfin.SocketSharp
value.Length = 0;
}
- Dictionary<string, HttpPostedFile> files;
+ private Dictionary<string, HttpPostedFile> files;
- class WebROCollection : QueryParamCollection
+ private class WebROCollection : QueryParamCollection
{
public override string ToString()
{
@@ -317,16 +317,16 @@ namespace Jellyfin.SocketSharp
public sealed class HttpPostedFile
{
- string name;
- string content_type;
- Stream stream;
+ private string name;
+ private string content_type;
+ private Stream stream;
- class ReadSubStream : Stream
+ private class ReadSubStream : Stream
{
- Stream s;
- long offset;
- long end;
- long position;
+ private Stream s;
+ private long offset;
+ private long end;
+ private long position;
public ReadSubStream(Stream s, long offset, long length)
{
@@ -360,13 +360,13 @@ namespace Jellyfin.SocketSharp
int len = buffer.Length;
if (dest_offset > len)
{
- throw new ArgumentException("destination offset is beyond array size");
+ throw new ArgumentException("destination offset is beyond array size", nameof(dest_offset));
}
// reordered to avoid possible integer overflow
if (dest_offset > len - count)
{
- throw new ArgumentException("Reading would overrun buffer");
+ throw new ArgumentException("Reading would overrun buffer", nameof(count));
}
if (count > end - position)
@@ -429,7 +429,7 @@ namespace Jellyfin.SocketSharp
real = position + d;
break;
default:
- throw new ArgumentException();
+ throw new ArgumentException(nameof(origin));
}
long virt = real - offset;
@@ -491,7 +491,7 @@ namespace Jellyfin.SocketSharp
public Stream InputStream => stream;
}
- class Helpers
+ private class Helpers
{
public static readonly CultureInfo InvariantCulture = CultureInfo.InvariantCulture;
}
@@ -528,7 +528,7 @@ namespace Jellyfin.SocketSharp
}
}
- class HttpMultipart
+ private class HttpMultipart
{
public class Element
@@ -543,19 +543,19 @@ namespace Jellyfin.SocketSharp
public override string ToString()
{
return "ContentType " + ContentType + ", Name " + Name + ", Filename " + Filename + ", Start " +
- Start.ToString() + ", Length " + Length.ToString();
+ Start.ToString(CultureInfo.CurrentCulture) + ", Length " + Length.ToString(CultureInfo.CurrentCulture);
}
}
- Stream data;
- string boundary;
- byte[] boundary_bytes;
- byte[] buffer;
- bool at_eof;
- Encoding encoding;
- StringBuilder sb;
+ private Stream data;
+ private string boundary;
+ private byte[] boundary_bytes;
+ private byte[] buffer;
+ private bool at_eof;
+ private Encoding encoding;
+ private StringBuilder sb;
- const byte LF = (byte)'\n', CR = (byte)'\r';
+ private const byte LF = (byte)'\n', CR = (byte)'\r';
// See RFC 2046
// In the case of multipart entities, in which one or more different
@@ -610,12 +610,11 @@ namespace Jellyfin.SocketSharp
}
return sb.ToString();
-
}
private static string GetContentDispositionAttribute(string l, string name)
{
- int idx = l.IndexOf(name + "=\"");
+ int idx = l.IndexOf(name + "=\"", StringComparison.Ordinal);
if (idx < 0)
{
return null;
@@ -638,7 +637,7 @@ namespace Jellyfin.SocketSharp
private string GetContentDispositionAttributeWithEncoding(string l, string name)
{
- int idx = l.IndexOf(name + "=\"");
+ int idx = l.IndexOf(name + "=\"", StringComparison.Ordinal);
if (idx < 0)
{
return null;
@@ -670,11 +669,12 @@ namespace Jellyfin.SocketSharp
{
try
{
- string line = ReadLine();
- while (line == string.Empty)
+ string line;
+ do
{
line = ReadLine();
}
+ while (line.Length == 0);
if (line[0] != '-' || line[1] != '-')
{
diff --git a/Jellyfin.Server/SocketSharp/SharpWebSocket.cs b/Jellyfin.Server/SocketSharp/SharpWebSocket.cs
index d0dcd86eb..f371cb25a 100644
--- a/Jellyfin.Server/SocketSharp/SharpWebSocket.cs
+++ b/Jellyfin.Server/SocketSharp/SharpWebSocket.cs
@@ -5,7 +5,7 @@ using System.Threading.Tasks;
using Emby.Server.Implementations.Net;
using Microsoft.Extensions.Logging;
-namespace Jellyfin.SocketSharp
+namespace Jellyfin.Server.SocketSharp
{
public class SharpWebSocket : IWebSocket
{
diff --git a/Jellyfin.Server/SocketSharp/WebSocketSharpListener.cs b/Jellyfin.Server/SocketSharp/WebSocketSharpListener.cs
index c7f9f01b5..a44343ab2 100644
--- a/Jellyfin.Server/SocketSharp/WebSocketSharpListener.cs
+++ b/Jellyfin.Server/SocketSharp/WebSocketSharpListener.cs
@@ -15,7 +15,7 @@ using MediaBrowser.Model.System;
using Microsoft.Extensions.Logging;
using SocketHttpListener.Net;
-namespace Jellyfin.SocketSharp
+namespace Jellyfin.Server.SocketSharp
{
public class WebSocketSharpListener : IHttpListener
{
diff --git a/Jellyfin.Server/SocketSharp/WebSocketSharpRequest.cs b/Jellyfin.Server/SocketSharp/WebSocketSharpRequest.cs
index 97550e686..ebeb18ea0 100644
--- a/Jellyfin.Server/SocketSharp/WebSocketSharpRequest.cs
+++ b/Jellyfin.Server/SocketSharp/WebSocketSharpRequest.cs
@@ -11,7 +11,7 @@ using IHttpRequest = MediaBrowser.Model.Services.IHttpRequest;
using IHttpResponse = MediaBrowser.Model.Services.IHttpResponse;
using IResponse = MediaBrowser.Model.Services.IResponse;
-namespace Jellyfin.SocketSharp
+namespace Jellyfin.Server.SocketSharp
{
public partial class WebSocketSharpRequest : IHttpRequest
{
@@ -29,12 +29,24 @@ namespace Jellyfin.SocketSharp
private static string GetHandlerPathIfAny(string listenerUrl)
{
- if (listenerUrl == null) return null;
+ if (listenerUrl == null)
+ {
+ return null;
+ }
+
var pos = listenerUrl.IndexOf("://", StringComparison.OrdinalIgnoreCase);
- if (pos == -1) return null;
+ if (pos == -1)
+ {
+ return null;
+ }
+
var startHostUrl = listenerUrl.Substring(pos + "://".Length);
var endPos = startHostUrl.IndexOf('/');
- if (endPos == -1) return null;
+ if (endPos == -1)
+ {
+ return null;
+ }
+
var endHostUrl = startHostUrl.Substring(endPos + 1);
return string.IsNullOrEmpty(endHostUrl) ? null : endHostUrl.TrimEnd('/');
}
@@ -68,15 +80,13 @@ namespace Jellyfin.SocketSharp
private string remoteIp;
public string RemoteIp =>
remoteIp ??
- (remoteIp = (CheckBadChars(XForwardedFor)) ??
- (NormalizeIp(CheckBadChars(XRealIp)) ??
+ (remoteIp = CheckBadChars(XForwardedFor) ??
+ NormalizeIp(CheckBadChars(XRealIp) ??
(request.RemoteEndPoint != null ? NormalizeIp(request.RemoteEndPoint.Address.ToString()) : null)));
private static readonly char[] HttpTrimCharacters = new char[] { (char)0x09, (char)0xA, (char)0xB, (char)0xC, (char)0xD, (char)0x20 };
- //
// CheckBadChars - throws on invalid chars to be not found in header name/value
- //
internal static string CheckBadChars(string name)
{
if (name == null || name.Length == 0)
@@ -85,11 +95,11 @@ namespace Jellyfin.SocketSharp
}
// VALUE check
- //Trim spaces from both ends
+ // Trim spaces from both ends
name = name.Trim(HttpTrimCharacters);
- //First, check for correctly formed multi-line value
- //Second, check for absenece of CTL characters
+ // First, check for correctly formed multi-line value
+ // Second, check for absenece of CTL characters
int crlf = 0;
for (int i = 0; i < name.Length; ++i)
{
@@ -186,9 +196,12 @@ namespace Jellyfin.SocketSharp
public static string GetResponseContentType(IRequest httpReq)
{
var specifiedContentType = GetQueryStringContentType(httpReq);
- if (!string.IsNullOrEmpty(specifiedContentType)) return specifiedContentType;
+ if (!string.IsNullOrEmpty(specifiedContentType))
+ {
+ return specifiedContentType;
+ }
- var serverDefaultContentType = "application/json";
+ const string serverDefaultContentType = "application/json";
var acceptContentTypes = httpReq.AcceptTypes;
string defaultContentType = null;
@@ -198,7 +211,7 @@ namespace Jellyfin.SocketSharp
}
var acceptsAnything = false;
- var hasDefaultContentType = !string.IsNullOrEmpty(defaultContentType);
+ var hasDefaultContentType = defaultContentType != null;
if (acceptContentTypes != null)
{
foreach (var acceptsType in acceptContentTypes)
@@ -210,9 +223,13 @@ namespace Jellyfin.SocketSharp
if (acceptsAnything)
{
if (hasDefaultContentType)
+ {
return defaultContentType;
- if (serverDefaultContentType != null)
+ }
+ else if (serverDefaultContentType != null)
+ {
return serverDefaultContentType;
+ }
}
}
@@ -221,7 +238,7 @@ namespace Jellyfin.SocketSharp
return Soap11;
}
- //We could also send a '406 Not Acceptable', but this is allowed also
+ // We could also send a '406 Not Acceptable', but this is allowed also
return serverDefaultContentType;
}
@@ -229,11 +246,19 @@ namespace Jellyfin.SocketSharp
public static bool HasAnyOfContentTypes(IRequest request, params string[] contentTypes)
{
- if (contentTypes == null || request.ContentType == null) return false;
+ if (contentTypes == null || request.ContentType == null)
+ {
+ return false;
+ }
+
foreach (var contentType in contentTypes)
{
- if (IsContentType(request, contentType)) return true;
+ if (IsContentType(request, contentType))
+ {
+ return true;
+ }
}
+
return false;
}
@@ -253,10 +278,12 @@ namespace Jellyfin.SocketSharp
{
return null;
}
+
if (pi[0] == '/')
{
pi = pi.Substring(1);
}
+
format = LeftPart(pi, '/');
if (format.Length > formatMaxLength)
{
@@ -264,12 +291,12 @@ namespace Jellyfin.SocketSharp
}
}
- format = LeftPart(format, '.').ToLower();
+ format = LeftPart(format, '.');
if (format.Contains("json", StringComparison.OrdinalIgnoreCase))
{
return "application/json";
}
- if (format.Contains("xml", StringComparison.OrdinalIgnoreCase))
+ else if (format.Contains("xml", StringComparison.OrdinalIgnoreCase))
{
return "application/xml";
}
@@ -283,10 +310,9 @@ namespace Jellyfin.SocketSharp
{
return null;
}
- var pos = strVal.IndexOf(needle);
- return pos == -1
- ? strVal
- : strVal.Substring(0, pos);
+
+ var pos = strVal.IndexOf(needle, StringComparison.Ordinal);
+ return pos == -1 ? strVal : strVal.Substring(0, pos);
}
public static string HandlerFactoryPath;
@@ -329,7 +355,7 @@ namespace Jellyfin.SocketSharp
return pathInfo;
}
- //Wildcard mode relies on this to work out the handlerPath
+ // Wildcard mode relies on this to work out the handlerPath
pathInfo = ResolvePathInfoFromMappedPath(fullPath, appPath);
if (!string.IsNullOrEmpty(pathInfo))
{
@@ -371,6 +397,7 @@ namespace Jellyfin.SocketSharp
}
}
}
+
if (!pathRootFound)
{
return null;
@@ -433,6 +460,7 @@ namespace Jellyfin.SocketSharp
{
return null;
}
+
try
{
return Encoding.GetEncoding(param);
@@ -480,10 +508,10 @@ namespace Jellyfin.SocketSharp
public static string NormalizePathInfo(string pathInfo, string handlerPath)
{
- if (handlerPath != null && pathInfo.TrimStart('/').StartsWith(
- handlerPath, StringComparison.OrdinalIgnoreCase))
+ var trimmed = pathInfo.TrimStart('/');
+ if (handlerPath != null && trimmed.StartsWith(handlerPath, StringComparison.OrdinalIgnoreCase))
{
- return pathInfo.TrimStart('/').Substring(handlerPath.Length);
+ return trimmed.Substring(handlerPath.Length);
}
return pathInfo;
diff --git a/Jellyfin.Server/SocketSharp/WebSocketSharpResponse.cs b/Jellyfin.Server/SocketSharp/WebSocketSharpResponse.cs
index 21bfac55d..cabc96b23 100644
--- a/Jellyfin.Server/SocketSharp/WebSocketSharpResponse.cs
+++ b/Jellyfin.Server/SocketSharp/WebSocketSharpResponse.cs
@@ -14,7 +14,7 @@ using IHttpResponse = MediaBrowser.Model.Services.IHttpResponse;
using IRequest = MediaBrowser.Model.Services.IRequest;
-namespace Jellyfin.SocketSharp
+namespace Jellyfin.Server.SocketSharp
{
public class WebSocketSharpResponse : IHttpResponse
{
diff --git a/Jellyfin.Server/StartupOptions.cs b/Jellyfin.Server/StartupOptions.cs
new file mode 100644
index 000000000..5d3f7b171
--- /dev/null
+++ b/Jellyfin.Server/StartupOptions.cs
@@ -0,0 +1,44 @@
+using CommandLine;
+using Emby.Server.Implementations;
+
+namespace Jellyfin.Server
+{
+ /// <summary>
+ /// Class used by CommandLine package when parsing the command line arguments.
+ /// </summary>
+ public class StartupOptions : IStartupOptions
+ {
+ [Option('d', "datadir", Required = false, HelpText = "Path to use for the data folder (database files, etc.).")]
+ public string DataDir { get; set; }
+
+ [Option('C', "cachedir", Required = false, HelpText = "Path to use for caching.")]
+ public string CacheDir { get; set; }
+
+ [Option('c', "configdir", Required = false, HelpText = "Path to use for configuration data (user settings and pictures).")]
+ public string ConfigDir { get; set; }
+
+ [Option('l', "logdir", Required = false, HelpText = "Path to use for writing log files.")]
+ public string LogDir { get; set; }
+
+ [Option("ffmpeg", Required = false, HelpText = "Path to external FFmpeg executable to use in place of default found in PATH. Must be specified along with --ffprobe.")]
+ public string FFmpegPath { get; set; }
+
+ [Option("ffprobe", Required = false, HelpText = "Path to external FFprobe executable to use in place of default found in PATH. Must be specified along with --ffmpeg.")]
+ public string FFprobePath { get; set; }
+
+ [Option("service", Required = false, HelpText = "Run as headless service.")]
+ public bool IsService { get; set; }
+
+ [Option("noautorunwebapp", Required = false, HelpText = "Run headless if startup wizard is complete.")]
+ public bool NoAutoRunWebApp { get; set; }
+
+ [Option("package-name", Required = false, HelpText = "Used when packaging Jellyfin (example, synology).")]
+ public string PackageName { get; set; }
+
+ [Option("restartpath", Required = false, HelpText = "Path to restart script.")]
+ public string RestartPath { get; set; }
+
+ [Option("restartargs", Required = false, HelpText = "Arguments for restart script.")]
+ public string RestartArgs { get; set; }
+ }
+}
diff --git a/MediaBrowser.Api/ApiEntryPoint.cs b/MediaBrowser.Api/ApiEntryPoint.cs
index 763535129..8dbc26356 100644
--- a/MediaBrowser.Api/ApiEntryPoint.cs
+++ b/MediaBrowser.Api/ApiEntryPoint.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading;
@@ -17,7 +18,6 @@ using MediaBrowser.Model.Diagnostics;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Session;
-using MediaBrowser.Model.Threading;
using Microsoft.Extensions.Logging;
namespace MediaBrowser.Api
@@ -47,7 +47,6 @@ namespace MediaBrowser.Api
private readonly ISessionManager _sessionManager;
private readonly IFileSystem _fileSystem;
private readonly IMediaSourceManager _mediaSourceManager;
- public readonly ITimerFactory TimerFactory;
public readonly IProcessFactory ProcessFactory;
/// <summary>
@@ -58,6 +57,8 @@ namespace MediaBrowser.Api
private readonly Dictionary<string, SemaphoreSlim> _transcodingLocks =
new Dictionary<string, SemaphoreSlim>();
+ private bool _disposed = false;
+
/// <summary>
/// Initializes a new instance of the <see cref="ApiEntryPoint" /> class.
/// </summary>
@@ -66,20 +67,27 @@ namespace MediaBrowser.Api
/// <param name="config">The configuration.</param>
/// <param name="fileSystem">The file system.</param>
/// <param name="mediaSourceManager">The media source manager.</param>
- public ApiEntryPoint(ILogger logger, ISessionManager sessionManager, IServerConfigurationManager config, IFileSystem fileSystem, IMediaSourceManager mediaSourceManager, ITimerFactory timerFactory, IProcessFactory processFactory, IHttpResultFactory resultFactory)
+ public ApiEntryPoint(
+ ILogger logger,
+ ISessionManager sessionManager,
+ IServerConfigurationManager config,
+ IFileSystem fileSystem,
+ IMediaSourceManager mediaSourceManager,
+ IProcessFactory processFactory,
+ IHttpResultFactory resultFactory)
{
Logger = logger;
_sessionManager = sessionManager;
_config = config;
_fileSystem = fileSystem;
_mediaSourceManager = mediaSourceManager;
- TimerFactory = timerFactory;
ProcessFactory = processFactory;
ResultFactory = resultFactory;
- Instance = this;
_sessionManager.PlaybackProgress += _sessionManager_PlaybackProgress;
_sessionManager.PlaybackStart += _sessionManager_PlaybackStart;
+
+ Instance = this;
}
public static string[] Split(string value, char separator, bool removeEmpty)
@@ -130,7 +138,7 @@ namespace MediaBrowser.Api
/// <summary>
/// Runs this instance.
/// </summary>
- public void Run()
+ public Task RunAsync()
{
try
{
@@ -148,6 +156,8 @@ namespace MediaBrowser.Api
{
Logger.LogError(ex, "Error deleting encoded media cache");
}
+
+ return Task.CompletedTask;
}
public EncodingOptions GetEncodingOptions()
@@ -162,8 +172,7 @@ namespace MediaBrowser.Api
{
var path = _config.ApplicationPaths.TranscodingTempPath;
- foreach (var file in _fileSystem.GetFilePaths(path, true)
- .ToList())
+ foreach (var file in _fileSystem.GetFilePaths(path, true))
{
_fileSystem.DeleteFile(file);
}
@@ -184,17 +193,40 @@ namespace MediaBrowser.Api
/// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
protected virtual void Dispose(bool dispose)
{
- var list = _activeTranscodingJobs.ToList();
- var jobCount = list.Count;
+ if (_disposed)
+ {
+ return;
+ }
+
+ if (dispose)
+ {
+ // TODO: dispose
+ }
- Parallel.ForEach(list, j => KillTranscodingJob(j, false, path => true));
+ var jobs = _activeTranscodingJobs.ToList();
+ var jobCount = jobs.Count;
- // Try to allow for some time to kill the ffmpeg processes and delete the partial stream files
+ IEnumerable<Task> GetKillJobs()
+ {
+ foreach (var job in jobs)
+ {
+ yield return KillTranscodingJob(job, false, path => true);
+ }
+ }
+
+ // Wait for all processes to be killed
if (jobCount > 0)
{
- var task = Task.Delay(1000);
- Task.WaitAll(task);
+ Task.WaitAll(GetKillJobs().ToArray());
}
+
+ _activeTranscodingJobs.Clear();
+ _transcodingLocks.Clear();
+
+ _sessionManager.PlaybackProgress -= _sessionManager_PlaybackProgress;
+ _sessionManager.PlaybackStart -= _sessionManager_PlaybackStart;
+
+ _disposed = true;
}
@@ -211,19 +243,20 @@ namespace MediaBrowser.Api
/// <param name="state">The state.</param>
/// <param name="cancellationTokenSource">The cancellation token source.</param>
/// <returns>TranscodingJob.</returns>
- public TranscodingJob OnTranscodeBeginning(string path,
+ public TranscodingJob OnTranscodeBeginning(
+ string path,
string playSessionId,
string liveStreamId,
string transcodingJobId,
TranscodingJobType type,
- IProcess process,
+ Process process,
string deviceId,
StreamState state,
CancellationTokenSource cancellationTokenSource)
{
lock (_activeTranscodingJobs)
{
- var job = new TranscodingJob(Logger, TimerFactory)
+ var job = new TranscodingJob(Logger)
{
Type = type,
Path = path,
@@ -445,7 +478,7 @@ namespace MediaBrowser.Api
/// Called when [transcode kill timer stopped].
/// </summary>
/// <param name="state">The state.</param>
- private void OnTranscodeKillTimerStopped(object state)
+ private async void OnTranscodeKillTimerStopped(object state)
{
var job = (TranscodingJob)state;
@@ -462,7 +495,7 @@ namespace MediaBrowser.Api
Logger.LogInformation("Transcoding kill timer stopped for JobId {0} PlaySessionId {1}. Killing transcoding", job.Id, job.PlaySessionId);
- KillTranscodingJob(job, true, path => true);
+ await KillTranscodingJob(job, true, path => true);
}
/// <summary>
@@ -472,9 +505,9 @@ namespace MediaBrowser.Api
/// <param name="playSessionId">The play session identifier.</param>
/// <param name="deleteFiles">The delete files.</param>
/// <returns>Task.</returns>
- internal void KillTranscodingJobs(string deviceId, string playSessionId, Func<string, bool> deleteFiles)
+ internal Task KillTranscodingJobs(string deviceId, string playSessionId, Func<string, bool> deleteFiles)
{
- KillTranscodingJobs(j =>
+ return KillTranscodingJobs(j =>
{
if (!string.IsNullOrWhiteSpace(playSessionId))
{
@@ -492,7 +525,7 @@ namespace MediaBrowser.Api
/// <param name="killJob">The kill job.</param>
/// <param name="deleteFiles">The delete files.</param>
/// <returns>Task.</returns>
- private void KillTranscodingJobs(Func<TranscodingJob, bool> killJob, Func<string, bool> deleteFiles)
+ private Task KillTranscodingJobs(Func<TranscodingJob, bool> killJob, Func<string, bool> deleteFiles)
{
var jobs = new List<TranscodingJob>();
@@ -505,13 +538,18 @@ namespace MediaBrowser.Api
if (jobs.Count == 0)
{
- return;
+ return Task.CompletedTask;
}
- foreach (var job in jobs)
+ IEnumerable<Task> GetKillJobs()
{
- KillTranscodingJob(job, false, deleteFiles);
+ foreach (var job in jobs)
+ {
+ yield return KillTranscodingJob(job, false, deleteFiles);
+ }
}
+
+ return Task.WhenAll(GetKillJobs());
}
/// <summary>
@@ -520,7 +558,7 @@ namespace MediaBrowser.Api
/// <param name="job">The job.</param>
/// <param name="closeLiveStream">if set to <c>true</c> [close live stream].</param>
/// <param name="delete">The delete.</param>
- private async void KillTranscodingJob(TranscodingJob job, bool closeLiveStream, Func<string, bool> delete)
+ private async Task KillTranscodingJob(TranscodingJob job, bool closeLiveStream, Func<string, bool> delete)
{
job.DisposeKillTimer();
@@ -545,7 +583,7 @@ namespace MediaBrowser.Api
{
if (job.TranscodingThrottler != null)
{
- job.TranscodingThrottler.Stop();
+ job.TranscodingThrottler.Stop().GetAwaiter().GetResult();
}
var process = job.Process;
@@ -556,7 +594,7 @@ namespace MediaBrowser.Api
{
try
{
- Logger.LogInformation("Stopping ffmpeg process with q command for {path}", job.Path);
+ Logger.LogInformation("Stopping ffmpeg process with q command for {Path}", job.Path);
//process.Kill();
process.StandardInput.WriteLine("q");
@@ -564,20 +602,20 @@ namespace MediaBrowser.Api
// Need to wait because killing is asynchronous
if (!process.WaitForExit(5000))
{
- Logger.LogInformation("Killing ffmpeg process for {path}", job.Path);
+ Logger.LogInformation("Killing ffmpeg process for {Path}", job.Path);
process.Kill();
}
}
catch (Exception ex)
{
- Logger.LogError(ex, "Error killing transcoding job for {path}", job.Path);
+ Logger.LogError(ex, "Error killing transcoding job for {Path}", job.Path);
}
}
}
if (delete(job.Path))
{
- DeletePartialStreamFiles(job.Path, job.Type, 0, 1500);
+ await DeletePartialStreamFiles(job.Path, job.Type, 0, 1500).ConfigureAwait(false);
}
if (closeLiveStream && !string.IsNullOrWhiteSpace(job.LiveStreamId))
@@ -588,19 +626,19 @@ namespace MediaBrowser.Api
}
catch (Exception ex)
{
- Logger.LogError(ex, "Error closing live stream for {path}", job.Path);
+ Logger.LogError(ex, "Error closing live stream for {Path}", job.Path);
}
}
}
- private async void DeletePartialStreamFiles(string path, TranscodingJobType jobType, int retryCount, int delayMs)
+ private async Task DeletePartialStreamFiles(string path, TranscodingJobType jobType, int retryCount, int delayMs)
{
if (retryCount >= 10)
{
return;
}
- Logger.LogInformation("Deleting partial stream file(s) {0}", path);
+ Logger.LogInformation("Deleting partial stream file(s) {Path}", path);
await Task.Delay(delayMs).ConfigureAwait(false);
@@ -621,13 +659,13 @@ namespace MediaBrowser.Api
}
catch (IOException ex)
{
- Logger.LogError(ex, "Error deleting partial stream file(s) {path}", path);
+ Logger.LogError(ex, "Error deleting partial stream file(s) {Path}", path);
- DeletePartialStreamFiles(path, jobType, retryCount + 1, 500);
+ await DeletePartialStreamFiles(path, jobType, retryCount + 1, 500).ConfigureAwait(false);
}
catch (Exception ex)
{
- Logger.LogError(ex, "Error deleting partial stream file(s) {path}", path);
+ Logger.LogError(ex, "Error deleting partial stream file(s) {Path}", path);
}
}
@@ -650,8 +688,7 @@ namespace MediaBrowser.Api
var name = Path.GetFileNameWithoutExtension(outputFilePath);
var filesToDelete = _fileSystem.GetFilePaths(directory)
- .Where(f => f.IndexOf(name, StringComparison.OrdinalIgnoreCase) != -1)
- .ToList();
+ .Where(f => f.IndexOf(name, StringComparison.OrdinalIgnoreCase) != -1);
Exception e = null;
@@ -669,7 +706,7 @@ namespace MediaBrowser.Api
catch (IOException ex)
{
e = ex;
- Logger.LogError(ex, "Error deleting HLS file {path}", file);
+ Logger.LogError(ex, "Error deleting HLS file {Path}", file);
}
}
@@ -713,7 +750,7 @@ namespace MediaBrowser.Api
/// Gets or sets the process.
/// </summary>
/// <value>The process.</value>
- public IProcess Process { get; set; }
+ public Process Process { get; set; }
public ILogger Logger { get; private set; }
/// <summary>
/// Gets or sets the active request count.
@@ -724,9 +761,7 @@ namespace MediaBrowser.Api
/// Gets or sets the kill timer.
/// </summary>
/// <value>The kill timer.</value>
- private ITimer KillTimer { get; set; }
-
- private readonly ITimerFactory _timerFactory;
+ private Timer KillTimer { get; set; }
public string DeviceId { get; set; }
@@ -756,10 +791,9 @@ namespace MediaBrowser.Api
public DateTime LastPingDate { get; set; }
public int PingTimeout { get; set; }
- public TranscodingJob(ILogger logger, ITimerFactory timerFactory)
+ public TranscodingJob(ILogger logger)
{
Logger = logger;
- _timerFactory = timerFactory;
}
public void StopKillTimer()
@@ -802,7 +836,7 @@ namespace MediaBrowser.Api
if (KillTimer == null)
{
//Logger.LogDebug("Starting kill timer at {0}ms. JobId {1} PlaySessionId {2}", intervalMs, Id, PlaySessionId);
- KillTimer = _timerFactory.Create(callback, this, intervalMs, Timeout.Infinite);
+ KillTimer = new Timer(new TimerCallback(callback), this, intervalMs, Timeout.Infinite);
}
else
{
diff --git a/MediaBrowser.Api/BaseApiService.cs b/MediaBrowser.Api/BaseApiService.cs
index 8decea5a2..451ee72dd 100644
--- a/MediaBrowser.Api/BaseApiService.cs
+++ b/MediaBrowser.Api/BaseApiService.cs
@@ -43,7 +43,7 @@ namespace MediaBrowser.Api
public static string[] SplitValue(string value, char delim)
{
- if (string.IsNullOrWhiteSpace(value))
+ if (value == null)
{
return Array.Empty<string>();
}
@@ -53,8 +53,14 @@ namespace MediaBrowser.Api
public static Guid[] GetGuids(string value)
{
- // Unfortunately filtermenu.js was using |. This can be deprecated after a while.
- return (value ?? string.Empty).Split(new[] { ',', '|' }, StringSplitOptions.RemoveEmptyEntries).Select(i => new Guid(i)).ToArray();
+ if (value == null)
+ {
+ return Array.Empty<Guid>();
+ }
+
+ return value.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
+ .Select(i => new Guid(i))
+ .ToArray();
}
/// <summary>
@@ -118,7 +124,8 @@ namespace MediaBrowser.Api
options.Fields = hasFields.GetItemFields();
}
- if (!options.ContainsField(Model.Querying.ItemFields.RecursiveItemCount) || !options.ContainsField(Model.Querying.ItemFields.ChildCount))
+ if (!options.ContainsField(Model.Querying.ItemFields.RecursiveItemCount)
+ || !options.ContainsField(Model.Querying.ItemFields.ChildCount))
{
var client = authContext.GetAuthorizationInfo(Request).Client ?? string.Empty;
if (client.IndexOf("kodi", StringComparison.OrdinalIgnoreCase) != -1 ||
@@ -145,8 +152,7 @@ namespace MediaBrowser.Api
}
}
- var hasDtoOptions = request as IHasDtoOptions;
- if (hasDtoOptions != null)
+ if (request is IHasDtoOptions hasDtoOptions)
{
options.EnableImages = hasDtoOptions.EnableImages ?? true;
@@ -228,21 +234,6 @@ namespace MediaBrowser.Api
return libraryManager.GetMusicGenre(name);
}
- protected GameGenre GetGameGenre(string name, ILibraryManager libraryManager, DtoOptions dtoOptions)
- {
- if (name.IndexOf(BaseItem.SlugChar) != -1)
- {
- var result = GetItemFromSlugName<GameGenre>(libraryManager, name, dtoOptions);
-
- if (result != null)
- {
- return result;
- }
- }
-
- return libraryManager.GetGameGenre(name);
- }
-
protected Person GetPerson(string name, ILibraryManager libraryManager, DtoOptions dtoOptions)
{
if (name.IndexOf(BaseItem.SlugChar) != -1)
@@ -309,7 +300,7 @@ namespace MediaBrowser.Api
return pathInfo[index];
}
- private List<string> Parse(string pathUri)
+ private string[] Parse(string pathUri)
{
var actionParts = pathUri.Split(new[] { "://" }, StringSplitOptions.None);
@@ -323,7 +314,7 @@ namespace MediaBrowser.Api
var args = pathInfo.Split('/');
- return args.Skip(1).ToList();
+ return args.Skip(1).ToArray();
}
/// <summary>
@@ -349,10 +340,6 @@ namespace MediaBrowser.Api
{
item = GetMusicGenre(name, libraryManager, dtoOptions);
}
- else if (type.IndexOf("GameGenre", StringComparison.OrdinalIgnoreCase) == 0)
- {
- item = GetGameGenre(name, libraryManager, dtoOptions);
- }
else if (type.IndexOf("Studio", StringComparison.OrdinalIgnoreCase) == 0)
{
item = GetStudio(name, libraryManager, dtoOptions);
diff --git a/MediaBrowser.Api/FilterService.cs b/MediaBrowser.Api/FilterService.cs
index be80305f9..9caf07cea 100644
--- a/MediaBrowser.Api/FilterService.cs
+++ b/MediaBrowser.Api/FilterService.cs
@@ -143,16 +143,6 @@ namespace MediaBrowser.Api
}).ToArray();
}
- else if (string.Equals(request.IncludeItemTypes, "Game", StringComparison.OrdinalIgnoreCase) ||
- string.Equals(request.IncludeItemTypes, "GameSystem", StringComparison.OrdinalIgnoreCase))
- {
- filters.Genres = _libraryManager.GetGameGenres(genreQuery).Items.Select(i => new NameGuidPair
- {
- Name = i.Item1.Name,
- Id = i.Item1.Id
-
- }).ToArray();
- }
else
{
filters.Genres = _libraryManager.GetGenres(genreQuery).Items.Select(i => new NameGuidPair
diff --git a/MediaBrowser.Api/GamesService.cs b/MediaBrowser.Api/GamesService.cs
deleted file mode 100644
index bb908836c..000000000
--- a/MediaBrowser.Api/GamesService.cs
+++ /dev/null
@@ -1,140 +0,0 @@
-using System;
-using System.IO;
-using System.Linq;
-using MediaBrowser.Controller.Dto;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.Net;
-using MediaBrowser.Controller.Persistence;
-using MediaBrowser.Model.Dto;
-using MediaBrowser.Model.Services;
-
-namespace MediaBrowser.Api
-{
- /// <summary>
- /// Class GetGameSystemSummaries
- /// </summary>
- [Route("/Games/SystemSummaries", "GET", Summary = "Finds games similar to a given game.")]
- public class GetGameSystemSummaries : IReturn<GameSystemSummary[]>
- {
- /// <summary>
- /// Gets or sets the user id.
- /// </summary>
- /// <value>The user id.</value>
- [ApiMember(Name = "UserId", Description = "Optional. Filter by user id", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
- public Guid UserId { get; set; }
- }
-
- /// <summary>
- /// Class GamesService
- /// </summary>
- [Authenticated]
- public class GamesService : BaseApiService
- {
- /// <summary>
- /// The _user manager
- /// </summary>
- private readonly IUserManager _userManager;
-
- /// <summary>
- /// The _user data repository
- /// </summary>
- private readonly IUserDataManager _userDataRepository;
- /// <summary>
- /// The _library manager
- /// </summary>
- private readonly ILibraryManager _libraryManager;
-
- /// <summary>
- /// The _item repo
- /// </summary>
- private readonly IItemRepository _itemRepo;
- /// <summary>
- /// The _dto service
- /// </summary>
- private readonly IDtoService _dtoService;
-
- private readonly IAuthorizationContext _authContext;
-
- /// <summary>
- /// Initializes a new instance of the <see cref="GamesService" /> class.
- /// </summary>
- /// <param name="userManager">The user manager.</param>
- /// <param name="userDataRepository">The user data repository.</param>
- /// <param name="libraryManager">The library manager.</param>
- /// <param name="itemRepo">The item repo.</param>
- /// <param name="dtoService">The dto service.</param>
- public GamesService(IUserManager userManager, IUserDataManager userDataRepository, ILibraryManager libraryManager, IItemRepository itemRepo, IDtoService dtoService, IAuthorizationContext authContext)
- {
- _userManager = userManager;
- _userDataRepository = userDataRepository;
- _libraryManager = libraryManager;
- _itemRepo = itemRepo;
- _dtoService = dtoService;
- _authContext = authContext;
- }
-
- /// <summary>
- /// Gets the specified request.
- /// </summary>
- /// <param name="request">The request.</param>
- /// <returns>System.Object.</returns>
- public object Get(GetGameSystemSummaries request)
- {
- var user = request.UserId == null ? null : _userManager.GetUserById(request.UserId);
- var query = new InternalItemsQuery(user)
- {
- IncludeItemTypes = new[] { typeof(GameSystem).Name },
- DtoOptions = new DtoOptions(false)
- {
- EnableImages = false
- }
- };
-
- var result = _libraryManager.GetItemList(query)
- .Cast<GameSystem>()
- .Select(i => GetSummary(i, user))
- .ToArray();
-
- return ToOptimizedResult(result);
- }
-
- /// <summary>
- /// Gets the summary.
- /// </summary>
- /// <param name="system">The system.</param>
- /// <param name="user">The user.</param>
- /// <returns>GameSystemSummary.</returns>
- private GameSystemSummary GetSummary(GameSystem system, User user)
- {
- var summary = new GameSystemSummary
- {
- Name = system.GameSystemName,
- DisplayName = system.Name
- };
-
- var items = user == null ?
- system.GetRecursiveChildren(i => i is Game) :
- system.GetRecursiveChildren(user, new InternalItemsQuery(user)
- {
- IncludeItemTypes = new[] { typeof(Game).Name },
- DtoOptions = new DtoOptions(false)
- {
- EnableImages = false
- }
- });
-
- var games = items.Cast<Game>().ToArray();
-
- summary.ClientInstalledGameCount = games.Count(i => i.IsPlaceHolder);
-
- summary.GameCount = games.Length;
-
- summary.GameFileExtensions = games.Where(i => !i.IsPlaceHolder).Select(i => Path.GetExtension(i.Path))
- .Distinct(StringComparer.OrdinalIgnoreCase)
- .ToArray();
-
- return summary;
- }
- }
-}
diff --git a/MediaBrowser.Api/Images/ImageByNameService.cs b/MediaBrowser.Api/Images/ImageByNameService.cs
index fdf584277..922bd8ed6 100644
--- a/MediaBrowser.Api/Images/ImageByNameService.cs
+++ b/MediaBrowser.Api/Images/ImageByNameService.cs
@@ -145,7 +145,7 @@ namespace MediaBrowser.Api.Images
Theme = supportsThemes ? GetThemeName(i.FullName, path) : null,
Context = supportsThemes ? null : GetThemeName(i.FullName, path),
- Format = i.Extension.ToLower().TrimStart('.')
+ Format = i.Extension.ToLowerInvariant().TrimStart('.')
})
.OrderBy(i => i.Name)
.ToList();
diff --git a/MediaBrowser.Api/Images/ImageService.cs b/MediaBrowser.Api/Images/ImageService.cs
index 149e54f01..61db7b8d4 100644
--- a/MediaBrowser.Api/Images/ImageService.cs
+++ b/MediaBrowser.Api/Images/ImageService.cs
@@ -95,8 +95,6 @@ namespace MediaBrowser.Api.Images
[Route("/Artists/{Name}/Images/{Type}/{Index}", "GET")]
[Route("/Genres/{Name}/Images/{Type}", "GET")]
[Route("/Genres/{Name}/Images/{Type}/{Index}", "GET")]
- [Route("/GameGenres/{Name}/Images/{Type}", "GET")]
- [Route("/GameGenres/{Name}/Images/{Type}/{Index}", "GET")]
[Route("/MusicGenres/{Name}/Images/{Type}", "GET")]
[Route("/MusicGenres/{Name}/Images/{Type}/{Index}", "GET")]
[Route("/Persons/{Name}/Images/{Type}", "GET")]
@@ -109,8 +107,6 @@ namespace MediaBrowser.Api.Images
[Route("/Artists/{Name}/Images/{Type}/{Index}", "HEAD")]
[Route("/Genres/{Name}/Images/{Type}", "HEAD")]
[Route("/Genres/{Name}/Images/{Type}/{Index}", "HEAD")]
- [Route("/GameGenres/{Name}/Images/{Type}", "HEAD")]
- [Route("/GameGenres/{Name}/Images/{Type}/{Index}", "HEAD")]
[Route("/MusicGenres/{Name}/Images/{Type}", "HEAD")]
[Route("/MusicGenres/{Name}/Images/{Type}/{Index}", "HEAD")]
[Route("/Persons/{Name}/Images/{Type}", "HEAD")]
@@ -328,7 +324,7 @@ namespace MediaBrowser.Api.Images
var fileInfo = _fileSystem.GetFileInfo(info.Path);
length = fileInfo.Length;
- ImageDimensions size = _imageProcessor.GetImageSize(item, info, true);
+ ImageDimensions size = _imageProcessor.GetImageDimensions(item, info, true);
width = size.Width;
height = size.Height;
diff --git a/MediaBrowser.Api/ItemLookupService.cs b/MediaBrowser.Api/ItemLookupService.cs
index 0e7bdc086..f3ea7907f 100644
--- a/MediaBrowser.Api/ItemLookupService.cs
+++ b/MediaBrowser.Api/ItemLookupService.cs
@@ -57,12 +57,6 @@ namespace MediaBrowser.Api
{
}
- [Route("/Items/RemoteSearch/Game", "POST")]
- [Authenticated]
- public class GetGameRemoteSearchResults : RemoteSearchQuery<GameInfo>, IReturn<List<RemoteSearchResult>>
- {
- }
-
[Route("/Items/RemoteSearch/BoxSet", "POST")]
[Authenticated]
public class GetBoxSetRemoteSearchResults : RemoteSearchQuery<BoxSetInfo>, IReturn<List<RemoteSearchResult>>
@@ -173,13 +167,6 @@ namespace MediaBrowser.Api
return ToOptimizedResult(result);
}
- public async Task<object> Post(GetGameRemoteSearchResults request)
- {
- var result = await _providerManager.GetRemoteSearchResults<Game, GameInfo>(request, CancellationToken.None).ConfigureAwait(false);
-
- return ToOptimizedResult(result);
- }
-
public async Task<object> Post(GetBoxSetRemoteSearchResults request)
{
var result = await _providerManager.GetRemoteSearchResults<BoxSet, BoxSetInfo>(request, CancellationToken.None).ConfigureAwait(false);
diff --git a/MediaBrowser.Api/ItemUpdateService.cs b/MediaBrowser.Api/ItemUpdateService.cs
index c386b25b8..825732888 100644
--- a/MediaBrowser.Api/ItemUpdateService.cs
+++ b/MediaBrowser.Api/ItemUpdateService.cs
@@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
+using System.Threading.Tasks;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
@@ -60,15 +61,15 @@ namespace MediaBrowser.Api
_fileSystem = fileSystem;
}
- public object Get(GetMetadataEditorInfo request)
+ public async Task<object> Get(GetMetadataEditorInfo request)
{
var item = _libraryManager.GetItemById(request.ItemId);
var info = new MetadataEditorInfo
{
- ParentalRatingOptions = _localizationManager.GetParentalRatings(),
+ ParentalRatingOptions = _localizationManager.GetParentalRatings().ToArray(),
ExternalIdInfos = _providerManager.GetExternalIdInfos(item).ToArray(),
- Countries = _localizationManager.GetCountries(),
+ Countries = await _localizationManager.GetCountries(),
Cultures = _localizationManager.GetCultures()
};
@@ -154,11 +155,6 @@ namespace MediaBrowser.Api
Name = "Books",
Value = "books"
});
- list.Add(new NameValuePair
- {
- Name = "Games",
- Value = "games"
- });
}
list.Add(new NameValuePair
diff --git a/MediaBrowser.Api/Library/LibraryService.cs b/MediaBrowser.Api/Library/LibraryService.cs
index 12d807a7e..d44b07256 100644
--- a/MediaBrowser.Api/Library/LibraryService.cs
+++ b/MediaBrowser.Api/Library/LibraryService.cs
@@ -265,7 +265,6 @@ namespace MediaBrowser.Api.Library
public string Id { get; set; }
}
- [Route("/Games/{Id}/Similar", "GET", Summary = "Finds games similar to a given game.")]
[Route("/Artists/{Id}/Similar", "GET", Summary = "Finds albums similar to a given album.")]
[Route("/Items/{Id}/Similar", "GET", Summary = "Gets similar items")]
[Route("/Albums/{Id}/Similar", "GET", Summary = "Finds albums similar to a given album.")]
@@ -369,8 +368,6 @@ namespace MediaBrowser.Api.Library
return new string[] { "Series", "Season", "Episode" };
case CollectionType.Books:
return new string[] { "Book" };
- case CollectionType.Games:
- return new string[] { "Game", "GameSystem" };
case CollectionType.Music:
return new string[] { "MusicAlbum", "MusicArtist", "Audio", "MusicVideo" };
case CollectionType.HomeVideos:
@@ -554,7 +551,8 @@ namespace MediaBrowser.Api.Library
Name = i.Name,
DefaultEnabled = IsSaverEnabledByDefault(i.Name, types, isNewLibrary)
})
- .DistinctBy(i => i.Name, StringComparer.OrdinalIgnoreCase)
+ .GroupBy(i => i.Name, StringComparer.OrdinalIgnoreCase)
+ .Select(x => x.First())
.ToArray();
result.MetadataReaders = plugins
@@ -564,7 +562,8 @@ namespace MediaBrowser.Api.Library
Name = i.Name,
DefaultEnabled = true
})
- .DistinctBy(i => i.Name, StringComparer.OrdinalIgnoreCase)
+ .GroupBy(i => i.Name, StringComparer.OrdinalIgnoreCase)
+ .Select(x => x.First())
.ToArray();
result.SubtitleFetchers = plugins
@@ -574,7 +573,8 @@ namespace MediaBrowser.Api.Library
Name = i.Name,
DefaultEnabled = true
})
- .DistinctBy(i => i.Name, StringComparer.OrdinalIgnoreCase)
+ .GroupBy(i => i.Name, StringComparer.OrdinalIgnoreCase)
+ .Select(x => x.First())
.ToArray();
var typeOptions = new List<LibraryTypeOptions>();
@@ -596,7 +596,8 @@ namespace MediaBrowser.Api.Library
Name = i.Name,
DefaultEnabled = IsMetadataFetcherEnabledByDefault(i.Name, type, isNewLibrary)
})
- .DistinctBy(i => i.Name, StringComparer.OrdinalIgnoreCase)
+ .GroupBy(i => i.Name, StringComparer.OrdinalIgnoreCase)
+ .Select(x => x.First())
.ToArray(),
ImageFetchers = plugins
@@ -607,7 +608,8 @@ namespace MediaBrowser.Api.Library
Name = i.Name,
DefaultEnabled = IsImageFetcherEnabledByDefault(i.Name, type, isNewLibrary)
})
- .DistinctBy(i => i.Name, StringComparer.OrdinalIgnoreCase)
+ .GroupBy(i => i.Name, StringComparer.OrdinalIgnoreCase)
+ .Select(x => x.First())
.ToArray(),
SupportedImageTypes = plugins
@@ -952,8 +954,6 @@ namespace MediaBrowser.Api.Library
{
AlbumCount = GetCount(typeof(MusicAlbum), user, request),
EpisodeCount = GetCount(typeof(Episode), user, request),
- GameCount = GetCount(typeof(Game), user, request),
- GameSystemCount = GetCount(typeof(GameSystem), user, request),
MovieCount = GetCount(typeof(Movie), user, request),
SeriesCount = GetCount(typeof(Series), user, request),
SongCount = GetCount(typeof(Audio), user, request),
diff --git a/MediaBrowser.Api/LiveTv/LiveTvService.cs b/MediaBrowser.Api/LiveTv/LiveTvService.cs
index 88ed4b525..8fdd726b7 100644
--- a/MediaBrowser.Api/LiveTv/LiveTvService.cs
+++ b/MediaBrowser.Api/LiveTv/LiveTvService.cs
@@ -875,7 +875,9 @@ namespace MediaBrowser.Api.LiveTv
private string GetHashedString(string str)
{
// legacy
- return BitConverter.ToString(_cryptographyProvider.ComputeSHA1(Encoding.UTF8.GetBytes(str))).Replace("-", string.Empty).ToLower();
+ return BitConverter.ToString(
+ _cryptographyProvider.ComputeSHA1(Encoding.UTF8.GetBytes(str)))
+ .Replace("-", string.Empty).ToLowerInvariant();
}
public void Delete(DeleteListingProvider request)
diff --git a/MediaBrowser.Api/LocalizationService.cs b/MediaBrowser.Api/LocalizationService.cs
index 3b2e18852..eeff67e13 100644
--- a/MediaBrowser.Api/LocalizationService.cs
+++ b/MediaBrowser.Api/LocalizationService.cs
@@ -1,3 +1,4 @@
+using System.Threading.Tasks;
using MediaBrowser.Controller.Net;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Globalization;
@@ -81,9 +82,9 @@ namespace MediaBrowser.Api
/// </summary>
/// <param name="request">The request.</param>
/// <returns>System.Object.</returns>
- public object Get(GetCountries request)
+ public async Task<object> Get(GetCountries request)
{
- var result = _localization.GetCountries();
+ var result = await _localization.GetCountries();
return ToOptimizedResult(result);
}
diff --git a/MediaBrowser.Api/Movies/MoviesService.cs b/MediaBrowser.Api/Movies/MoviesService.cs
index 996087018..91766255f 100644
--- a/MediaBrowser.Api/Movies/MoviesService.cs
+++ b/MediaBrowser.Api/Movies/MoviesService.cs
@@ -268,7 +268,8 @@ namespace MediaBrowser.Api.Movies
EnableGroupByMetadataKey = true,
DtoOptions = dtoOptions
- }).DistinctBy(i => i.GetProviderId(MetadataProviders.Imdb) ?? Guid.NewGuid().ToString("N"))
+ }).GroupBy(i => i.GetProviderId(MetadataProviders.Imdb) ?? Guid.NewGuid().ToString("N"))
+ .Select(x => x.First())
.Take(itemLimit)
.ToList();
@@ -308,7 +309,8 @@ namespace MediaBrowser.Api.Movies
EnableGroupByMetadataKey = true,
DtoOptions = dtoOptions
- }).DistinctBy(i => i.GetProviderId(MetadataProviders.Imdb) ?? Guid.NewGuid().ToString("N"))
+ }).GroupBy(i => i.GetProviderId(MetadataProviders.Imdb) ?? Guid.NewGuid().ToString("N"))
+ .Select(x => x.First())
.Take(itemLimit)
.ToList();
diff --git a/MediaBrowser.Api/PackageService.cs b/MediaBrowser.Api/PackageService.cs
index 16819ee37..fbb876dea 100644
--- a/MediaBrowser.Api/PackageService.cs
+++ b/MediaBrowser.Api/PackageService.cs
@@ -197,7 +197,7 @@ namespace MediaBrowser.Api
throw new ResourceNotFoundException(string.Format("Package not found: {0}", request.Name));
}
- Task.Run(() => _installationManager.InstallPackage(package, true, new SimpleProgress<double>(), CancellationToken.None));
+ await _installationManager.InstallPackage(package, true, new SimpleProgress<double>(), CancellationToken.None);
}
/// <summary>
diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs
index 4ed83baad..073686298 100644
--- a/MediaBrowser.Api/Playback/BaseStreamingService.cs
+++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
@@ -68,10 +69,8 @@ namespace MediaBrowser.Api.Playback
protected IDeviceManager DeviceManager { get; private set; }
protected ISubtitleEncoder SubtitleEncoder { get; private set; }
protected IMediaSourceManager MediaSourceManager { get; private set; }
- protected IZipClient ZipClient { get; private set; }
protected IJsonSerializer JsonSerializer { get; private set; }
- public static IServerApplicationHost AppHost;
public static IHttpClient HttpClient;
protected IAuthorizationContext AuthorizationContext { get; private set; }
@@ -80,21 +79,33 @@ namespace MediaBrowser.Api.Playback
/// <summary>
/// Initializes a new instance of the <see cref="BaseStreamingService" /> class.
/// </summary>
- protected BaseStreamingService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IJsonSerializer jsonSerializer, IAuthorizationContext authorizationContext)
+ protected BaseStreamingService(
+ IServerConfigurationManager serverConfig,
+ IUserManager userManager,
+ ILibraryManager libraryManager,
+ IIsoManager isoManager,
+ IMediaEncoder mediaEncoder,
+ IFileSystem fileSystem,
+ IDlnaManager dlnaManager,
+ ISubtitleEncoder subtitleEncoder,
+ IDeviceManager deviceManager,
+ IMediaSourceManager mediaSourceManager,
+ IJsonSerializer jsonSerializer,
+ IAuthorizationContext authorizationContext)
{
- JsonSerializer = jsonSerializer;
- AuthorizationContext = authorizationContext;
- ZipClient = zipClient;
- MediaSourceManager = mediaSourceManager;
- DeviceManager = deviceManager;
- SubtitleEncoder = subtitleEncoder;
- DlnaManager = dlnaManager;
- FileSystem = fileSystem;
ServerConfigurationManager = serverConfig;
UserManager = userManager;
LibraryManager = libraryManager;
IsoManager = isoManager;
MediaEncoder = mediaEncoder;
+ FileSystem = fileSystem;
+ DlnaManager = dlnaManager;
+ SubtitleEncoder = subtitleEncoder;
+ DeviceManager = deviceManager;
+ MediaSourceManager = mediaSourceManager;
+ JsonSerializer = jsonSerializer;
+ AuthorizationContext = authorizationContext;
+
EncodingHelper = new EncodingHelper(MediaEncoder, FileSystem, SubtitleEncoder);
}
@@ -135,10 +146,10 @@ namespace MediaBrowser.Api.Playback
if (EnableOutputInSubFolder)
{
- return Path.Combine(folder, dataHash, dataHash + (outputFileExtension ?? string.Empty).ToLower());
+ return Path.Combine(folder, dataHash, dataHash + (outputFileExtension ?? string.Empty).ToLowerInvariant());
}
- return Path.Combine(folder, dataHash + (outputFileExtension ?? string.Empty).ToLower());
+ return Path.Combine(folder, dataHash + (outputFileExtension ?? string.Empty).ToLowerInvariant());
}
protected virtual bool EnableOutputInSubFolder => false;
@@ -187,7 +198,8 @@ namespace MediaBrowser.Api.Playback
/// <param name="cancellationTokenSource">The cancellation token source.</param>
/// <param name="workingDirectory">The working directory.</param>
/// <returns>Task.</returns>
- protected async Task<TranscodingJob> StartFfMpeg(StreamState state,
+ protected async Task<TranscodingJob> StartFfMpeg(
+ StreamState state,
string outputPath,
CancellationTokenSource cancellationTokenSource,
string workingDirectory = null)
@@ -215,24 +227,27 @@ namespace MediaBrowser.Api.Playback
var transcodingId = Guid.NewGuid().ToString("N");
var commandLineArgs = GetCommandLineArguments(outputPath, encodingOptions, state, true);
- var process = ApiEntryPoint.Instance.ProcessFactory.Create(new ProcessOptions
+ var process = new Process()
{
- CreateNoWindow = true,
- UseShellExecute = false,
-
- // Must consume both stdout and stderr or deadlocks may occur
- //RedirectStandardOutput = true,
- RedirectStandardError = true,
- RedirectStandardInput = true,
-
- FileName = MediaEncoder.EncoderPath,
- Arguments = commandLineArgs,
-
- IsHidden = true,
- ErrorDialog = false,
- EnableRaisingEvents = true,
- WorkingDirectory = !string.IsNullOrWhiteSpace(workingDirectory) ? workingDirectory : null
- });
+ StartInfo = new ProcessStartInfo()
+ {
+ WindowStyle = ProcessWindowStyle.Hidden,
+ CreateNoWindow = true,
+ UseShellExecute = false,
+
+ // Must consume both stdout and stderr or deadlocks may occur
+ //RedirectStandardOutput = true,
+ RedirectStandardError = true,
+ RedirectStandardInput = true,
+
+ FileName = MediaEncoder.EncoderPath,
+ Arguments = commandLineArgs,
+ WorkingDirectory = string.IsNullOrWhiteSpace(workingDirectory) ? null : workingDirectory,
+
+ ErrorDialog = false
+ },
+ EnableRaisingEvents = true
+ };
var transcodingJob = ApiEntryPoint.Instance.OnTranscodeBeginning(outputPath,
state.Request.PlaySessionId,
@@ -248,13 +263,17 @@ namespace MediaBrowser.Api.Playback
Logger.LogInformation(commandLineLogMessage);
var logFilePrefix = "ffmpeg-transcode";
- if (state.VideoRequest != null && string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase) && string.Equals(state.OutputAudioCodec, "copy", StringComparison.OrdinalIgnoreCase))
- {
- logFilePrefix = "ffmpeg-directstream";
- }
- else if (state.VideoRequest != null && string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase))
+ if (state.VideoRequest != null)
{
- logFilePrefix = "ffmpeg-remux";
+ if (string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase)
+ && string.Equals(state.OutputAudioCodec, "copy", StringComparison.OrdinalIgnoreCase))
+ {
+ logFilePrefix = "ffmpeg-directstream";
+ }
+ else if (string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase))
+ {
+ logFilePrefix = "ffmpeg-remux";
+ }
}
var logFilePath = Path.Combine(ServerConfigurationManager.ApplicationPaths.LogDirectoryPath, logFilePrefix + "-" + Guid.NewGuid() + ".txt");
@@ -317,7 +336,7 @@ namespace MediaBrowser.Api.Playback
{
if (EnableThrottling(state))
{
- transcodingJob.TranscodingThrottler = state.TranscodingThrottler = new TranscodingThrottler(transcodingJob, Logger, ServerConfigurationManager, ApiEntryPoint.Instance.TimerFactory, FileSystem);
+ transcodingJob.TranscodingThrottler = state.TranscodingThrottler = new TranscodingThrottler(transcodingJob, Logger, ServerConfigurationManager, FileSystem);
state.TranscodingThrottler.Start();
}
}
@@ -341,7 +360,7 @@ namespace MediaBrowser.Api.Playback
/// <param name="process">The process.</param>
/// <param name="job">The job.</param>
/// <param name="state">The state.</param>
- private void OnFfMpegProcessExited(IProcess process, TranscodingJob job, StreamState state)
+ private void OnFfMpegProcessExited(Process process, TranscodingJob job, StreamState state)
{
if (job != null)
{
diff --git a/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs b/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs
index 08a2183f8..1acc42ea5 100644
--- a/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs
+++ b/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs
@@ -55,17 +55,6 @@ namespace MediaBrowser.Api.Playback.Hls
protected override TranscodingJobType TranscodingJobType => TranscodingJobType.Hls;
/// <summary>
- /// Processes the request.
- /// </summary>
- /// <param name="request">The request.</param>
- /// <param name="isLive">if set to <c>true</c> [is live].</param>
- /// <returns>System.Object.</returns>
- protected async Task<object> ProcessRequest(StreamRequest request, bool isLive)
- {
- return await ProcessRequestAsync(request, isLive).ConfigureAwait(false);
- }
-
- /// <summary>
/// Processes the request async.
/// </summary>
/// <param name="request">The request.</param>
@@ -74,7 +63,7 @@ namespace MediaBrowser.Api.Playback.Hls
/// <exception cref="ArgumentException">A video bitrate is required
/// or
/// An audio bitrate is required</exception>
- private async Task<object> ProcessRequestAsync(StreamRequest request, bool isLive)
+ protected async Task<object> ProcessRequestAsync(StreamRequest request, bool isLive)
{
var cancellationTokenSource = new CancellationTokenSource();
@@ -324,7 +313,31 @@ namespace MediaBrowser.Api.Playback.Hls
return 0;
}
- public BaseHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IJsonSerializer jsonSerializer, IAuthorizationContext authorizationContext) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient, jsonSerializer, authorizationContext)
+ public BaseHlsService(
+ IServerConfigurationManager serverConfig,
+ IUserManager userManager,
+ ILibraryManager libraryManager,
+ IIsoManager isoManager,
+ IMediaEncoder mediaEncoder,
+ IFileSystem fileSystem,
+ IDlnaManager dlnaManager,
+ ISubtitleEncoder subtitleEncoder,
+ IDeviceManager deviceManager,
+ IMediaSourceManager mediaSourceManager,
+ IJsonSerializer jsonSerializer,
+ IAuthorizationContext authorizationContext)
+ : base(serverConfig,
+ userManager,
+ libraryManager,
+ isoManager,
+ mediaEncoder,
+ fileSystem,
+ dlnaManager,
+ subtitleEncoder,
+ deviceManager,
+ mediaSourceManager,
+ jsonSerializer,
+ authorizationContext)
{
}
}
diff --git a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs
index 30696ec97..45f003cae 100644
--- a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs
+++ b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs
@@ -95,7 +95,32 @@ namespace MediaBrowser.Api.Playback.Hls
public class DynamicHlsService : BaseHlsService
{
- public DynamicHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IJsonSerializer jsonSerializer, IAuthorizationContext authorizationContext, INetworkManager networkManager) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient, jsonSerializer, authorizationContext)
+ public DynamicHlsService(
+ IServerConfigurationManager serverConfig,
+ IUserManager userManager,
+ ILibraryManager libraryManager,
+ IIsoManager isoManager,
+ IMediaEncoder mediaEncoder,
+ IFileSystem fileSystem,
+ IDlnaManager dlnaManager,
+ ISubtitleEncoder subtitleEncoder,
+ IDeviceManager deviceManager,
+ IMediaSourceManager mediaSourceManager,
+ IJsonSerializer jsonSerializer,
+ IAuthorizationContext authorizationContext,
+ INetworkManager networkManager)
+ : base(serverConfig,
+ userManager,
+ libraryManager,
+ isoManager,
+ mediaEncoder,
+ fileSystem,
+ dlnaManager,
+ subtitleEncoder,
+ deviceManager,
+ mediaSourceManager,
+ jsonSerializer,
+ authorizationContext)
{
NetworkManager = networkManager;
}
@@ -209,7 +234,7 @@ namespace MediaBrowser.Api.Playback.Hls
// If the playlist doesn't already exist, startup ffmpeg
try
{
- ApiEntryPoint.Instance.KillTranscodingJobs(request.DeviceId, request.PlaySessionId, p => false);
+ await ApiEntryPoint.Instance.KillTranscodingJobs(request.DeviceId, request.PlaySessionId, p => false);
if (currentTranscodingIndex.HasValue)
{
@@ -233,7 +258,7 @@ namespace MediaBrowser.Api.Playback.Hls
job = ApiEntryPoint.Instance.OnTranscodeBeginRequest(playlistPath, TranscodingJobType);
if (job.TranscodingThrottler != null)
{
- job.TranscodingThrottler.UnpauseTranscoding();
+ await job.TranscodingThrottler.UnpauseTranscoding();
}
}
}
diff --git a/MediaBrowser.Api/Playback/Hls/HlsSegmentService.cs b/MediaBrowser.Api/Playback/Hls/HlsSegmentService.cs
index 02b837912..6a2c7ae03 100644
--- a/MediaBrowser.Api/Playback/Hls/HlsSegmentService.cs
+++ b/MediaBrowser.Api/Playback/Hls/HlsSegmentService.cs
@@ -102,9 +102,9 @@ namespace MediaBrowser.Api.Playback.Hls
return GetFileResult(file, file);
}
- public void Delete(StopEncodingProcess request)
+ public Task Delete(StopEncodingProcess request)
{
- ApiEntryPoint.Instance.KillTranscodingJobs(request.DeviceId, request.PlaySessionId, path => true);
+ return ApiEntryPoint.Instance.KillTranscodingJobs(request.DeviceId, request.PlaySessionId, path => true);
}
/// <summary>
diff --git a/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs b/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs
index 142dc2dfd..eb1bbfb74 100644
--- a/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs
+++ b/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs
@@ -1,4 +1,5 @@
using System;
+using System.Threading.Tasks;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Devices;
using MediaBrowser.Controller.Dlna;
@@ -24,9 +25,9 @@ namespace MediaBrowser.Api.Playback.Hls
[Authenticated]
public class VideoHlsService : BaseHlsService
{
- public object Get(GetLiveHlsStream request)
+ public Task<object> Get(GetLiveHlsStream request)
{
- return ProcessRequest(request, true);
+ return ProcessRequestAsync(request, true);
}
/// <summary>
@@ -130,7 +131,31 @@ namespace MediaBrowser.Api.Playback.Hls
return args;
}
- public VideoHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IJsonSerializer jsonSerializer, IAuthorizationContext authorizationContext) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient, jsonSerializer, authorizationContext)
+ public VideoHlsService(
+ IServerConfigurationManager serverConfig,
+ IUserManager userManager,
+ ILibraryManager libraryManager,
+ IIsoManager isoManager,
+ IMediaEncoder mediaEncoder,
+ IFileSystem fileSystem,
+ IDlnaManager dlnaManager,
+ ISubtitleEncoder subtitleEncoder,
+ IDeviceManager deviceManager,
+ IMediaSourceManager mediaSourceManager,
+ IJsonSerializer jsonSerializer,
+ IAuthorizationContext authorizationContext)
+ : base(serverConfig,
+ userManager,
+ libraryManager,
+ isoManager,
+ mediaEncoder,
+ fileSystem,
+ dlnaManager,
+ subtitleEncoder,
+ deviceManager,
+ mediaSourceManager,
+ jsonSerializer,
+ authorizationContext)
{
}
}
diff --git a/MediaBrowser.Api/Playback/Progressive/AudioService.cs b/MediaBrowser.Api/Playback/Progressive/AudioService.cs
index 150571ce9..208a5560d 100644
--- a/MediaBrowser.Api/Playback/Progressive/AudioService.cs
+++ b/MediaBrowser.Api/Playback/Progressive/AudioService.cs
@@ -32,7 +32,33 @@ namespace MediaBrowser.Api.Playback.Progressive
//[Authenticated]
public class AudioService : BaseProgressiveStreamingService
{
- public AudioService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IJsonSerializer jsonSerializer, IAuthorizationContext authorizationContext, IImageProcessor imageProcessor, IEnvironmentInfo environmentInfo) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient, jsonSerializer, authorizationContext, imageProcessor, environmentInfo)
+ public AudioService(
+ IServerConfigurationManager serverConfig,
+ IUserManager userManager,
+ ILibraryManager libraryManager,
+ IIsoManager isoManager,
+ IMediaEncoder mediaEncoder,
+ IFileSystem fileSystem,
+ IDlnaManager dlnaManager,
+ ISubtitleEncoder subtitleEncoder,
+ IDeviceManager deviceManager,
+ IMediaSourceManager mediaSourceManager,
+ IJsonSerializer jsonSerializer,
+ IAuthorizationContext authorizationContext,
+ IEnvironmentInfo environmentInfo)
+ : base(serverConfig,
+ userManager,
+ libraryManager,
+ isoManager,
+ mediaEncoder,
+ fileSystem,
+ dlnaManager,
+ subtitleEncoder,
+ deviceManager,
+ mediaSourceManager,
+ jsonSerializer,
+ authorizationContext,
+ environmentInfo)
{
}
diff --git a/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs b/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs
index 621d1ff88..c197de173 100644
--- a/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs
+++ b/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs
@@ -25,12 +25,35 @@ namespace MediaBrowser.Api.Playback.Progressive
/// </summary>
public abstract class BaseProgressiveStreamingService : BaseStreamingService
{
- protected readonly IImageProcessor ImageProcessor;
protected readonly IEnvironmentInfo EnvironmentInfo;
- public BaseProgressiveStreamingService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IJsonSerializer jsonSerializer, IAuthorizationContext authorizationContext, IImageProcessor imageProcessor, IEnvironmentInfo environmentInfo) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient, jsonSerializer, authorizationContext)
+ public BaseProgressiveStreamingService(
+ IServerConfigurationManager serverConfig,
+ IUserManager userManager,
+ ILibraryManager libraryManager,
+ IIsoManager isoManager,
+ IMediaEncoder mediaEncoder,
+ IFileSystem fileSystem,
+ IDlnaManager dlnaManager,
+ ISubtitleEncoder subtitleEncoder,
+ IDeviceManager deviceManager,
+ IMediaSourceManager mediaSourceManager,
+ IJsonSerializer jsonSerializer,
+ IAuthorizationContext authorizationContext,
+ IEnvironmentInfo environmentInfo)
+ : base(serverConfig,
+ userManager,
+ libraryManager,
+ isoManager,
+ mediaEncoder,
+ fileSystem,
+ dlnaManager,
+ subtitleEncoder,
+ deviceManager,
+ mediaSourceManager,
+ jsonSerializer,
+ authorizationContext)
{
- ImageProcessor = imageProcessor;
EnvironmentInfo = environmentInfo;
}
diff --git a/MediaBrowser.Api/Playback/Progressive/VideoService.cs b/MediaBrowser.Api/Playback/Progressive/VideoService.cs
index 00b79ccdd..a0ea5c62d 100644
--- a/MediaBrowser.Api/Playback/Progressive/VideoService.cs
+++ b/MediaBrowser.Api/Playback/Progressive/VideoService.cs
@@ -68,7 +68,33 @@ namespace MediaBrowser.Api.Playback.Progressive
//[Authenticated]
public class VideoService : BaseProgressiveStreamingService
{
- public VideoService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IJsonSerializer jsonSerializer, IAuthorizationContext authorizationContext, IImageProcessor imageProcessor, IEnvironmentInfo environmentInfo) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient, jsonSerializer, authorizationContext, imageProcessor, environmentInfo)
+ public VideoService(
+ IServerConfigurationManager serverConfig,
+ IUserManager userManager,
+ ILibraryManager libraryManager,
+ IIsoManager isoManager,
+ IMediaEncoder mediaEncoder,
+ IFileSystem fileSystem,
+ IDlnaManager dlnaManager,
+ ISubtitleEncoder subtitleEncoder,
+ IDeviceManager deviceManager,
+ IMediaSourceManager mediaSourceManager,
+ IJsonSerializer jsonSerializer,
+ IAuthorizationContext authorizationContext,
+ IEnvironmentInfo environmentInfo)
+ : base(serverConfig,
+ userManager,
+ libraryManager,
+ isoManager,
+ mediaEncoder,
+ fileSystem,
+ dlnaManager,
+ subtitleEncoder,
+ deviceManager,
+ mediaSourceManager,
+ jsonSerializer,
+ authorizationContext,
+ environmentInfo)
{
}
diff --git a/MediaBrowser.Api/Playback/TranscodingThrottler.cs b/MediaBrowser.Api/Playback/TranscodingThrottler.cs
index 97f21c8f3..0e73d77ef 100644
--- a/MediaBrowser.Api/Playback/TranscodingThrottler.cs
+++ b/MediaBrowser.Api/Playback/TranscodingThrottler.cs
@@ -1,8 +1,9 @@
using System;
+using System.Threading;
+using System.Threading.Tasks;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.IO;
-using MediaBrowser.Model.Threading;
using Microsoft.Extensions.Logging;
namespace MediaBrowser.Api.Playback
@@ -11,18 +12,16 @@ namespace MediaBrowser.Api.Playback
{
private readonly TranscodingJob _job;
private readonly ILogger _logger;
- private ITimer _timer;
+ private Timer _timer;
private bool _isPaused;
private readonly IConfigurationManager _config;
- private readonly ITimerFactory _timerFactory;
private readonly IFileSystem _fileSystem;
- public TranscodingThrottler(TranscodingJob job, ILogger logger, IConfigurationManager config, ITimerFactory timerFactory, IFileSystem fileSystem)
+ public TranscodingThrottler(TranscodingJob job, ILogger logger, IConfigurationManager config, IFileSystem fileSystem)
{
_job = job;
_logger = logger;
_config = config;
- _timerFactory = timerFactory;
_fileSystem = fileSystem;
}
@@ -33,10 +32,10 @@ namespace MediaBrowser.Api.Playback
public void Start()
{
- _timer = _timerFactory.Create(TimerCallback, null, 5000, 5000);
+ _timer = new Timer(TimerCallback, null, 5000, 5000);
}
- private void TimerCallback(object state)
+ private async void TimerCallback(object state)
{
if (_job.HasExited)
{
@@ -48,15 +47,15 @@ namespace MediaBrowser.Api.Playback
if (options.EnableThrottling && IsThrottleAllowed(_job, options.ThrottleDelaySeconds))
{
- PauseTranscoding();
+ await PauseTranscoding();
}
else
{
- UnpauseTranscoding();
+ await UnpauseTranscoding();
}
}
- private void PauseTranscoding()
+ private async Task PauseTranscoding()
{
if (!_isPaused)
{
@@ -64,7 +63,7 @@ namespace MediaBrowser.Api.Playback
try
{
- _job.Process.StandardInput.Write("c");
+ await _job.Process.StandardInput.WriteAsync("c");
_isPaused = true;
}
catch (Exception ex)
@@ -74,7 +73,7 @@ namespace MediaBrowser.Api.Playback
}
}
- public void UnpauseTranscoding()
+ public async Task UnpauseTranscoding()
{
if (_isPaused)
{
@@ -82,7 +81,7 @@ namespace MediaBrowser.Api.Playback
try
{
- _job.Process.StandardInput.WriteLine();
+ await _job.Process.StandardInput.WriteLineAsync();
_isPaused = false;
}
catch (Exception ex)
@@ -153,10 +152,10 @@ namespace MediaBrowser.Api.Playback
return false;
}
- public void Stop()
+ public async Task Stop()
{
DisposeTimer();
- UnpauseTranscoding();
+ await UnpauseTranscoding();
}
public void Dispose()
diff --git a/MediaBrowser.Api/Playback/UniversalAudioService.cs b/MediaBrowser.Api/Playback/UniversalAudioService.cs
index 1aa77792c..e07770a4c 100644
--- a/MediaBrowser.Api/Playback/UniversalAudioService.cs
+++ b/MediaBrowser.Api/Playback/UniversalAudioService.cs
@@ -287,7 +287,6 @@ namespace MediaBrowser.Api.Playback
SubtitleEncoder,
DeviceManager,
MediaSourceManager,
- ZipClient,
JsonSerializer,
AuthorizationContext,
NetworkManager)
@@ -334,10 +333,8 @@ namespace MediaBrowser.Api.Playback
SubtitleEncoder,
DeviceManager,
MediaSourceManager,
- ZipClient,
JsonSerializer,
AuthorizationContext,
- ImageProcessor,
EnvironmentInfo)
{
Request = Request
diff --git a/MediaBrowser.Api/Session/SessionsService.cs b/MediaBrowser.Api/Session/SessionsService.cs
index c9a11c117..f011e6e41 100644
--- a/MediaBrowser.Api/Session/SessionsService.cs
+++ b/MediaBrowser.Api/Session/SessionsService.cs
@@ -194,7 +194,7 @@ namespace MediaBrowser.Api.Session
[ApiMember(Name = "Id", Description = "Session Id", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST")]
public string Id { get; set; }
- [ApiMember(Name = "PlayableMediaTypes", Description = "A list of playable media types, comma delimited. Audio, Video, Book, Game, Photo.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")]
+ [ApiMember(Name = "PlayableMediaTypes", Description = "A list of playable media types, comma delimited. Audio, Video, Book, Photo.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")]
public string PlayableMediaTypes { get; set; }
[ApiMember(Name = "SupportedCommands", Description = "A list of supported remote control commands, comma delimited", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")]
diff --git a/MediaBrowser.Api/StartupWizardService.cs b/MediaBrowser.Api/StartupWizardService.cs
index 3d59b4c9a..53ba7eefd 100644
--- a/MediaBrowser.Api/StartupWizardService.cs
+++ b/MediaBrowser.Api/StartupWizardService.cs
@@ -3,7 +3,6 @@ using System.Threading.Tasks;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller;
using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Connect;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.Controller.Net;
@@ -39,7 +38,7 @@ namespace MediaBrowser.Api
}
[Route("/Startup/User", "POST", Summary = "Updates initial user info", IsHidden = true)]
- public class UpdateStartupUser : StartupUser, IReturn<UpdateStartupUserResult>
+ public class UpdateStartupUser : StartupUser
{
}
@@ -102,12 +101,11 @@ namespace MediaBrowser.Api
return new StartupUser
{
Name = user.Name,
- ConnectUserName = user.ConnectUserName,
Password = user.Password
};
}
- public async Task<object> Post(UpdateStartupUser request)
+ public async Task Post(UpdateStartupUser request)
{
var user = _userManager.Users.First();
@@ -118,10 +116,6 @@ namespace MediaBrowser.Api
if (!string.IsNullOrEmpty(request.Password)) {
await _userManager.ChangePassword(user, request.Password).ConfigureAwait(false);
}
-
- var result = new UpdateStartupUserResult();
-
- return result;
}
}
@@ -135,12 +129,6 @@ namespace MediaBrowser.Api
public class StartupUser
{
public string Name { get; set; }
- public string ConnectUserName { get; set; }
public string Password { get; set; }
}
-
- public class UpdateStartupUserResult
- {
- public UserLinkResult UserLinkResult { get; set; }
- }
}
diff --git a/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs b/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs
index 6e577c53e..471b41127 100644
--- a/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs
+++ b/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs
@@ -224,7 +224,6 @@ namespace MediaBrowser.Api.UserLibrary
dto.TrailerCount = counts.TrailerCount;
dto.AlbumCount = counts.AlbumCount;
dto.SongCount = counts.SongCount;
- dto.GameCount = counts.GameCount;
dto.ArtistCount = counts.ArtistCount;
}
diff --git a/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs b/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs
index 4cccc0cb5..7af50c329 100644
--- a/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs
+++ b/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs
@@ -42,12 +42,6 @@ namespace MediaBrowser.Api.UserLibrary
[ApiMember(Name = "MinIndexNumber", Description = "Optional filter by minimum index number.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
public int? MinIndexNumber { get; set; }
- [ApiMember(Name = "MinPlayers", Description = "Optional filter by minimum number of game players.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
- public int? MinPlayers { get; set; }
-
- [ApiMember(Name = "MaxPlayers", Description = "Optional filter by maximum number of game players.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
- public int? MaxPlayers { get; set; }
-
[ApiMember(Name = "ParentIndexNumber", Description = "Optional filter by parent index number.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
public int? ParentIndexNumber { get; set; }
diff --git a/MediaBrowser.Api/UserLibrary/GameGenresService.cs b/MediaBrowser.Api/UserLibrary/GameGenresService.cs
deleted file mode 100644
index 3e0d4aca4..000000000
--- a/MediaBrowser.Api/UserLibrary/GameGenresService.cs
+++ /dev/null
@@ -1,105 +0,0 @@
-using System;
-using System.Collections.Generic;
-using MediaBrowser.Controller.Dto;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.Net;
-using MediaBrowser.Controller.Persistence;
-using MediaBrowser.Model.Dto;
-using MediaBrowser.Model.Querying;
-using MediaBrowser.Model.Services;
-
-namespace MediaBrowser.Api.UserLibrary
-{
- [Route("/GameGenres", "GET", Summary = "Gets all Game genres from a given item, folder, or the entire library")]
- public class GetGameGenres : GetItemsByName
- {
- }
-
- [Route("/GameGenres/{Name}", "GET", Summary = "Gets a Game genre, by name")]
- public class GetGameGenre : IReturn<BaseItemDto>
- {
- /// <summary>
- /// Gets or sets the name.
- /// </summary>
- /// <value>The name.</value>
- [ApiMember(Name = "Name", Description = "The genre name", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
- public string Name { get; set; }
-
- /// <summary>
- /// Gets or sets the user id.
- /// </summary>
- /// <value>The user id.</value>
- [ApiMember(Name = "UserId", Description = "Optional. Filter by user id, and attach user data", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
- public Guid UserId { get; set; }
- }
-
- [Authenticated]
- public class GameGenresService : BaseItemsByNameService<GameGenre>
- {
- /// <summary>
- /// Gets the specified request.
- /// </summary>
- /// <param name="request">The request.</param>
- /// <returns>System.Object.</returns>
- public object Get(GetGameGenre request)
- {
- var result = GetItem(request);
-
- return ToOptimizedResult(result);
- }
-
- /// <summary>
- /// Gets the item.
- /// </summary>
- /// <param name="request">The request.</param>
- /// <returns>Task{BaseItemDto}.</returns>
- private BaseItemDto GetItem(GetGameGenre request)
- {
- var dtoOptions = GetDtoOptions(AuthorizationContext, request);
-
- var item = GetGameGenre(request.Name, LibraryManager, dtoOptions);
-
- if (!request.UserId.Equals(Guid.Empty))
- {
- var user = UserManager.GetUserById(request.UserId);
-
- return DtoService.GetBaseItemDto(item, dtoOptions, user);
- }
-
- return DtoService.GetBaseItemDto(item, dtoOptions);
- }
-
- /// <summary>
- /// Gets the specified request.
- /// </summary>
- /// <param name="request">The request.</param>
- /// <returns>System.Object.</returns>
- public object Get(GetGameGenres request)
- {
- var result = GetResultSlim(request);
-
- return ToOptimizedResult(result);
- }
-
- protected override QueryResult<Tuple<BaseItem, ItemCounts>> GetItems(GetItemsByName request, InternalItemsQuery query)
- {
- return LibraryManager.GetGameGenres(query);
- }
-
- /// <summary>
- /// Gets all items.
- /// </summary>
- /// <param name="request">The request.</param>
- /// <param name="items">The items.</param>
- /// <returns>IEnumerable{Tuple{System.StringFunc{System.Int32}}}.</returns>
- protected override IEnumerable<BaseItem> GetAllItems(GetItemsByName request, IList<BaseItem> items)
- {
- throw new NotImplementedException();
- }
-
- public GameGenresService(IUserManager userManager, ILibraryManager libraryManager, IUserDataManager userDataRepository, IItemRepository itemRepository, IDtoService dtoService, IAuthorizationContext authorizationContext) : base(userManager, libraryManager, userDataRepository, itemRepository, dtoService, authorizationContext)
- {
- }
- }
-}
diff --git a/MediaBrowser.Api/UserLibrary/GenresService.cs b/MediaBrowser.Api/UserLibrary/GenresService.cs
index e20428ead..baf570d50 100644
--- a/MediaBrowser.Api/UserLibrary/GenresService.cs
+++ b/MediaBrowser.Api/UserLibrary/GenresService.cs
@@ -101,11 +101,6 @@ namespace MediaBrowser.Api.UserLibrary
return LibraryManager.GetMusicGenres(query);
}
- if (string.Equals(viewType, CollectionType.Games))
- {
- return LibraryManager.GetGameGenres(query);
- }
-
return LibraryManager.GetGenres(query);
}
diff --git a/MediaBrowser.Api/UserLibrary/ItemsService.cs b/MediaBrowser.Api/UserLibrary/ItemsService.cs
index bf453576c..3ae7da007 100644
--- a/MediaBrowser.Api/UserLibrary/ItemsService.cs
+++ b/MediaBrowser.Api/UserLibrary/ItemsService.cs
@@ -304,8 +304,6 @@ namespace MediaBrowser.Api.UserLibrary
VideoTypes = request.GetVideoTypes(),
AdjacentTo = request.AdjacentTo,
ItemIds = GetGuids(request.Ids),
- MinPlayers = request.MinPlayers,
- MaxPlayers = request.MaxPlayers,
MinCommunityRating = request.MinCommunityRating,
MinCriticRating = request.MinCriticRating,
ParentId = string.IsNullOrWhiteSpace(request.ParentId) ? Guid.Empty : new Guid(request.ParentId),
diff --git a/MediaBrowser.Api/UserLibrary/PlaystateService.cs b/MediaBrowser.Api/UserLibrary/PlaystateService.cs
index 72a943092..b40a92a7c 100644
--- a/MediaBrowser.Api/UserLibrary/PlaystateService.cs
+++ b/MediaBrowser.Api/UserLibrary/PlaystateService.cs
@@ -247,14 +247,14 @@ namespace MediaBrowser.Api.UserLibrary
/// Posts the specified request.
/// </summary>
/// <param name="request">The request.</param>
- public async Task<object> Post(MarkPlayedItem request)
+ public object Post(MarkPlayedItem request)
{
- var result = await MarkPlayed(request).ConfigureAwait(false);
+ var result = MarkPlayed(request);
return ToOptimizedResult(result);
}
- private async Task<UserItemDataDto> MarkPlayed(MarkPlayedItem request)
+ private UserItemDataDto MarkPlayed(MarkPlayedItem request)
{
var user = _userManager.GetUserById(request.UserId);
@@ -366,9 +366,9 @@ namespace MediaBrowser.Api.UserLibrary
/// Posts the specified request.
/// </summary>
/// <param name="request">The request.</param>
- public void Delete(OnPlaybackStopped request)
+ public Task Delete(OnPlaybackStopped request)
{
- Post(new ReportPlaybackStopped
+ return Post(new ReportPlaybackStopped
{
ItemId = new Guid(request.Id),
PositionTicks = request.PositionTicks,
@@ -379,20 +379,18 @@ namespace MediaBrowser.Api.UserLibrary
});
}
- public void Post(ReportPlaybackStopped request)
+ public async Task Post(ReportPlaybackStopped request)
{
Logger.LogDebug("ReportPlaybackStopped PlaySessionId: {0}", request.PlaySessionId ?? string.Empty);
if (!string.IsNullOrWhiteSpace(request.PlaySessionId))
{
- ApiEntryPoint.Instance.KillTranscodingJobs(_authContext.GetAuthorizationInfo(Request).DeviceId, request.PlaySessionId, s => true);
+ await ApiEntryPoint.Instance.KillTranscodingJobs(_authContext.GetAuthorizationInfo(Request).DeviceId, request.PlaySessionId, s => true);
}
request.SessionId = GetSession(_sessionContext).Id;
- var task = _sessionManager.OnPlaybackStopped(request);
-
- Task.WaitAll(task);
+ await _sessionManager.OnPlaybackStopped(request);
}
/// <summary>
@@ -403,10 +401,10 @@ namespace MediaBrowser.Api.UserLibrary
{
var task = MarkUnplayed(request);
- return ToOptimizedResult(task.Result);
+ return ToOptimizedResult(task);
}
- private async Task<UserItemDataDto> MarkUnplayed(MarkUnplayedItem request)
+ private UserItemDataDto MarkUnplayed(MarkUnplayedItem request)
{
var user = _userManager.GetUserById(request.UserId);
diff --git a/MediaBrowser.Api/UserService.cs b/MediaBrowser.Api/UserService.cs
index 2ef18d7cf..a6849f75f 100644
--- a/MediaBrowser.Api/UserService.cs
+++ b/MediaBrowser.Api/UserService.cs
@@ -10,7 +10,6 @@ using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Net;
using MediaBrowser.Controller.Session;
using MediaBrowser.Model.Configuration;
-using MediaBrowser.Model.Connect;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Services;
using MediaBrowser.Model.Users;
@@ -299,11 +298,6 @@ namespace MediaBrowser.Api
users = users.Where(i => i.Policy.IsHidden == request.IsHidden.Value);
}
- if (request.IsGuest.HasValue)
- {
- users = users.Where(i => (i.ConnectLinkType.HasValue && i.ConnectLinkType.Value == UserLinkType.Guest) == request.IsGuest.Value);
- }
-
if (filterByDevice)
{
var deviceId = _authContext.GetAuthorizationInfo(Request).DeviceId;
diff --git a/MediaBrowser.Common/IApplicationHost.cs b/MediaBrowser.Common/IApplicationHost.cs
index 385127c54..59e3c1767 100644
--- a/MediaBrowser.Common/IApplicationHost.cs
+++ b/MediaBrowser.Common/IApplicationHost.cs
@@ -89,7 +89,7 @@ namespace MediaBrowser.Common
/// <typeparam name="T"></typeparam>
/// <param name="manageLiftime">if set to <c>true</c> [manage liftime].</param>
/// <returns>IEnumerable{``0}.</returns>
- IEnumerable<T> GetExports<T>(bool manageLiftime = true);
+ IEnumerable<T> GetExports<T>(bool manageLifetime = true);
/// <summary>
/// Updates the application.
@@ -131,7 +131,7 @@ namespace MediaBrowser.Common
/// <summary>
/// Inits this instance.
/// </summary>
- void Init();
+ Task Init();
/// <summary>
/// Creates the instance.
diff --git a/MediaBrowser.Controller/Connect/UserLinkResult.cs b/MediaBrowser.Controller/Connect/UserLinkResult.cs
deleted file mode 100644
index 327ceb952..000000000
--- a/MediaBrowser.Controller/Connect/UserLinkResult.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-namespace MediaBrowser.Controller.Connect
-{
- public class UserLinkResult
- {
- public bool IsPending { get; set; }
- public bool IsNewUserInvitation { get; set; }
- public string GuestDisplayName { get; set; }
- }
-}
diff --git a/MediaBrowser.Controller/Drawing/IImageEncoder.cs b/MediaBrowser.Controller/Drawing/IImageEncoder.cs
index 5b8c9da6f..4eaecd0a0 100644
--- a/MediaBrowser.Controller/Drawing/IImageEncoder.cs
+++ b/MediaBrowser.Controller/Drawing/IImageEncoder.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections.Generic;
using MediaBrowser.Model.Drawing;
namespace MediaBrowser.Controller.Drawing
@@ -9,12 +10,12 @@ namespace MediaBrowser.Controller.Drawing
/// Gets the supported input formats.
/// </summary>
/// <value>The supported input formats.</value>
- string[] SupportedInputFormats { get; }
+ IReadOnlyCollection<string> SupportedInputFormats { get; }
/// <summary>
/// Gets the supported output formats.
/// </summary>
/// <value>The supported output formats.</value>
- ImageFormat[] SupportedOutputFormats { get; }
+ IReadOnlyCollection<ImageFormat> SupportedOutputFormats { get; }
/// <summary>
/// Encodes the image.
diff --git a/MediaBrowser.Controller/Drawing/IImageProcessor.cs b/MediaBrowser.Controller/Drawing/IImageProcessor.cs
index 783182730..a11e2186f 100644
--- a/MediaBrowser.Controller/Drawing/IImageProcessor.cs
+++ b/MediaBrowser.Controller/Drawing/IImageProcessor.cs
@@ -18,7 +18,7 @@ namespace MediaBrowser.Controller.Drawing
/// Gets the supported input formats.
/// </summary>
/// <value>The supported input formats.</value>
- string[] SupportedInputFormats { get; }
+ IReadOnlyCollection<string> SupportedInputFormats { get; }
/// <summary>
/// Gets the image enhancers.
@@ -26,16 +26,29 @@ namespace MediaBrowser.Controller.Drawing
/// <value>The image enhancers.</value>
IImageEnhancer[] ImageEnhancers { get; }
- ImageDimensions GetImageSize(string path);
+ /// <summary>
+ /// Gets the dimensions of the image.
+ /// </summary>
+ /// <param name="path">Path to the image file.</param>
+ /// <returns>ImageDimensions</returns>
+ ImageDimensions GetImageDimensions(string path);
/// <summary>
- /// Gets the size of the image.
+ /// Gets the dimensions of the image.
/// </summary>
+ /// <param name="item">The base item.</param>
/// <param name="info">The information.</param>
- /// <returns>ImageSize.</returns>
- ImageDimensions GetImageSize(BaseItem item, ItemImageInfo info);
+ /// <returns>ImageDimensions</returns>
+ ImageDimensions GetImageDimensions(BaseItem item, ItemImageInfo info);
- ImageDimensions GetImageSize(BaseItem item, ItemImageInfo info, bool updateItem);
+ /// <summary>
+ /// Gets the dimensions of the image.
+ /// </summary>
+ /// <param name="item">The base item.</param>
+ /// <param name="info">The information.</param>
+ /// <param name="updateItem">Whether or not the item info should be updated.</param>
+ /// <returns>ImageDimensions</returns>
+ ImageDimensions GetImageDimensions(BaseItem item, ItemImageInfo info, bool updateItem);
/// <summary>
/// Adds the parts.
@@ -96,8 +109,8 @@ namespace MediaBrowser.Controller.Drawing
/// <summary>
/// Gets the supported image output formats.
/// </summary>
- /// <returns>ImageOutputFormat[].</returns>
- ImageFormat[] GetSupportedImageOutputFormats();
+ /// <returns>IReadOnlyCollection{ImageOutput}.</returns>
+ IReadOnlyCollection<ImageFormat> GetSupportedImageOutputFormats();
/// <summary>
/// Creates the image collage.
diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs
index 482d14e11..72c4e3573 100644
--- a/MediaBrowser.Controller/Entities/BaseItem.cs
+++ b/MediaBrowser.Controller/Entities/BaseItem.cs
@@ -615,7 +615,7 @@ namespace MediaBrowser.Controller.Entities
if (!string.IsNullOrEmpty(ForcedSortName))
{
// Need the ToLower because that's what CreateSortName does
- _sortName = ModifySortChunks(ForcedSortName).ToLower();
+ _sortName = ModifySortChunks(ForcedSortName).ToLowerInvariant();
}
else
{
@@ -661,7 +661,7 @@ namespace MediaBrowser.Controller.Entities
return Name.TrimStart();
}
- var sortable = Name.Trim().ToLower();
+ var sortable = Name.Trim().ToLowerInvariant();
foreach (var removeChar in ConfigurationManager.Configuration.SortRemoveCharacters)
{
diff --git a/MediaBrowser.Controller/Entities/CollectionFolder.cs b/MediaBrowser.Controller/Entities/CollectionFolder.cs
index 91cfcd0ce..275052d48 100644
--- a/MediaBrowser.Controller/Entities/CollectionFolder.cs
+++ b/MediaBrowser.Controller/Entities/CollectionFolder.cs
@@ -335,7 +335,11 @@ namespace MediaBrowser.Controller.Entities
.OfType<Folder>()
.ToList();
- return PhysicalLocations.Where(i => !FileSystem.AreEqual(i, Path)).SelectMany(i => GetPhysicalParents(i, rootChildren)).DistinctBy(i => i.Id);
+ return PhysicalLocations
+ .Where(i => !FileSystem.AreEqual(i, Path))
+ .SelectMany(i => GetPhysicalParents(i, rootChildren))
+ .GroupBy(x => x.Id)
+ .Select(x => x.First());
}
private IEnumerable<Folder> GetPhysicalParents(string path, List<Folder> rootChildren)
diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs
index dab96509c..8bfadbee6 100644
--- a/MediaBrowser.Controller/Entities/Folder.cs
+++ b/MediaBrowser.Controller/Entities/Folder.cs
@@ -1149,16 +1149,6 @@ namespace MediaBrowser.Controller.Entities
return false;
}
- if (request.MinPlayers.HasValue)
- {
- return false;
- }
-
- if (request.MaxPlayers.HasValue)
- {
- return false;
- }
-
if (request.MinCommunityRating.HasValue)
{
return false;
diff --git a/MediaBrowser.Controller/Entities/Game.cs b/MediaBrowser.Controller/Entities/Game.cs
deleted file mode 100644
index eea1bf43d..000000000
--- a/MediaBrowser.Controller/Entities/Game.cs
+++ /dev/null
@@ -1,113 +0,0 @@
-using System;
-using System.Collections.Generic;
-using MediaBrowser.Controller.Providers;
-using MediaBrowser.Model.Configuration;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Model.Serialization;
-
-namespace MediaBrowser.Controller.Entities
-{
- public class Game : BaseItem, IHasTrailers, IHasScreenshots, ISupportsPlaceHolders, IHasLookupInfo<GameInfo>
- {
- public Game()
- {
- MultiPartGameFiles = Array.Empty<string>();
- RemoteTrailers = EmptyMediaUrlArray;
- LocalTrailerIds = Array.Empty<Guid>();
- RemoteTrailerIds = Array.Empty<Guid>();
- }
-
- public Guid[] LocalTrailerIds { get; set; }
- public Guid[] RemoteTrailerIds { get; set; }
-
- public override bool CanDownload()
- {
- return IsFileProtocol;
- }
-
- [IgnoreDataMember]
- public override bool SupportsThemeMedia => true;
-
- [IgnoreDataMember]
- public override bool SupportsPeople => false;
-
- /// <summary>
- /// Gets the type of the media.
- /// </summary>
- /// <value>The type of the media.</value>
- [IgnoreDataMember]
- public override string MediaType => Model.Entities.MediaType.Game;
-
- /// <summary>
- /// Gets or sets the players supported.
- /// </summary>
- /// <value>The players supported.</value>
- public int? PlayersSupported { get; set; }
-
- /// <summary>
- /// Gets a value indicating whether this instance is place holder.
- /// </summary>
- /// <value><c>true</c> if this instance is place holder; otherwise, <c>false</c>.</value>
- public bool IsPlaceHolder { get; set; }
-
- /// <summary>
- /// Gets or sets the game system.
- /// </summary>
- /// <value>The game system.</value>
- public string GameSystem { get; set; }
-
- /// <summary>
- /// Gets or sets a value indicating whether this instance is multi part.
- /// </summary>
- /// <value><c>true</c> if this instance is multi part; otherwise, <c>false</c>.</value>
- public bool IsMultiPart { get; set; }
-
- /// <summary>
- /// Holds the paths to the game files in the event this is a multipart game
- /// </summary>
- public string[] MultiPartGameFiles { get; set; }
-
- public override List<string> GetUserDataKeys()
- {
- var list = base.GetUserDataKeys();
- var id = this.GetProviderId(MetadataProviders.Gamesdb);
-
- if (!string.IsNullOrEmpty(id))
- {
- list.Insert(0, "Game-Gamesdb-" + id);
- }
- return list;
- }
-
- public override IEnumerable<FileSystemMetadata> GetDeletePaths()
- {
- if (!IsInMixedFolder)
- {
- return new[] {
- new FileSystemMetadata
- {
- FullName = System.IO.Path.GetDirectoryName(Path),
- IsDirectory = true
- }
- };
- }
-
- return base.GetDeletePaths();
- }
-
- public override UnratedItem GetBlockUnratedType()
- {
- return UnratedItem.Game;
- }
-
- public GameInfo GetLookupInfo()
- {
- var id = GetItemLookupInfo<GameInfo>();
-
- id.GameSystem = GameSystem;
-
- return id;
- }
- }
-}
diff --git a/MediaBrowser.Controller/Entities/GameGenre.cs b/MediaBrowser.Controller/Entities/GameGenre.cs
deleted file mode 100644
index c0fd4ae89..000000000
--- a/MediaBrowser.Controller/Entities/GameGenre.cs
+++ /dev/null
@@ -1,109 +0,0 @@
-using System;
-using System.Collections.Generic;
-using MediaBrowser.Controller.Extensions;
-using MediaBrowser.Model.Serialization;
-using Microsoft.Extensions.Logging;
-
-namespace MediaBrowser.Controller.Entities
-{
- public class GameGenre : BaseItem, IItemByName
- {
- public override List<string> GetUserDataKeys()
- {
- var list = base.GetUserDataKeys();
-
- list.Insert(0, GetType().Name + "-" + (Name ?? string.Empty).RemoveDiacritics());
- return list;
- }
-
- public override string CreatePresentationUniqueKey()
- {
- return GetUserDataKeys()[0];
- }
-
- public override double GetDefaultPrimaryImageAspectRatio()
- {
- return 1;
- }
-
- /// <summary>
- /// Returns the folder containing the item.
- /// If the item is a folder, it returns the folder itself
- /// </summary>
- /// <value>The containing folder path.</value>
- [IgnoreDataMember]
- public override string ContainingFolderPath => Path;
-
- [IgnoreDataMember]
- public override bool SupportsAncestors => false;
-
- public override bool IsSaveLocalMetadataEnabled()
- {
- return true;
- }
-
- public override bool CanDelete()
- {
- return false;
- }
-
- public IList<BaseItem> GetTaggedItems(InternalItemsQuery query)
- {
- query.GenreIds = new[] { Id };
- query.IncludeItemTypes = new[] { typeof(Game).Name };
-
- return LibraryManager.GetItemList(query);
- }
-
- [IgnoreDataMember]
- public override bool SupportsPeople => false;
-
- public static string GetPath(string name)
- {
- return GetPath(name, true);
- }
-
- public static string GetPath(string name, bool normalizeName)
- {
- // Trim the period at the end because windows will have a hard time with that
- var validName = normalizeName ?
- FileSystem.GetValidFilename(name).Trim().TrimEnd('.') :
- name;
-
- return System.IO.Path.Combine(ConfigurationManager.ApplicationPaths.GameGenrePath, validName);
- }
-
- private string GetRebasedPath()
- {
- return GetPath(System.IO.Path.GetFileName(Path), false);
- }
-
- public override bool RequiresRefresh()
- {
- var newPath = GetRebasedPath();
- if (!string.Equals(Path, newPath, StringComparison.Ordinal))
- {
- Logger.LogDebug("{0} path has changed from {1} to {2}", GetType().Name, Path, newPath);
- return true;
- }
- return base.RequiresRefresh();
- }
-
- /// <summary>
- /// This is called before any metadata refresh and returns true or false indicating if changes were made
- /// </summary>
- public override bool BeforeMetadataRefresh(bool replaceAllMetdata)
- {
- var hasChanges = base.BeforeMetadataRefresh(replaceAllMetdata);
-
- var newPath = GetRebasedPath();
- if (!string.Equals(Path, newPath, StringComparison.Ordinal))
- {
- Path = newPath;
- hasChanges = true;
- }
-
- return hasChanges;
- }
- }
-}
diff --git a/MediaBrowser.Controller/Entities/GameSystem.cs b/MediaBrowser.Controller/Entities/GameSystem.cs
deleted file mode 100644
index 63f830d25..000000000
--- a/MediaBrowser.Controller/Entities/GameSystem.cs
+++ /dev/null
@@ -1,77 +0,0 @@
-using System;
-using System.Collections.Generic;
-using MediaBrowser.Controller.Providers;
-using MediaBrowser.Model.Configuration;
-using MediaBrowser.Model.Serialization;
-using MediaBrowser.Model.Users;
-
-namespace MediaBrowser.Controller.Entities
-{
- /// <summary>
- /// Class GameSystem
- /// </summary>
- public class GameSystem : Folder, IHasLookupInfo<GameSystemInfo>
- {
- /// <summary>
- /// Return the id that should be used to key display prefs for this item.
- /// Default is based on the type for everything except actual generic folders.
- /// </summary>
- /// <value>The display prefs id.</value>
- [IgnoreDataMember]
- public override Guid DisplayPreferencesId => Id;
-
- [IgnoreDataMember]
- public override bool SupportsPlayedStatus => false;
-
- [IgnoreDataMember]
- public override bool SupportsInheritedParentImages => false;
-
- public override double GetDefaultPrimaryImageAspectRatio()
- {
- double value = 16;
- value /= 9;
-
- return value;
- }
-
- /// <summary>
- /// Gets or sets the game system.
- /// </summary>
- /// <value>The game system.</value>
- public string GameSystemName { get; set; }
-
- public override List<string> GetUserDataKeys()
- {
- var list = base.GetUserDataKeys();
-
- if (!string.IsNullOrEmpty(GameSystemName))
- {
- list.Insert(0, "GameSystem-" + GameSystemName);
- }
- return list;
- }
-
- protected override bool GetBlockUnratedValue(UserPolicy config)
- {
- // Don't block. Determine by game
- return false;
- }
-
- public override UnratedItem GetBlockUnratedType()
- {
- return UnratedItem.Game;
- }
-
- public GameSystemInfo GetLookupInfo()
- {
- var id = GetItemLookupInfo<GameSystemInfo>();
-
- id.Path = Path;
-
- return id;
- }
-
- [IgnoreDataMember]
- public override bool SupportsPeople => false;
- }
-}
diff --git a/MediaBrowser.Controller/Entities/Genre.cs b/MediaBrowser.Controller/Entities/Genre.cs
index 3f3ab3551..44cb62d22 100644
--- a/MediaBrowser.Controller/Entities/Genre.cs
+++ b/MediaBrowser.Controller/Entities/Genre.cs
@@ -56,7 +56,7 @@ namespace MediaBrowser.Controller.Entities
public IList<BaseItem> GetTaggedItems(InternalItemsQuery query)
{
query.GenreIds = new[] { Id };
- query.ExcludeItemTypes = new[] { typeof(Game).Name, typeof(MusicVideo).Name, typeof(Audio.Audio).Name, typeof(MusicAlbum).Name, typeof(MusicArtist).Name };
+ query.ExcludeItemTypes = new[] { typeof(MusicVideo).Name, typeof(Audio.Audio).Name, typeof(MusicAlbum).Name, typeof(MusicArtist).Name };
return LibraryManager.GetItemList(query);
}
diff --git a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs
index 4b7af5391..78f859069 100644
--- a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs
+++ b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs
@@ -95,9 +95,6 @@ namespace MediaBrowser.Controller.Entities
public bool? IsKids { get; set; }
public bool? IsNews { get; set; }
public bool? IsSeries { get; set; }
-
- public int? MinPlayers { get; set; }
- public int? MaxPlayers { get; set; }
public int? MinIndexNumber { get; set; }
public int? AiredDuringSeason { get; set; }
public double? MinCriticRating { get; set; }
diff --git a/MediaBrowser.Controller/Entities/TV/Series.cs b/MediaBrowser.Controller/Entities/TV/Series.cs
index 4539ab0f2..570e9389e 100644
--- a/MediaBrowser.Controller/Entities/TV/Series.cs
+++ b/MediaBrowser.Controller/Entities/TV/Series.cs
@@ -270,7 +270,7 @@ namespace MediaBrowser.Controller.Entities.TV
// This depends on settings for that series
// When this happens, remove the duplicate from season 0
- return allEpisodes.DistinctBy(i => i.Id).Reverse();
+ return allEpisodes.GroupBy(i => i.Id).Select(x => x.First()).Reverse();
}
public async Task RefreshAllMetadata(MetadataRefreshOptions refreshOptions, IProgress<double> progress, CancellationToken cancellationToken)
diff --git a/MediaBrowser.Controller/Entities/User.cs b/MediaBrowser.Controller/Entities/User.cs
index 06bae9211..0d5f508dd 100644
--- a/MediaBrowser.Controller/Entities/User.cs
+++ b/MediaBrowser.Controller/Entities/User.cs
@@ -5,7 +5,6 @@ using System.Threading.Tasks;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Configuration;
-using MediaBrowser.Model.Connect;
using MediaBrowser.Model.Serialization;
using MediaBrowser.Model.Users;
@@ -33,11 +32,6 @@ namespace MediaBrowser.Controller.Entities
public string EasyPassword { get; set; }
public string Salt { get; set; }
- public string ConnectUserName { get; set; }
- public string ConnectUserId { get; set; }
- public UserLinkType? ConnectLinkType { get; set; }
- public string ConnectAccessKey { get; set; }
-
// Strictly to remove IgnoreDataMember
public override ItemImageInfo[] ImageInfos
{
diff --git a/MediaBrowser.Controller/Entities/UserView.cs b/MediaBrowser.Controller/Entities/UserView.cs
index de4105df9..3e2191376 100644
--- a/MediaBrowser.Controller/Entities/UserView.cs
+++ b/MediaBrowser.Controller/Entities/UserView.cs
@@ -150,7 +150,6 @@ namespace MediaBrowser.Controller.Entities
private static string[] OriginalFolderViewTypes = new string[]
{
- MediaBrowser.Model.Entities.CollectionType.Games,
MediaBrowser.Model.Entities.CollectionType.Books,
MediaBrowser.Model.Entities.CollectionType.MusicVideos,
MediaBrowser.Model.Entities.CollectionType.HomeVideos,
diff --git a/MediaBrowser.Controller/Entities/UserViewBuilder.cs b/MediaBrowser.Controller/Entities/UserViewBuilder.cs
index 0b0134669..683218a9e 100644
--- a/MediaBrowser.Controller/Entities/UserViewBuilder.cs
+++ b/MediaBrowser.Controller/Entities/UserViewBuilder.cs
@@ -848,52 +848,6 @@ namespace MediaBrowser.Controller.Entities
}
}
- if (query.MinPlayers.HasValue)
- {
- var filterValue = query.MinPlayers.Value;
-
- var game = item as Game;
-
- if (game != null)
- {
- var players = game.PlayersSupported ?? 1;
-
- var ok = players >= filterValue;
-
- if (!ok)
- {
- return false;
- }
- }
- else
- {
- return false;
- }
- }
-
- if (query.MaxPlayers.HasValue)
- {
- var filterValue = query.MaxPlayers.Value;
-
- var game = item as Game;
-
- if (game != null)
- {
- var players = game.PlayersSupported ?? 1;
-
- var ok = players <= filterValue;
-
- if (!ok)
- {
- return false;
- }
- }
- else
- {
- return false;
- }
- }
-
if (query.MinCommunityRating.HasValue)
{
var val = query.MinCommunityRating.Value;
diff --git a/MediaBrowser.Controller/Entities/Video.cs b/MediaBrowser.Controller/Entities/Video.cs
index 33a967758..31cd42975 100644
--- a/MediaBrowser.Controller/Entities/Video.cs
+++ b/MediaBrowser.Controller/Entities/Video.cs
@@ -305,7 +305,7 @@ namespace MediaBrowser.Controller.Entities
private string GetUserDataKey(string providerId)
{
- var key = providerId + "-" + ExtraType.ToString().ToLower();
+ var key = providerId + "-" + ExtraType.ToString().ToLowerInvariant();
// Make sure different trailers have their own data.
if (RunTimeTicks.HasValue)
diff --git a/MediaBrowser.Controller/Extensions/StringExtensions.cs b/MediaBrowser.Controller/Extensions/StringExtensions.cs
index 73f529fc0..b1aaf6534 100644
--- a/MediaBrowser.Controller/Extensions/StringExtensions.cs
+++ b/MediaBrowser.Controller/Extensions/StringExtensions.cs
@@ -1,4 +1,8 @@
-using MediaBrowser.Model.Globalization;
+using System;
+using System.Globalization;
+using System.Linq;
+using System.Text;
+using System.Text.RegularExpressions;
namespace MediaBrowser.Controller.Extensions
{
@@ -7,11 +11,45 @@ namespace MediaBrowser.Controller.Extensions
/// </summary>
public static class StringExtensions
{
- public static ILocalizationManager LocalizationManager { get; set; }
-
public static string RemoveDiacritics(this string text)
{
- return LocalizationManager.RemoveDiacritics(text);
+ if (text == null)
+ {
+ throw new ArgumentNullException(nameof(text));
+ }
+
+ var chars = Normalize(text, NormalizationForm.FormD)
+ .Where(ch => CharUnicodeInfo.GetUnicodeCategory(ch) != UnicodeCategory.NonSpacingMark);
+
+ return Normalize(string.Concat(chars), NormalizationForm.FormC);
+ }
+
+ private static string Normalize(string text, NormalizationForm form, bool stripStringOnFailure = true)
+ {
+ if (stripStringOnFailure)
+ {
+ try
+ {
+ return text.Normalize(form);
+ }
+ catch (ArgumentException)
+ {
+ // will throw if input contains invalid unicode chars
+ // https://mnaoumov.wordpress.com/2014/06/14/stripping-invalid-characters-from-utf-16-strings/
+ text = Regex.Replace(text, "([\ud800-\udbff](?![\udc00-\udfff]))|((?<![\ud800-\udbff])[\udc00-\udfff])", "");
+ return Normalize(text, form, false);
+ }
+ }
+
+ try
+ {
+ return text.Normalize(form);
+ }
+ catch (ArgumentException)
+ {
+ // if it still fails, return the original text
+ return text;
+ }
}
}
}
diff --git a/MediaBrowser.Controller/IServerApplicationPaths.cs b/MediaBrowser.Controller/IServerApplicationPaths.cs
index 2b43513b7..15d7e9f62 100644
--- a/MediaBrowser.Controller/IServerApplicationPaths.cs
+++ b/MediaBrowser.Controller/IServerApplicationPaths.cs
@@ -47,12 +47,6 @@ namespace MediaBrowser.Controller
string MusicGenrePath { get; }
/// <summary>
- /// Gets the game genre path.
- /// </summary>
- /// <value>The game genre path.</value>
- string GameGenrePath { get; }
-
- /// <summary>
/// Gets the path to the Studio directory
/// </summary>
/// <value>The studio path.</value>
diff --git a/MediaBrowser.Controller/Library/ILibraryManager.cs b/MediaBrowser.Controller/Library/ILibraryManager.cs
index 9d404ba1a..60c183d04 100644
--- a/MediaBrowser.Controller/Library/ILibraryManager.cs
+++ b/MediaBrowser.Controller/Library/ILibraryManager.cs
@@ -89,13 +89,6 @@ namespace MediaBrowser.Controller.Library
MusicGenre GetMusicGenre(string name);
/// <summary>
- /// Gets the game genre.
- /// </summary>
- /// <param name="name">The name.</param>
- /// <returns>Task{GameGenre}.</returns>
- GameGenre GetGameGenre(string name);
-
- /// <summary>
/// Gets a Year
/// </summary>
/// <param name="value">The value.</param>
@@ -521,8 +514,6 @@ namespace MediaBrowser.Controller.Library
Guid GetMusicGenreId(string name);
- Guid GetGameGenreId(string name);
-
Task AddVirtualFolder(string name, string collectionType, LibraryOptions options, bool refreshLibrary);
Task RemoveVirtualFolder(string name, bool refreshLibrary);
void AddMediaPath(string virtualFolderName, MediaPathInfo path);
@@ -531,7 +522,6 @@ namespace MediaBrowser.Controller.Library
QueryResult<Tuple<BaseItem, ItemCounts>> GetGenres(InternalItemsQuery query);
QueryResult<Tuple<BaseItem, ItemCounts>> GetMusicGenres(InternalItemsQuery query);
- QueryResult<Tuple<BaseItem, ItemCounts>> GetGameGenres(InternalItemsQuery query);
QueryResult<Tuple<BaseItem, ItemCounts>> GetStudios(InternalItemsQuery query);
QueryResult<Tuple<BaseItem, ItemCounts>> GetArtists(InternalItemsQuery query);
QueryResult<Tuple<BaseItem, ItemCounts>> GetAlbumArtists(InternalItemsQuery query);
diff --git a/MediaBrowser.Controller/Library/NameExtensions.cs b/MediaBrowser.Controller/Library/NameExtensions.cs
index e2988a831..6b0b7e53a 100644
--- a/MediaBrowser.Controller/Library/NameExtensions.cs
+++ b/MediaBrowser.Controller/Library/NameExtensions.cs
@@ -1,7 +1,7 @@
using System;
+using System.Linq;
using System.Collections.Generic;
using MediaBrowser.Controller.Extensions;
-using MediaBrowser.Model.Extensions;
namespace MediaBrowser.Controller.Library
{
@@ -14,13 +14,11 @@ namespace MediaBrowser.Controller.Library
return string.Empty;
}
- //return name;
return name.RemoveDiacritics();
}
public static IEnumerable<string> DistinctNames(this IEnumerable<string> names)
- {
- return names.DistinctBy(RemoveDiacritics, StringComparer.OrdinalIgnoreCase);
- }
+ => names.GroupBy(RemoveDiacritics, StringComparer.OrdinalIgnoreCase)
+ .Select(x => x.First());
}
}
diff --git a/MediaBrowser.Controller/LiveTv/ILiveTvService.cs b/MediaBrowser.Controller/LiveTv/ILiveTvService.cs
index ba3813d8a..b71a76648 100644
--- a/MediaBrowser.Controller/LiveTv/ILiveTvService.cs
+++ b/MediaBrowser.Controller/LiveTv/ILiveTvService.cs
@@ -13,11 +13,6 @@ namespace MediaBrowser.Controller.LiveTv
public interface ILiveTvService
{
/// <summary>
- /// Occurs when [data source changed].
- /// </summary>
- event EventHandler DataSourceChanged;
-
- /// <summary>
/// Gets the name.
/// </summary>
/// <value>The name.</value>
diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs
index fc2b8f9c9..f5f147db1 100644
--- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs
+++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs
@@ -136,7 +136,7 @@ namespace MediaBrowser.Controller.MediaEncoding
return "libtheora";
}
- return codec.ToLower();
+ return codec.ToLowerInvariant();
}
return "copy";
@@ -405,7 +405,7 @@ namespace MediaBrowser.Controller.MediaEncoding
return "libopus";
}
- return codec.ToLower();
+ return codec.ToLowerInvariant();
}
/// <summary>
@@ -762,7 +762,7 @@ namespace MediaBrowser.Controller.MediaEncoding
// vaapi does not support Baseline profile, force Constrained Baseline in this case,
// which is compatible (and ugly)
if (string.Equals(videoEncoder, "h264_vaapi", StringComparison.OrdinalIgnoreCase) &&
- profile != null && profile.ToLower().Contains("baseline"))
+ profile != null && profile.ToLowerInvariant().Contains("baseline"))
{
profile = "constrained_baseline";
}
@@ -2175,7 +2175,7 @@ namespace MediaBrowser.Controller.MediaEncoding
{
if (string.Equals(encodingOptions.HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase))
{
- switch (videoStream.Codec.ToLower())
+ switch (videoStream.Codec.ToLowerInvariant())
{
case "avc":
case "h264":
@@ -2215,7 +2215,7 @@ namespace MediaBrowser.Controller.MediaEncoding
else if (string.Equals(encodingOptions.HardwareAccelerationType, "nvenc", StringComparison.OrdinalIgnoreCase))
{
- switch (videoStream.Codec.ToLower())
+ switch (videoStream.Codec.ToLowerInvariant())
{
case "avc":
case "h264":
@@ -2254,7 +2254,7 @@ namespace MediaBrowser.Controller.MediaEncoding
else if (string.Equals(encodingOptions.HardwareAccelerationType, "mediacodec", StringComparison.OrdinalIgnoreCase))
{
- switch (videoStream.Codec.ToLower())
+ switch (videoStream.Codec.ToLowerInvariant())
{
case "avc":
case "h264":
@@ -2299,7 +2299,7 @@ namespace MediaBrowser.Controller.MediaEncoding
else if (string.Equals(encodingOptions.HardwareAccelerationType, "omx", StringComparison.OrdinalIgnoreCase))
{
- switch (videoStream.Codec.ToLower())
+ switch (videoStream.Codec.ToLowerInvariant())
{
case "avc":
case "h264":
@@ -2324,7 +2324,7 @@ namespace MediaBrowser.Controller.MediaEncoding
return "-hwaccel dxva2";
}
- switch (videoStream.Codec.ToLower())
+ switch (videoStream.Codec.ToLowerInvariant())
{
case "avc":
case "h264":
diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs b/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs
index 1fe8856cc..916d691b8 100644
--- a/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs
+++ b/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs
@@ -10,19 +10,13 @@ using MediaBrowser.Model.Entities;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.MediaInfo;
using MediaBrowser.Model.Session;
-using Microsoft.Extensions.Logging;
-using System.IO;
using MediaBrowser.Model.Net;
-using MediaBrowser.Controller.Library;
-using System.Threading.Tasks;
namespace MediaBrowser.Controller.MediaEncoding
{
// For now, a common base class until the API and MediaEncoding classes are unified
public class EncodingJobInfo
{
- protected readonly IMediaSourceManager MediaSourceManager;
-
public MediaStream VideoStream { get; set; }
public VideoType VideoType { get; set; }
public Dictionary<string, string> RemoteHttpHeaders { get; set; }
@@ -49,7 +43,6 @@ namespace MediaBrowser.Controller.MediaEncoding
public string OutputFilePath { get; set; }
public string MimeType { get; set; }
- public long? EncodingDurationTicks { get; set; }
public string GetMimeType(string outputPath, bool enableStreamDefault = true)
{
@@ -68,7 +61,12 @@ namespace MediaBrowser.Controller.MediaEncoding
{
if (_transcodeReasons == null)
{
- _transcodeReasons = (BaseRequest.TranscodeReasons ?? string.Empty)
+ if (BaseRequest.TranscodeReasons == null)
+ {
+ return Array.Empty<TranscodeReason>();
+ }
+
+ _transcodeReasons = BaseRequest.TranscodeReasons
.Split(',')
.Where(i => !string.IsNullOrEmpty(i))
.Select(v => (TranscodeReason)Enum.Parse(typeof(TranscodeReason), v, true))
@@ -98,7 +96,8 @@ namespace MediaBrowser.Controller.MediaEncoding
get
{
// For live tv + in progress recordings
- if (string.Equals(InputContainer, "mpegts", StringComparison.OrdinalIgnoreCase) || string.Equals(InputContainer, "ts", StringComparison.OrdinalIgnoreCase))
+ if (string.Equals(InputContainer, "mpegts", StringComparison.OrdinalIgnoreCase)
+ || string.Equals(InputContainer, "ts", StringComparison.OrdinalIgnoreCase))
{
if (!MediaSource.RunTimeTicks.HasValue)
{
@@ -155,15 +154,7 @@ namespace MediaBrowser.Controller.MediaEncoding
}
}
- if (forceDeinterlaceIfSourceIsInterlaced)
- {
- if (isInputInterlaced)
- {
- return true;
- }
- }
-
- return false;
+ return forceDeinterlaceIfSourceIsInterlaced && isInputInterlaced;
}
public string[] GetRequestedProfiles(string codec)
@@ -211,7 +202,8 @@ namespace MediaBrowser.Controller.MediaEncoding
if (!string.IsNullOrEmpty(codec))
{
var value = BaseRequest.GetOption(codec, "maxrefframes");
- if (!string.IsNullOrEmpty(value) && int.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out var result))
+ if (!string.IsNullOrEmpty(value)
+ && int.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out var result))
{
return result;
}
@@ -230,7 +222,8 @@ namespace MediaBrowser.Controller.MediaEncoding
if (!string.IsNullOrEmpty(codec))
{
var value = BaseRequest.GetOption(codec, "videobitdepth");
- if (!string.IsNullOrEmpty(value) && int.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out var result))
+ if (!string.IsNullOrEmpty(value)
+ && int.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out var result))
{
return result;
}
@@ -249,7 +242,8 @@ namespace MediaBrowser.Controller.MediaEncoding
if (!string.IsNullOrEmpty(codec))
{
var value = BaseRequest.GetOption(codec, "audiobitdepth");
- if (!string.IsNullOrEmpty(value) && int.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out var result))
+ if (!string.IsNullOrEmpty(value)
+ && int.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out var result))
{
return result;
}
@@ -264,6 +258,7 @@ namespace MediaBrowser.Controller.MediaEncoding
{
return BaseRequest.MaxAudioChannels;
}
+
if (BaseRequest.AudioChannels.HasValue)
{
return BaseRequest.AudioChannels;
@@ -272,7 +267,8 @@ namespace MediaBrowser.Controller.MediaEncoding
if (!string.IsNullOrEmpty(codec))
{
var value = BaseRequest.GetOption(codec, "audiochannels");
- if (!string.IsNullOrEmpty(value) && int.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out var result))
+ if (!string.IsNullOrEmpty(value)
+ && int.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out var result))
{
return result;
}
@@ -294,7 +290,8 @@ namespace MediaBrowser.Controller.MediaEncoding
SupportedSubtitleCodecs = Array.Empty<string>();
}
- public bool IsSegmentedLiveStream => TranscodingType != TranscodingJobType.Progressive && !RunTimeTicks.HasValue;
+ public bool IsSegmentedLiveStream
+ => TranscodingType != TranscodingJobType.Progressive && !RunTimeTicks.HasValue;
public bool EnableBreakOnNonKeyFrames(string videoCodec)
{
@@ -428,11 +425,12 @@ namespace MediaBrowser.Controller.MediaEncoding
{
if (BaseRequest.Static || string.Equals(OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase))
{
- return VideoStream == null ? null : VideoStream.Level;
+ return VideoStream?.Level;
}
var level = GetRequestedLevel(ActualOutputVideoCodec);
- if (!string.IsNullOrEmpty(level) && double.TryParse(level, NumberStyles.Any, CultureInfo.InvariantCulture, out var result))
+ if (!string.IsNullOrEmpty(level)
+ && double.TryParse(level, NumberStyles.Any, CultureInfo.InvariantCulture, out var result))
{
return result;
}
@@ -450,7 +448,7 @@ namespace MediaBrowser.Controller.MediaEncoding
{
if (BaseRequest.Static || string.Equals(OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase))
{
- return VideoStream == null ? null : VideoStream.BitDepth;
+ return VideoStream?.BitDepth;
}
return null;
@@ -467,7 +465,7 @@ namespace MediaBrowser.Controller.MediaEncoding
{
if (BaseRequest.Static || string.Equals(OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase))
{
- return VideoStream == null ? null : VideoStream.RefFrames;
+ return VideoStream?.RefFrames;
}
return null;
@@ -494,13 +492,14 @@ namespace MediaBrowser.Controller.MediaEncoding
{
get
{
- var defaultValue = string.Equals(OutputContainer, "m2ts", StringComparison.OrdinalIgnoreCase) ?
+ if (BaseRequest.Static)
+ {
+ return InputTimestamp;
+ }
+
+ return string.Equals(OutputContainer, "m2ts", StringComparison.OrdinalIgnoreCase) ?
TransportStreamTimestamp.Valid :
TransportStreamTimestamp.None;
-
- return !BaseRequest.Static
- ? defaultValue
- : InputTimestamp;
}
}
@@ -513,7 +512,7 @@ namespace MediaBrowser.Controller.MediaEncoding
{
if (BaseRequest.Static || string.Equals(OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase))
{
- return VideoStream == null ? null : VideoStream.PacketLength;
+ return VideoStream?.PacketLength;
}
return null;
@@ -529,7 +528,7 @@ namespace MediaBrowser.Controller.MediaEncoding
{
if (BaseRequest.Static || string.Equals(OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase))
{
- return VideoStream == null ? null : VideoStream.Profile;
+ return VideoStream?.Profile;
}
var requestedProfile = GetRequestedProfiles(ActualOutputVideoCodec).FirstOrDefault();
@@ -542,42 +541,13 @@ namespace MediaBrowser.Controller.MediaEncoding
}
}
- /// <summary>
- /// Predicts the audio sample rate that will be in the output stream
- /// </summary>
- public string TargetVideoRange
- {
- get
- {
- if (BaseRequest.Static || string.Equals(OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase))
- {
- return VideoStream == null ? null : VideoStream.VideoRange;
- }
-
- return "SDR";
- }
- }
-
- public string TargetAudioProfile
- {
- get
- {
- if (BaseRequest.Static || string.Equals(OutputAudioCodec, "copy", StringComparison.OrdinalIgnoreCase))
- {
- return AudioStream == null ? null : AudioStream.Profile;
- }
-
- return null;
- }
- }
-
public string TargetVideoCodecTag
{
get
{
if (BaseRequest.Static || string.Equals(OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase))
{
- return VideoStream == null ? null : VideoStream.CodecTag;
+ return VideoStream?.CodecTag;
}
return null;
@@ -590,7 +560,7 @@ namespace MediaBrowser.Controller.MediaEncoding
{
if (BaseRequest.Static || string.Equals(OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase))
{
- return VideoStream == null ? null : VideoStream.IsAnamorphic;
+ return VideoStream?.IsAnamorphic;
}
return false;
@@ -605,14 +575,7 @@ namespace MediaBrowser.Controller.MediaEncoding
if (string.Equals(codec, "copy", StringComparison.OrdinalIgnoreCase))
{
- var stream = VideoStream;
-
- if (stream != null)
- {
- return stream.Codec;
- }
-
- return null;
+ return VideoStream?.Codec;
}
return codec;
@@ -627,14 +590,7 @@ namespace MediaBrowser.Controller.MediaEncoding
if (string.Equals(codec, "copy", StringComparison.OrdinalIgnoreCase))
{
- var stream = AudioStream;
-
- if (stream != null)
- {
- return stream.Codec;
- }
-
- return null;
+ return AudioStream?.Codec;
}
return codec;
@@ -647,7 +603,7 @@ namespace MediaBrowser.Controller.MediaEncoding
{
if (BaseRequest.Static || string.Equals(OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase))
{
- return VideoStream == null ? (bool?)null : VideoStream.IsInterlaced;
+ return VideoStream?.IsInterlaced;
}
if (DeInterlace(ActualOutputVideoCodec, true))
@@ -655,7 +611,7 @@ namespace MediaBrowser.Controller.MediaEncoding
return false;
}
- return VideoStream == null ? (bool?)null : VideoStream.IsInterlaced;
+ return VideoStream?.IsInterlaced;
}
}
@@ -665,7 +621,7 @@ namespace MediaBrowser.Controller.MediaEncoding
{
if (BaseRequest.Static || string.Equals(OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase))
{
- return VideoStream == null ? null : VideoStream.IsAVC;
+ return VideoStream?.IsAVC;
}
return false;
diff --git a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs
index 48055a37e..057e43910 100644
--- a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs
+++ b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs
@@ -82,28 +82,6 @@ namespace MediaBrowser.Controller.MediaEncoding
/// <returns>System.String.</returns>
string GetTimeParameter(long ticks);
- /// <summary>
- /// Encodes the audio.
- /// </summary>
- /// <param name="options">The options.</param>
- /// <param name="progress">The progress.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- Task<string> EncodeAudio(EncodingJobOptions options,
- IProgress<double> progress,
- CancellationToken cancellationToken);
-
- /// <summary>
- /// Encodes the video.
- /// </summary>
- /// <param name="options">The options.</param>
- /// <param name="progress">The progress.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task&lt;System.String&gt;.</returns>
- Task<string> EncodeVideo(EncodingJobOptions options,
- IProgress<double> progress,
- CancellationToken cancellationToken);
-
Task ConvertImage(string inputPath, string outputPath);
/// <summary>
diff --git a/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs b/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs
index 4e7e1c8ed..4242a00e2 100644
--- a/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs
+++ b/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs
@@ -6,7 +6,6 @@ using System.Net.WebSockets;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Model.Net;
-using MediaBrowser.Model.Threading;
using Microsoft.Extensions.Logging;
namespace MediaBrowser.Controller.Net
@@ -23,8 +22,8 @@ namespace MediaBrowser.Controller.Net
/// <summary>
/// The _active connections
/// </summary>
- protected readonly List<Tuple<IWebSocketConnection, CancellationTokenSource, ITimer, TStateType>> ActiveConnections =
- new List<Tuple<IWebSocketConnection, CancellationTokenSource, ITimer, TStateType>>();
+ protected readonly List<Tuple<IWebSocketConnection, CancellationTokenSource, Timer, TStateType>> ActiveConnections =
+ new List<Tuple<IWebSocketConnection, CancellationTokenSource, Timer, TStateType>>();
/// <summary>
/// Gets the name.
@@ -44,8 +43,6 @@ namespace MediaBrowser.Controller.Net
/// </summary>
protected ILogger Logger;
- protected ITimerFactory TimerFactory { get; private set; }
-
protected BasePeriodicWebSocketListener(ILogger logger)
{
if (logger == null)
@@ -111,7 +108,7 @@ namespace MediaBrowser.Controller.Net
Logger.LogDebug("{1} Begin transmitting over websocket to {0}", message.Connection.RemoteEndPoint, GetType().Name);
var timer = SendOnTimer ?
- TimerFactory.Create(TimerCallback, message.Connection, Timeout.Infinite, Timeout.Infinite) :
+ new Timer(TimerCallback, message.Connection, Timeout.Infinite, Timeout.Infinite) :
null;
var state = new TStateType
@@ -122,7 +119,7 @@ namespace MediaBrowser.Controller.Net
lock (ActiveConnections)
{
- ActiveConnections.Add(new Tuple<IWebSocketConnection, CancellationTokenSource, ITimer, TStateType>(message.Connection, cancellationTokenSource, timer, state));
+ ActiveConnections.Add(new Tuple<IWebSocketConnection, CancellationTokenSource, Timer, TStateType>(message.Connection, cancellationTokenSource, timer, state));
}
if (timer != null)
@@ -139,7 +136,7 @@ namespace MediaBrowser.Controller.Net
{
var connection = (IWebSocketConnection)state;
- Tuple<IWebSocketConnection, CancellationTokenSource, ITimer, TStateType> tuple;
+ Tuple<IWebSocketConnection, CancellationTokenSource, Timer, TStateType> tuple;
lock (ActiveConnections)
{
@@ -162,7 +159,7 @@ namespace MediaBrowser.Controller.Net
protected void SendData(bool force)
{
- Tuple<IWebSocketConnection, CancellationTokenSource, ITimer, TStateType>[] tuples;
+ Tuple<IWebSocketConnection, CancellationTokenSource, Timer, TStateType>[] tuples;
lock (ActiveConnections)
{
@@ -190,7 +187,7 @@ namespace MediaBrowser.Controller.Net
}
}
- private async void SendData(Tuple<IWebSocketConnection, CancellationTokenSource, ITimer, TStateType> tuple)
+ private async void SendData(Tuple<IWebSocketConnection, CancellationTokenSource, Timer, TStateType> tuple)
{
var connection = tuple.Item1;
@@ -249,7 +246,7 @@ namespace MediaBrowser.Controller.Net
/// Disposes the connection.
/// </summary>
/// <param name="connection">The connection.</param>
- private void DisposeConnection(Tuple<IWebSocketConnection, CancellationTokenSource, ITimer, TStateType> connection)
+ private void DisposeConnection(Tuple<IWebSocketConnection, CancellationTokenSource, Timer, TStateType> connection)
{
Logger.LogDebug("{1} stop transmitting over websocket to {0}", connection.Item1.RemoteEndPoint, GetType().Name);
diff --git a/MediaBrowser.Controller/Persistence/IItemRepository.cs b/MediaBrowser.Controller/Persistence/IItemRepository.cs
index 0d086fd7e..5156fce11 100644
--- a/MediaBrowser.Controller/Persistence/IItemRepository.cs
+++ b/MediaBrowser.Controller/Persistence/IItemRepository.cs
@@ -143,13 +143,11 @@ namespace MediaBrowser.Controller.Persistence
QueryResult<Tuple<BaseItem, ItemCounts>> GetGenres(InternalItemsQuery query);
QueryResult<Tuple<BaseItem, ItemCounts>> GetMusicGenres(InternalItemsQuery query);
- QueryResult<Tuple<BaseItem, ItemCounts>> GetGameGenres(InternalItemsQuery query);
QueryResult<Tuple<BaseItem, ItemCounts>> GetStudios(InternalItemsQuery query);
QueryResult<Tuple<BaseItem, ItemCounts>> GetArtists(InternalItemsQuery query);
QueryResult<Tuple<BaseItem, ItemCounts>> GetAlbumArtists(InternalItemsQuery query);
QueryResult<Tuple<BaseItem, ItemCounts>> GetAllArtists(InternalItemsQuery query);
- List<string> GetGameGenreNames();
List<string> GetMusicGenreNames();
List<string> GetStudioNames();
List<string> GetGenreNames();
diff --git a/MediaBrowser.Controller/Plugins/IServerEntryPoint.cs b/MediaBrowser.Controller/Plugins/IServerEntryPoint.cs
index 7b7a591aa..e57929989 100644
--- a/MediaBrowser.Controller/Plugins/IServerEntryPoint.cs
+++ b/MediaBrowser.Controller/Plugins/IServerEntryPoint.cs
@@ -1,4 +1,5 @@
using System;
+using System.Threading.Tasks;
namespace MediaBrowser.Controller.Plugins
{
@@ -10,7 +11,7 @@ namespace MediaBrowser.Controller.Plugins
/// <summary>
/// Runs this instance.
/// </summary>
- void Run();
+ Task RunAsync();
}
public interface IRunBeforeStartup
diff --git a/MediaBrowser.Controller/Providers/GameInfo.cs b/MediaBrowser.Controller/Providers/GameInfo.cs
deleted file mode 100644
index 1f3eb40b7..000000000
--- a/MediaBrowser.Controller/Providers/GameInfo.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-namespace MediaBrowser.Controller.Providers
-{
- public class GameInfo : ItemLookupInfo
- {
- /// <summary>
- /// Gets or sets the game system.
- /// </summary>
- /// <value>The game system.</value>
- public string GameSystem { get; set; }
- }
-}
diff --git a/MediaBrowser.Controller/Providers/GameSystemInfo.cs b/MediaBrowser.Controller/Providers/GameSystemInfo.cs
deleted file mode 100644
index 796486b82..000000000
--- a/MediaBrowser.Controller/Providers/GameSystemInfo.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-namespace MediaBrowser.Controller.Providers
-{
- public class GameSystemInfo : ItemLookupInfo
- {
- /// <summary>
- /// Gets or sets the path.
- /// </summary>
- /// <value>The path.</value>
- public string Path { get; set; }
- }
-}
diff --git a/MediaBrowser.Controller/Session/SessionInfo.cs b/MediaBrowser.Controller/Session/SessionInfo.cs
index d698795dd..f0e81e8e7 100644
--- a/MediaBrowser.Controller/Session/SessionInfo.cs
+++ b/MediaBrowser.Controller/Session/SessionInfo.cs
@@ -1,10 +1,10 @@
using System;
using System.Linq;
+using System.Threading;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Serialization;
using MediaBrowser.Model.Session;
-using MediaBrowser.Model.Threading;
using Microsoft.Extensions.Logging;
namespace MediaBrowser.Controller.Session
@@ -268,10 +268,10 @@ namespace MediaBrowser.Controller.Session
}
private readonly object _progressLock = new object();
- private ITimer _progressTimer;
+ private Timer _progressTimer;
private PlaybackProgressInfo _lastProgressInfo;
- public void StartAutomaticProgress(ITimerFactory timerFactory, PlaybackProgressInfo progressInfo)
+ public void StartAutomaticProgress(PlaybackProgressInfo progressInfo)
{
if (_disposed)
{
@@ -284,7 +284,7 @@ namespace MediaBrowser.Controller.Session
if (_progressTimer == null)
{
- _progressTimer = timerFactory.Create(OnProgressTimerCallback, null, 1000, 1000);
+ _progressTimer = new Timer(OnProgressTimerCallback, null, 1000, 1000);
}
else
{
diff --git a/MediaBrowser.LocalMetadata/Images/LocalImageProvider.cs b/MediaBrowser.LocalMetadata/Images/LocalImageProvider.cs
index 0a4928ed7..1a7654bfd 100644
--- a/MediaBrowser.LocalMetadata/Images/LocalImageProvider.cs
+++ b/MediaBrowser.LocalMetadata/Images/LocalImageProvider.cs
@@ -128,7 +128,6 @@ namespace MediaBrowser.LocalMetadata.Images
var added = false;
var isEpisode = item is Episode;
var isSong = item.GetType() == typeof(Audio);
- var isGame = item is Game;
var isPerson = item is Person;
// Logo
@@ -157,7 +156,7 @@ namespace MediaBrowser.LocalMetadata.Images
added = AddImage(files, images, "disc", imagePrefix, isInMixedFolder, ImageType.Disc);
}
}
- else if (isGame || item is Video || item is BoxSet)
+ else if (item is Video || item is BoxSet)
{
added = AddImage(files, images, "disc", imagePrefix, isInMixedFolder, ImageType.Disc);
@@ -172,19 +171,6 @@ namespace MediaBrowser.LocalMetadata.Images
}
}
- if (isGame)
- {
- AddImage(files, images, "box", imagePrefix, isInMixedFolder, ImageType.Box);
- AddImage(files, images, "menu", imagePrefix, isInMixedFolder, ImageType.Menu);
-
- added = AddImage(files, images, "back", imagePrefix, isInMixedFolder, ImageType.BoxRear);
-
- if (!added)
- {
- added = AddImage(files, images, "boxrear", imagePrefix, isInMixedFolder, ImageType.BoxRear);
- }
- }
-
// Banner
if (!isEpisode && !isSong && !isPerson)
{
@@ -417,7 +403,7 @@ namespace MediaBrowser.LocalMetadata.Images
var seriesFiles = GetFiles(series, false, directoryService).ToList();
// Try using the season name
- var prefix = season.Name.ToLower().Replace(" ", string.Empty);
+ var prefix = season.Name.ToLowerInvariant().Replace(" ", string.Empty);
var filenamePrefixes = new List<string> { prefix };
diff --git a/MediaBrowser.LocalMetadata/Parsers/GameSystemXmlParser.cs b/MediaBrowser.LocalMetadata/Parsers/GameSystemXmlParser.cs
deleted file mode 100644
index a4997270f..000000000
--- a/MediaBrowser.LocalMetadata/Parsers/GameSystemXmlParser.cs
+++ /dev/null
@@ -1,66 +0,0 @@
-using System.Threading;
-using System.Threading.Tasks;
-using System.Xml;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Providers;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Model.Xml;
-using Microsoft.Extensions.Logging;
-
-namespace MediaBrowser.LocalMetadata.Parsers
-{
- public class GameSystemXmlParser : BaseItemXmlParser<GameSystem>
- {
- public Task FetchAsync(MetadataResult<GameSystem> item, string metadataFile, CancellationToken cancellationToken)
- {
- Fetch(item, metadataFile, cancellationToken);
-
- cancellationToken.ThrowIfCancellationRequested();
-
- return Task.CompletedTask;
- }
-
- /// <summary>
- /// Fetches the data from XML node.
- /// </summary>
- /// <param name="reader">The reader.</param>
- /// <param name="result">The result.</param>
- protected override void FetchDataFromXmlNode(XmlReader reader, MetadataResult<GameSystem> result)
- {
- var item = result.Item;
-
- switch (reader.Name)
- {
- case "GameSystem":
- {
- var val = reader.ReadElementContentAsString();
- if (!string.IsNullOrWhiteSpace(val))
- {
- item.GameSystemName = val;
- }
- break;
- }
-
- case "GamesDbId":
- {
- var val = reader.ReadElementContentAsString();
- if (!string.IsNullOrWhiteSpace(val))
- {
- item.SetProviderId(MetadataProviders.Gamesdb, val);
- }
- break;
- }
-
-
- default:
- base.FetchDataFromXmlNode(reader, result);
- break;
- }
- }
-
- public GameSystemXmlParser(ILogger logger, IProviderManager providerManager, IXmlReaderSettingsFactory xmlReaderSettingsFactory, IFileSystem fileSystem) : base(logger, providerManager, xmlReaderSettingsFactory, fileSystem)
- {
- }
- }
-}
diff --git a/MediaBrowser.LocalMetadata/Parsers/GameXmlParser.cs b/MediaBrowser.LocalMetadata/Parsers/GameXmlParser.cs
deleted file mode 100644
index df7c51f27..000000000
--- a/MediaBrowser.LocalMetadata/Parsers/GameXmlParser.cs
+++ /dev/null
@@ -1,85 +0,0 @@
-using System.Globalization;
-using System.Threading;
-using System.Threading.Tasks;
-using System.Xml;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Providers;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Model.Xml;
-using Microsoft.Extensions.Logging;
-
-namespace MediaBrowser.LocalMetadata.Parsers
-{
- /// <summary>
- /// Class EpisodeXmlParser
- /// </summary>
- public class GameXmlParser : BaseItemXmlParser<Game>
- {
- private readonly CultureInfo _usCulture = new CultureInfo("en-US");
-
- public Task FetchAsync(MetadataResult<Game> item, string metadataFile, CancellationToken cancellationToken)
- {
- Fetch(item, metadataFile, cancellationToken);
-
- cancellationToken.ThrowIfCancellationRequested();
-
- return Task.CompletedTask;
- }
-
- /// <summary>
- /// Fetches the data from XML node.
- /// </summary>
- /// <param name="reader">The reader.</param>
- /// <param name="result">The result.</param>
- protected override void FetchDataFromXmlNode(XmlReader reader, MetadataResult<Game> result)
- {
- var item = result.Item;
-
- switch (reader.Name)
- {
- case "GameSystem":
- {
- var val = reader.ReadElementContentAsString();
- if (!string.IsNullOrWhiteSpace(val))
- {
- item.GameSystem = val;
- }
- break;
- }
-
- case "GamesDbId":
- {
- var val = reader.ReadElementContentAsString();
- if (!string.IsNullOrWhiteSpace(val))
- {
- item.SetProviderId(MetadataProviders.Gamesdb, val);
- }
- break;
- }
-
- case "Players":
- {
- var val = reader.ReadElementContentAsString();
- if (!string.IsNullOrWhiteSpace(val))
- {
- if (int.TryParse(val, NumberStyles.Integer, _usCulture, out var num))
- {
- item.PlayersSupported = num;
- }
- }
- break;
- }
-
-
- default:
- base.FetchDataFromXmlNode(reader, result);
- break;
- }
- }
-
- public GameXmlParser(ILogger logger, IProviderManager providerManager, IXmlReaderSettingsFactory xmlReaderSettingsFactory, IFileSystem fileSystem) : base(logger, providerManager, xmlReaderSettingsFactory, fileSystem)
- {
- }
- }
-}
diff --git a/MediaBrowser.LocalMetadata/Providers/GameSystemXmlProvider.cs b/MediaBrowser.LocalMetadata/Providers/GameSystemXmlProvider.cs
deleted file mode 100644
index 62f31d4fa..000000000
--- a/MediaBrowser.LocalMetadata/Providers/GameSystemXmlProvider.cs
+++ /dev/null
@@ -1,36 +0,0 @@
-using System.IO;
-using System.Threading;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Providers;
-using MediaBrowser.LocalMetadata.Parsers;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Model.Xml;
-using Microsoft.Extensions.Logging;
-
-namespace MediaBrowser.LocalMetadata.Providers
-{
- public class GameSystemXmlProvider : BaseXmlProvider<GameSystem>
- {
- private readonly ILogger _logger;
- private readonly IProviderManager _providerManager;
- private readonly IXmlReaderSettingsFactory _xmlSettings;
-
- public GameSystemXmlProvider(IFileSystem fileSystem, ILogger logger, IProviderManager providerManager, IXmlReaderSettingsFactory xmlSettings)
- : base(fileSystem)
- {
- _logger = logger;
- _providerManager = providerManager;
- _xmlSettings = xmlSettings;
- }
-
- protected override void Fetch(MetadataResult<GameSystem> result, string path, CancellationToken cancellationToken)
- {
- new GameSystemXmlParser(_logger, _providerManager, _xmlSettings, FileSystem).Fetch(result, path, cancellationToken);
- }
-
- protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService)
- {
- return directoryService.GetFile(Path.Combine(info.Path, "gamesystem.xml"));
- }
- }
-}
diff --git a/MediaBrowser.LocalMetadata/Providers/GameXmlProvider.cs b/MediaBrowser.LocalMetadata/Providers/GameXmlProvider.cs
deleted file mode 100644
index acdbb0a29..000000000
--- a/MediaBrowser.LocalMetadata/Providers/GameXmlProvider.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-using System.IO;
-using System.Threading;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Providers;
-using MediaBrowser.LocalMetadata.Parsers;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Model.Xml;
-using Microsoft.Extensions.Logging;
-
-namespace MediaBrowser.LocalMetadata.Providers
-{
- public class GameXmlProvider : BaseXmlProvider<Game>
- {
- private readonly ILogger _logger;
- private readonly IProviderManager _providerManager;
- private readonly IXmlReaderSettingsFactory _xmlSettings;
-
- public GameXmlProvider(IFileSystem fileSystem, ILogger logger, IProviderManager providerManager, IXmlReaderSettingsFactory xmlSettings)
- : base(fileSystem)
- {
- _logger = logger;
- _providerManager = providerManager;
- _xmlSettings = xmlSettings;
- }
-
- protected override void Fetch(MetadataResult<Game> result, string path, CancellationToken cancellationToken)
- {
- new GameXmlParser(_logger, _providerManager, _xmlSettings, FileSystem).Fetch(result, path, cancellationToken);
- }
-
- protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService)
- {
- var specificFile = Path.ChangeExtension(info.Path, ".xml");
- var file = FileSystem.GetFileInfo(specificFile);
-
- return info.IsInMixedFolder || file.Exists ? file : FileSystem.GetFileInfo(Path.Combine(Path.GetDirectoryName(info.Path), "game.xml"));
- }
- }
-}
diff --git a/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs b/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs
index 8a291e6a8..438b84252 100644
--- a/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs
+++ b/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs
@@ -172,7 +172,7 @@ namespace MediaBrowser.LocalMetadata.Savers
writer.WriteElementString("Added", item.DateCreated.ToLocalTime().ToString("G"));
- writer.WriteElementString("LockData", item.IsLocked.ToString().ToLower());
+ writer.WriteElementString("LockData", item.IsLocked.ToString(CultureInfo.InvariantCulture).ToLowerInvariant());
if (item.LockedFields.Length > 0)
{
@@ -410,7 +410,9 @@ namespace MediaBrowser.LocalMetadata.Savers
writer.WriteStartElement("Share");
writer.WriteElementString("UserId", share.UserId);
- writer.WriteElementString("CanEdit", share.CanEdit.ToString().ToLower());
+ writer.WriteElementString(
+ "CanEdit",
+ share.CanEdit.ToString(CultureInfo.InvariantCulture).ToLowerInvariant());
writer.WriteEndElement();
}
diff --git a/MediaBrowser.LocalMetadata/Savers/GameSystemXmlSaver.cs b/MediaBrowser.LocalMetadata/Savers/GameSystemXmlSaver.cs
deleted file mode 100644
index cf123171a..000000000
--- a/MediaBrowser.LocalMetadata/Savers/GameSystemXmlSaver.cs
+++ /dev/null
@@ -1,48 +0,0 @@
-using System.IO;
-using System.Xml;
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Model.Xml;
-using Microsoft.Extensions.Logging;
-
-namespace MediaBrowser.LocalMetadata.Savers
-{
- public class GameSystemXmlSaver : BaseXmlSaver
- {
- public GameSystemXmlSaver(IFileSystem fileSystem, IServerConfigurationManager configurationManager, ILibraryManager libraryManager, IUserManager userManager, IUserDataManager userDataManager, ILogger logger, IXmlReaderSettingsFactory xmlReaderSettingsFactory) : base(fileSystem, configurationManager, libraryManager, userManager, userDataManager, logger, xmlReaderSettingsFactory)
- {
- }
-
- public override bool IsEnabledFor(BaseItem item, ItemUpdateType updateType)
- {
- if (!item.SupportsLocalMetadata)
- {
- return false;
- }
-
- return item is GameSystem && updateType >= ItemUpdateType.MetadataDownload;
- }
-
- protected override void WriteCustomElements(BaseItem item, XmlWriter writer)
- {
- var gameSystem = (GameSystem)item;
-
- if (!string.IsNullOrEmpty(gameSystem.GameSystemName))
- {
- writer.WriteElementString("GameSystem", gameSystem.GameSystemName);
- }
- }
-
- protected override string GetLocalSavePath(BaseItem item)
- {
- return Path.Combine(item.Path, "gamesystem.xml");
- }
-
- protected override string GetRootElementName(BaseItem item)
- {
- return "Item";
- }
- }
-}
diff --git a/MediaBrowser.LocalMetadata/Savers/GameXmlSaver.cs b/MediaBrowser.LocalMetadata/Savers/GameXmlSaver.cs
deleted file mode 100644
index 3b7929618..000000000
--- a/MediaBrowser.LocalMetadata/Savers/GameXmlSaver.cs
+++ /dev/null
@@ -1,68 +0,0 @@
-using System.Globalization;
-using System.IO;
-using System.Xml;
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Model.Xml;
-using Microsoft.Extensions.Logging;
-
-namespace MediaBrowser.LocalMetadata.Savers
-{
- /// <summary>
- /// Saves game.xml for games
- /// </summary>
- public class GameXmlSaver : BaseXmlSaver
- {
- private readonly CultureInfo UsCulture = new CultureInfo("en-US");
-
- public override bool IsEnabledFor(BaseItem item, ItemUpdateType updateType)
- {
- if (!item.SupportsLocalMetadata)
- {
- return false;
- }
-
- return item is Game && updateType >= ItemUpdateType.MetadataDownload;
- }
-
- protected override void WriteCustomElements(BaseItem item, XmlWriter writer)
- {
- var game = (Game)item;
-
- if (!string.IsNullOrEmpty(game.GameSystem))
- {
- writer.WriteElementString("GameSystem", game.GameSystem);
- }
- if (game.PlayersSupported.HasValue)
- {
- writer.WriteElementString("Players", game.PlayersSupported.Value.ToString(UsCulture));
- }
- }
-
- protected override string GetLocalSavePath(BaseItem item)
- {
- return GetGameSavePath((Game)item);
- }
-
- protected override string GetRootElementName(BaseItem item)
- {
- return "Item";
- }
-
- public static string GetGameSavePath(Game item)
- {
- if (item.IsInMixedFolder)
- {
- return Path.ChangeExtension(item.Path, ".xml");
- }
-
- return Path.Combine(item.ContainingFolderPath, "game.xml");
- }
-
- public GameXmlSaver(IFileSystem fileSystem, IServerConfigurationManager configurationManager, ILibraryManager libraryManager, IUserManager userManager, IUserDataManager userDataManager, ILogger logger, IXmlReaderSettingsFactory xmlReaderSettingsFactory) : base(fileSystem, configurationManager, libraryManager, userManager, userDataManager, logger, xmlReaderSettingsFactory)
- {
- }
- }
-}
diff --git a/MediaBrowser.LocalMetadata/Savers/PersonXmlSaver.cs b/MediaBrowser.LocalMetadata/Savers/PersonXmlSaver.cs
deleted file mode 100644
index 7dd2c589f..000000000
--- a/MediaBrowser.LocalMetadata/Savers/PersonXmlSaver.cs
+++ /dev/null
@@ -1,47 +0,0 @@
-namespace MediaBrowser.LocalMetadata.Savers
-{
- ///// <summary>
- ///// Class PersonXmlSaver
- ///// </summary>
- //public class PersonXmlSaver : BaseXmlSaver
- //{
- // public override bool IsEnabledFor(IHasMetadata item, ItemUpdateType updateType)
- // {
- // if (!item.SupportsLocalMetadata)
- // {
- // return false;
- // }
-
- // return item is Person && updateType >= ItemUpdateType.MetadataDownload;
- // }
-
- // protected override List<string> GetTagsUsed()
- // {
- // var list = new List<string>
- // {
- // "PlaceOfBirth"
- // };
-
- // return list;
- // }
-
- // protected override void WriteCustomElements(IHasMetadata item, XmlWriter writer)
- // {
- // var person = (Person)item;
-
- // if (person.ProductionLocations.Count > 0)
- // {
- // writer.WriteElementString("PlaceOfBirth", person.ProductionLocations[0]);
- // }
- // }
-
- // protected override string GetLocalSavePath(IHasMetadata item)
- // {
- // return Path.Combine(item.Path, "person.xml");
- // }
-
- // public PersonXmlSaver(IFileSystem fileSystem, IServerConfigurationManager configurationManager, ILibraryManager libraryManager, IUserManager userManager, IUserDataManager userDataManager, ILogger logger, IXmlReaderSettingsFactory xmlReaderSettingsFactory) : base(fileSystem, configurationManager, libraryManager, userManager, userDataManager, logger, xmlReaderSettingsFactory)
- // {
- // }
- //}
-}
diff --git a/MediaBrowser.MediaEncoding/Encoder/AudioEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/AudioEncoder.cs
deleted file mode 100644
index d5773fe31..000000000
--- a/MediaBrowser.MediaEncoding/Encoder/AudioEncoder.cs
+++ /dev/null
@@ -1,58 +0,0 @@
-using System;
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.MediaEncoding;
-using MediaBrowser.Controller.Session;
-using MediaBrowser.Model.Diagnostics;
-using MediaBrowser.Model.IO;
-using Microsoft.Extensions.Logging;
-
-namespace MediaBrowser.MediaEncoding.Encoder
-{
- public class AudioEncoder : BaseEncoder
- {
- public AudioEncoder(MediaEncoder mediaEncoder, ILogger logger, IServerConfigurationManager configurationManager, IFileSystem fileSystem, IIsoManager isoManager, ILibraryManager libraryManager, ISessionManager sessionManager, ISubtitleEncoder subtitleEncoder, IMediaSourceManager mediaSourceManager, IProcessFactory processFactory) : base(mediaEncoder, logger, configurationManager, fileSystem, isoManager, libraryManager, sessionManager, subtitleEncoder, mediaSourceManager, processFactory)
- {
- }
-
- protected override string GetCommandLineArguments(EncodingJob state)
- {
- var encodingOptions = GetEncodingOptions();
-
- return EncodingHelper.GetProgressiveAudioFullCommandLine(state, encodingOptions, state.OutputFilePath);
- }
-
- protected override string GetOutputFileExtension(EncodingJob state)
- {
- var ext = base.GetOutputFileExtension(state);
-
- if (!string.IsNullOrEmpty(ext))
- {
- return ext;
- }
-
- var audioCodec = state.Options.AudioCodec;
-
- if (string.Equals("aac", audioCodec, StringComparison.OrdinalIgnoreCase))
- {
- return ".aac";
- }
- if (string.Equals("mp3", audioCodec, StringComparison.OrdinalIgnoreCase))
- {
- return ".mp3";
- }
- if (string.Equals("vorbis", audioCodec, StringComparison.OrdinalIgnoreCase))
- {
- return ".ogg";
- }
- if (string.Equals("wma", audioCodec, StringComparison.OrdinalIgnoreCase))
- {
- return ".wma";
- }
-
- return null;
- }
-
- protected override bool IsVideoEncoder => false;
- }
-}
diff --git a/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs
deleted file mode 100644
index d3c44f5eb..000000000
--- a/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs
+++ /dev/null
@@ -1,372 +0,0 @@
-using System;
-using System.Globalization;
-using System.IO;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Common.Configuration;
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.MediaEncoding;
-using MediaBrowser.Controller.Session;
-using MediaBrowser.Model.Configuration;
-using MediaBrowser.Model.Diagnostics;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Model.MediaInfo;
-using Microsoft.Extensions.Logging;
-
-namespace MediaBrowser.MediaEncoding.Encoder
-{
- public abstract class BaseEncoder
- {
- protected readonly MediaEncoder MediaEncoder;
- protected readonly ILogger Logger;
- protected readonly IServerConfigurationManager ConfigurationManager;
- protected readonly IFileSystem FileSystem;
- protected readonly IIsoManager IsoManager;
- protected readonly ILibraryManager LibraryManager;
- protected readonly ISessionManager SessionManager;
- protected readonly ISubtitleEncoder SubtitleEncoder;
- protected readonly IMediaSourceManager MediaSourceManager;
- protected IProcessFactory ProcessFactory;
-
- protected readonly CultureInfo UsCulture = new CultureInfo("en-US");
-
- protected EncodingHelper EncodingHelper;
-
- protected BaseEncoder(MediaEncoder mediaEncoder,
- ILogger logger,
- IServerConfigurationManager configurationManager,
- IFileSystem fileSystem,
- IIsoManager isoManager,
- ILibraryManager libraryManager,
- ISessionManager sessionManager,
- ISubtitleEncoder subtitleEncoder,
- IMediaSourceManager mediaSourceManager, IProcessFactory processFactory)
- {
- MediaEncoder = mediaEncoder;
- Logger = logger;
- ConfigurationManager = configurationManager;
- FileSystem = fileSystem;
- IsoManager = isoManager;
- LibraryManager = libraryManager;
- SessionManager = sessionManager;
- SubtitleEncoder = subtitleEncoder;
- MediaSourceManager = mediaSourceManager;
- ProcessFactory = processFactory;
-
- EncodingHelper = new EncodingHelper(MediaEncoder, FileSystem, SubtitleEncoder);
- }
-
- public async Task<EncodingJob> Start(EncodingJobOptions options,
- IProgress<double> progress,
- CancellationToken cancellationToken)
- {
- var encodingJob = await new EncodingJobFactory(Logger, LibraryManager, MediaSourceManager, ConfigurationManager, MediaEncoder)
- .CreateJob(options, EncodingHelper, IsVideoEncoder, progress, cancellationToken).ConfigureAwait(false);
-
- encodingJob.OutputFilePath = GetOutputFilePath(encodingJob);
- Directory.CreateDirectory(Path.GetDirectoryName(encodingJob.OutputFilePath));
-
- encodingJob.ReadInputAtNativeFramerate = options.ReadInputAtNativeFramerate;
-
- await AcquireResources(encodingJob, cancellationToken).ConfigureAwait(false);
-
- var commandLineArgs = GetCommandLineArguments(encodingJob);
-
- var process = ProcessFactory.Create(new ProcessOptions
- {
- CreateNoWindow = true,
- UseShellExecute = false,
-
- // Must consume both stdout and stderr or deadlocks may occur
- //RedirectStandardOutput = true,
- RedirectStandardError = true,
- RedirectStandardInput = true,
-
- FileName = MediaEncoder.EncoderPath,
- Arguments = commandLineArgs,
-
- IsHidden = true,
- ErrorDialog = false,
- EnableRaisingEvents = true
- });
-
- var workingDirectory = GetWorkingDirectory(options);
- if (!string.IsNullOrWhiteSpace(workingDirectory))
- {
- process.StartInfo.WorkingDirectory = workingDirectory;
- }
-
- OnTranscodeBeginning(encodingJob);
-
- var commandLineLogMessage = process.StartInfo.FileName + " " + process.StartInfo.Arguments;
- Logger.LogInformation(commandLineLogMessage);
-
- var logFilePath = Path.Combine(ConfigurationManager.CommonApplicationPaths.LogDirectoryPath, "transcode-" + Guid.NewGuid() + ".txt");
- Directory.CreateDirectory(Path.GetDirectoryName(logFilePath));
-
- // FFMpeg writes debug/error info to stderr. This is useful when debugging so let's put it in the log directory.
- encodingJob.LogFileStream = FileSystem.GetFileStream(logFilePath, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read, true);
-
- var commandLineLogMessageBytes = Encoding.UTF8.GetBytes(commandLineLogMessage + Environment.NewLine + Environment.NewLine);
- await encodingJob.LogFileStream.WriteAsync(commandLineLogMessageBytes, 0, commandLineLogMessageBytes.Length, cancellationToken).ConfigureAwait(false);
-
- process.Exited += (sender, args) => OnFfMpegProcessExited(process, encodingJob);
-
- try
- {
- process.Start();
- }
- catch (Exception ex)
- {
- Logger.LogError(ex, "Error starting ffmpeg");
-
- OnTranscodeFailedToStart(encodingJob.OutputFilePath, encodingJob);
-
- throw;
- }
-
- cancellationToken.Register(() => Cancel(process, encodingJob));
-
- // MUST read both stdout and stderr asynchronously or a deadlock may occurr
- //process.BeginOutputReadLine();
-
- // Important - don't await the log task or we won't be able to kill ffmpeg when the user stops playback
- new JobLogger(Logger).StartStreamingLog(encodingJob, process.StandardError.BaseStream, encodingJob.LogFileStream);
-
- // Wait for the file to exist before proceeeding
- while (!File.Exists(encodingJob.OutputFilePath) && !encodingJob.HasExited)
- {
- await Task.Delay(100, cancellationToken).ConfigureAwait(false);
- }
-
- return encodingJob;
- }
-
- private void Cancel(IProcess process, EncodingJob job)
- {
- Logger.LogInformation("Killing ffmpeg process for {0}", job.OutputFilePath);
-
- //process.Kill();
- process.StandardInput.WriteLine("q");
-
- job.IsCancelled = true;
- }
-
- /// <summary>
- /// Processes the exited.
- /// </summary>
- /// <param name="process">The process.</param>
- /// <param name="job">The job.</param>
- private void OnFfMpegProcessExited(IProcess process, EncodingJob job)
- {
- job.HasExited = true;
-
- Logger.LogDebug("Disposing stream resources");
- job.Dispose();
-
- var isSuccesful = false;
-
- try
- {
- var exitCode = process.ExitCode;
- Logger.LogInformation("FFMpeg exited with code {0}", exitCode);
-
- isSuccesful = exitCode == 0;
- }
- catch (Exception ex)
- {
- Logger.LogError(ex, "FFMpeg exited with an error.");
- }
-
- if (isSuccesful && !job.IsCancelled)
- {
- job.TaskCompletionSource.TrySetResult(true);
- }
- else if (job.IsCancelled)
- {
- try
- {
- DeleteFiles(job);
- }
- catch
- {
- }
- try
- {
- job.TaskCompletionSource.TrySetException(new OperationCanceledException());
- }
- catch
- {
- }
- }
- else
- {
- try
- {
- DeleteFiles(job);
- }
- catch
- {
- }
- try
- {
- job.TaskCompletionSource.TrySetException(new Exception("Encoding failed"));
- }
- catch
- {
- }
- }
-
- // This causes on exited to be called twice:
- //try
- //{
- // // Dispose the process
- // process.Dispose();
- //}
- //catch (Exception ex)
- //{
- // Logger.LogError("Error disposing ffmpeg.", ex);
- //}
- }
-
- protected virtual void DeleteFiles(EncodingJob job)
- {
- FileSystem.DeleteFile(job.OutputFilePath);
- }
-
- private void OnTranscodeBeginning(EncodingJob job)
- {
- job.ReportTranscodingProgress(null, null, null, null, null);
- }
-
- private void OnTranscodeFailedToStart(string path, EncodingJob job)
- {
- if (!string.IsNullOrWhiteSpace(job.Options.DeviceId))
- {
- SessionManager.ClearTranscodingInfo(job.Options.DeviceId);
- }
- }
-
- protected abstract bool IsVideoEncoder { get; }
-
- protected virtual string GetWorkingDirectory(EncodingJobOptions options)
- {
- return null;
- }
-
- protected EncodingOptions GetEncodingOptions()
- {
- return ConfigurationManager.GetConfiguration<EncodingOptions>("encoding");
- }
-
- protected abstract string GetCommandLineArguments(EncodingJob job);
-
- private string GetOutputFilePath(EncodingJob state)
- {
- var folder = string.IsNullOrWhiteSpace(state.Options.TempDirectory) ?
- ConfigurationManager.ApplicationPaths.TranscodingTempPath :
- state.Options.TempDirectory;
-
- var outputFileExtension = GetOutputFileExtension(state);
-
- var filename = state.Id + (outputFileExtension ?? string.Empty).ToLower();
- return Path.Combine(folder, filename);
- }
-
- protected virtual string GetOutputFileExtension(EncodingJob state)
- {
- if (!string.IsNullOrWhiteSpace(state.Options.Container))
- {
- return "." + state.Options.Container;
- }
-
- return null;
- }
-
- /// <summary>
- /// Gets the name of the output video codec
- /// </summary>
- /// <param name="state">The state.</param>
- /// <returns>System.String.</returns>
- protected string GetVideoDecoder(EncodingJob state)
- {
- if (string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase))
- {
- return null;
- }
-
- // Only use alternative encoders for video files.
- // When using concat with folder rips, if the mfx session fails to initialize, ffmpeg will be stuck retrying and will not exit gracefully
- // Since transcoding of folder rips is expiremental anyway, it's not worth adding additional variables such as this.
- if (state.VideoType != VideoType.VideoFile)
- {
- return null;
- }
-
- if (state.VideoStream != null && !string.IsNullOrWhiteSpace(state.VideoStream.Codec))
- {
- if (string.Equals(GetEncodingOptions().HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase))
- {
- switch (state.MediaSource.VideoStream.Codec.ToLower())
- {
- case "avc":
- case "h264":
- if (MediaEncoder.SupportsDecoder("h264_qsv"))
- {
- // Seeing stalls and failures with decoding. Not worth it compared to encoding.
- return "-c:v h264_qsv ";
- }
- break;
- case "mpeg2video":
- if (MediaEncoder.SupportsDecoder("mpeg2_qsv"))
- {
- return "-c:v mpeg2_qsv ";
- }
- break;
- case "vc1":
- if (MediaEncoder.SupportsDecoder("vc1_qsv"))
- {
- return "-c:v vc1_qsv ";
- }
- break;
- }
- }
- }
-
- // leave blank so ffmpeg will decide
- return null;
- }
-
- private async Task AcquireResources(EncodingJob state, CancellationToken cancellationToken)
- {
- if (state.VideoType == VideoType.Iso && state.IsoType.HasValue && IsoManager.CanMount(state.MediaPath))
- {
- state.IsoMount = await IsoManager.Mount(state.MediaPath, cancellationToken).ConfigureAwait(false);
- }
-
- if (state.MediaSource.RequiresOpening && string.IsNullOrWhiteSpace(state.Options.LiveStreamId))
- {
- var liveStreamResponse = await MediaSourceManager.OpenLiveStream(new LiveStreamRequest
- {
- OpenToken = state.MediaSource.OpenToken
-
- }, cancellationToken).ConfigureAwait(false);
-
- EncodingHelper.AttachMediaSourceInfo(state, liveStreamResponse.MediaSource, null);
-
- if (state.IsVideoRequest)
- {
- EncodingHelper.TryStreamCopy(state);
- }
- }
-
- if (state.MediaSource.BufferMs.HasValue)
- {
- await Task.Delay(state.MediaSource.BufferMs.Value, cancellationToken).ConfigureAwait(false);
- }
- }
- }
-}
diff --git a/MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs b/MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs
deleted file mode 100644
index d4040cd31..000000000
--- a/MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs
+++ /dev/null
@@ -1,149 +0,0 @@
-using System;
-using System.IO;
-using System.Threading.Tasks;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.MediaEncoding;
-using MediaBrowser.Model.Dlna;
-using MediaBrowser.Model.Net;
-using Microsoft.Extensions.Logging;
-
-namespace MediaBrowser.MediaEncoding.Encoder
-{
- public class EncodingJob : EncodingJobInfo, IDisposable
- {
- public bool HasExited { get; internal set; }
- public bool IsCancelled { get; internal set; }
-
- public Stream LogFileStream { get; set; }
- public TaskCompletionSource<bool> TaskCompletionSource;
-
- public EncodingJobOptions Options
- {
- get => (EncodingJobOptions)BaseRequest;
- set => BaseRequest = value;
- }
-
- public Guid Id { get; set; }
-
- public bool EstimateContentLength { get; set; }
- public TranscodeSeekInfo TranscodeSeekInfo { get; set; }
-
- public string ItemType { get; set; }
-
- private readonly ILogger _logger;
- private readonly IMediaSourceManager _mediaSourceManager;
-
- public EncodingJob(ILogger logger, IMediaSourceManager mediaSourceManager) :
- base(TranscodingJobType.Progressive)
- {
- _logger = logger;
- _mediaSourceManager = mediaSourceManager;
- Id = Guid.NewGuid();
-
- _logger = logger;
- TaskCompletionSource = new TaskCompletionSource<bool>();
- }
-
- public override void Dispose()
- {
- DisposeLiveStream();
- DisposeLogStream();
- DisposeIsoMount();
- }
-
- private void DisposeLogStream()
- {
- if (LogFileStream != null)
- {
- try
- {
- LogFileStream.Dispose();
- }
- catch (Exception ex)
- {
- _logger.LogError(ex, "Error disposing log stream");
- }
-
- LogFileStream = null;
- }
- }
-
- private async void DisposeLiveStream()
- {
- if (MediaSource.RequiresClosing && string.IsNullOrWhiteSpace(Options.LiveStreamId) && !string.IsNullOrWhiteSpace(MediaSource.LiveStreamId))
- {
- try
- {
- await _mediaSourceManager.CloseLiveStream(MediaSource.LiveStreamId).ConfigureAwait(false);
- }
- catch (Exception ex)
- {
- _logger.LogError(ex, "Error closing media source");
- }
- }
- }
-
-
- private void DisposeIsoMount()
- {
- if (IsoMount != null)
- {
- try
- {
- IsoMount.Dispose();
- }
- catch (Exception ex)
- {
- _logger.LogError("Error disposing iso mount", ex);
- }
-
- IsoMount = null;
- }
- }
-
- public void ReportTranscodingProgress(TimeSpan? transcodingPosition, float? framerate, double? percentComplete, long? bytesTranscoded, int? bitRate)
- {
- var ticks = transcodingPosition.HasValue ? transcodingPosition.Value.Ticks : (long?)null;
-
- //job.Framerate = framerate;
-
- if (!percentComplete.HasValue && ticks.HasValue && RunTimeTicks.HasValue)
- {
- var pct = ticks.Value / RunTimeTicks.Value;
- percentComplete = pct * 100;
- }
-
- if (percentComplete.HasValue)
- {
- Progress.Report(percentComplete.Value);
- }
-
- /*
- job.TranscodingPositionTicks = ticks;
- job.BytesTranscoded = bytesTranscoded;
-
- var deviceId = Options.DeviceId;
-
- if (!string.IsNullOrWhiteSpace(deviceId))
- {
- var audioCodec = ActualOutputVideoCodec;
- var videoCodec = ActualOutputVideoCodec;
-
- SessionManager.ReportTranscodingInfo(deviceId, new TranscodingInfo
- {
- Bitrate = job.TotalOutputBitrate,
- AudioCodec = audioCodec,
- VideoCodec = videoCodec,
- Container = job.Options.OutputContainer,
- Framerate = framerate,
- CompletionPercentage = percentComplete,
- Width = job.OutputWidth,
- Height = job.OutputHeight,
- AudioChannels = job.OutputAudioChannels,
- IsAudioDirect = string.Equals(job.OutputAudioCodec, "copy", StringComparison.OrdinalIgnoreCase),
- IsVideoDirect = string.Equals(job.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase)
- });
- }*/
- }
- }
-}
diff --git a/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs b/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs
deleted file mode 100644
index 95454c447..000000000
--- a/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs
+++ /dev/null
@@ -1,307 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Common.Configuration;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.MediaEncoding;
-using MediaBrowser.Model.Configuration;
-using MediaBrowser.Model.Dlna;
-using MediaBrowser.Model.Entities;
-using Microsoft.Extensions.Logging;
-
-namespace MediaBrowser.MediaEncoding.Encoder
-{
- public class EncodingJobFactory
- {
- private readonly ILogger _logger;
- private readonly ILibraryManager _libraryManager;
- private readonly IMediaSourceManager _mediaSourceManager;
- private readonly IConfigurationManager _config;
- private readonly IMediaEncoder _mediaEncoder;
-
- protected static readonly CultureInfo UsCulture = new CultureInfo("en-US");
-
- public EncodingJobFactory(ILogger logger, ILibraryManager libraryManager, IMediaSourceManager mediaSourceManager, IConfigurationManager config, IMediaEncoder mediaEncoder)
- {
- _logger = logger;
- _libraryManager = libraryManager;
- _mediaSourceManager = mediaSourceManager;
- _config = config;
- _mediaEncoder = mediaEncoder;
- }
-
- public async Task<EncodingJob> CreateJob(EncodingJobOptions options, EncodingHelper encodingHelper, bool isVideoRequest, IProgress<double> progress, CancellationToken cancellationToken)
- {
- var request = options;
-
- if (string.IsNullOrEmpty(request.AudioCodec))
- {
- request.AudioCodec = InferAudioCodec(request.Container);
- }
-
- var state = new EncodingJob(_logger, _mediaSourceManager)
- {
- Options = options,
- IsVideoRequest = isVideoRequest,
- Progress = progress
- };
-
- if (!string.IsNullOrWhiteSpace(request.VideoCodec))
- {
- state.SupportedVideoCodecs = request.VideoCodec.Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).ToArray();
- request.VideoCodec = state.SupportedVideoCodecs.FirstOrDefault();
- }
-
- if (!string.IsNullOrWhiteSpace(request.AudioCodec))
- {
- state.SupportedAudioCodecs = request.AudioCodec.Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).ToArray();
- request.AudioCodec = state.SupportedAudioCodecs.FirstOrDefault();
- }
-
- if (!string.IsNullOrWhiteSpace(request.SubtitleCodec))
- {
- state.SupportedSubtitleCodecs = request.SubtitleCodec.Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).ToArray();
- request.SubtitleCodec = state.SupportedSubtitleCodecs.FirstOrDefault(i => _mediaEncoder.CanEncodeToSubtitleCodec(i))
- ?? state.SupportedSubtitleCodecs.FirstOrDefault();
- }
-
- var item = _libraryManager.GetItemById(request.Id);
- state.ItemType = item.GetType().Name;
-
- state.IsInputVideo = string.Equals(item.MediaType, MediaType.Video, StringComparison.OrdinalIgnoreCase);
-
- // TODO
- // var primaryImage = item.GetImageInfo(ImageType.Primary, 0) ??
- // item.Parents.Select(i => i.GetImageInfo(ImageType.Primary, 0)).FirstOrDefault(i => i != null);
-
- // if (primaryImage != null)
- // {
- // state.AlbumCoverPath = primaryImage.Path;
- // }
-
- // TODO network path substition useful ?
- var mediaSources = await _mediaSourceManager.GetPlayackMediaSources(item, null, true, true, cancellationToken).ConfigureAwait(false);
-
- var mediaSource = string.IsNullOrEmpty(request.MediaSourceId)
- ? mediaSources.First()
- : mediaSources.First(i => string.Equals(i.Id, request.MediaSourceId));
-
- var videoRequest = state.Options;
-
- encodingHelper.AttachMediaSourceInfo(state, mediaSource, null);
-
- //var container = Path.GetExtension(state.RequestedUrl);
-
- //if (string.IsNullOrEmpty(container))
- //{
- // container = request.Static ?
- // state.InputContainer :
- // (Path.GetExtension(GetOutputFilePath(state)) ?? string.Empty).TrimStart('.');
- //}
-
- //state.OutputContainer = (container ?? string.Empty).TrimStart('.');
-
- state.OutputAudioBitrate = encodingHelper.GetAudioBitrateParam(state.Options, state.AudioStream);
-
- state.OutputAudioCodec = state.Options.AudioCodec;
-
- state.OutputAudioChannels = encodingHelper.GetNumAudioChannelsParam(state, state.AudioStream, state.OutputAudioCodec);
-
- if (videoRequest != null)
- {
- state.OutputVideoCodec = state.Options.VideoCodec;
- state.OutputVideoBitrate = encodingHelper.GetVideoBitrateParamValue(state.Options, state.VideoStream, state.OutputVideoCodec);
-
- if (state.OutputVideoBitrate.HasValue)
- {
- var resolution = ResolutionNormalizer.Normalize(
- state.VideoStream == null ? (int?)null : state.VideoStream.BitRate,
- state.VideoStream == null ? (int?)null : state.VideoStream.Width,
- state.VideoStream == null ? (int?)null : state.VideoStream.Height,
- state.OutputVideoBitrate.Value,
- state.VideoStream == null ? null : state.VideoStream.Codec,
- state.OutputVideoCodec,
- videoRequest.MaxWidth,
- videoRequest.MaxHeight);
-
- videoRequest.MaxWidth = resolution.MaxWidth;
- videoRequest.MaxHeight = resolution.MaxHeight;
- }
- }
-
- ApplyDeviceProfileSettings(state);
-
- if (videoRequest != null)
- {
- encodingHelper.TryStreamCopy(state);
- }
-
- //state.OutputFilePath = GetOutputFilePath(state);
-
- return state;
- }
-
- protected EncodingOptions GetEncodingOptions()
- {
- return _config.GetConfiguration<EncodingOptions>("encoding");
- }
-
- /// <summary>
- /// Infers the video codec.
- /// </summary>
- /// <param name="container">The container.</param>
- /// <returns>System.Nullable{VideoCodecs}.</returns>
- private static string InferVideoCodec(string container)
- {
- var ext = "." + (container ?? string.Empty);
-
- if (string.Equals(ext, ".asf", StringComparison.OrdinalIgnoreCase))
- {
- return "wmv";
- }
- if (string.Equals(ext, ".webm", StringComparison.OrdinalIgnoreCase))
- {
- return "vpx";
- }
- if (string.Equals(ext, ".ogg", StringComparison.OrdinalIgnoreCase) || string.Equals(ext, ".ogv", StringComparison.OrdinalIgnoreCase))
- {
- return "theora";
- }
- if (string.Equals(ext, ".m3u8", StringComparison.OrdinalIgnoreCase) || string.Equals(ext, ".ts", StringComparison.OrdinalIgnoreCase))
- {
- return "h264";
- }
-
- return "copy";
- }
-
- private string InferAudioCodec(string container)
- {
- var ext = "." + (container ?? string.Empty);
-
- if (string.Equals(ext, ".mp3", StringComparison.OrdinalIgnoreCase))
- {
- return "mp3";
- }
- if (string.Equals(ext, ".aac", StringComparison.OrdinalIgnoreCase))
- {
- return "aac";
- }
- if (string.Equals(ext, ".wma", StringComparison.OrdinalIgnoreCase))
- {
- return "wma";
- }
- if (string.Equals(ext, ".ogg", StringComparison.OrdinalIgnoreCase))
- {
- return "vorbis";
- }
- if (string.Equals(ext, ".oga", StringComparison.OrdinalIgnoreCase))
- {
- return "vorbis";
- }
- if (string.Equals(ext, ".ogv", StringComparison.OrdinalIgnoreCase))
- {
- return "vorbis";
- }
- if (string.Equals(ext, ".webm", StringComparison.OrdinalIgnoreCase))
- {
- return "vorbis";
- }
- if (string.Equals(ext, ".webma", StringComparison.OrdinalIgnoreCase))
- {
- return "vorbis";
- }
-
- return "copy";
- }
-
- /// <summary>
- /// Determines whether the specified stream is H264.
- /// </summary>
- /// <param name="stream">The stream.</param>
- /// <returns><c>true</c> if the specified stream is H264; otherwise, <c>false</c>.</returns>
- protected bool IsH264(MediaStream stream)
- {
- var codec = stream.Codec ?? string.Empty;
-
- return codec.IndexOf("264", StringComparison.OrdinalIgnoreCase) != -1 ||
- codec.IndexOf("avc", StringComparison.OrdinalIgnoreCase) != -1;
- }
-
- private static int GetVideoProfileScore(string profile)
- {
- var list = new List<string>
- {
- "Constrained Baseline",
- "Baseline",
- "Extended",
- "Main",
- "High",
- "Progressive High",
- "Constrained High"
- };
-
- return Array.FindIndex(list.ToArray(), t => string.Equals(t, profile, StringComparison.OrdinalIgnoreCase));
- }
-
- private void ApplyDeviceProfileSettings(EncodingJob state)
- {
- var profile = state.Options.DeviceProfile;
-
- if (profile == null)
- {
- // Don't use settings from the default profile.
- // Only use a specific profile if it was requested.
- return;
- }
-
- var audioCodec = state.ActualOutputAudioCodec;
-
- var videoCodec = state.ActualOutputVideoCodec;
- var outputContainer = state.Options.Container;
-
- var mediaProfile = state.IsVideoRequest ?
- profile.GetAudioMediaProfile(outputContainer, audioCodec, state.OutputAudioChannels, state.OutputAudioBitrate, state.OutputAudioSampleRate, state.OutputAudioBitDepth) :
- profile.GetVideoMediaProfile(outputContainer,
- audioCodec,
- videoCodec,
- state.OutputWidth,
- state.OutputHeight,
- state.TargetVideoBitDepth,
- state.OutputVideoBitrate,
- state.TargetVideoProfile,
- state.TargetVideoLevel,
- state.TargetFramerate,
- state.TargetPacketLength,
- state.TargetTimestamp,
- state.IsTargetAnamorphic,
- state.IsTargetInterlaced,
- state.TargetRefFrames,
- state.TargetVideoStreamCount,
- state.TargetAudioStreamCount,
- state.TargetVideoCodecTag,
- state.IsTargetAVC);
-
- if (mediaProfile != null)
- {
- state.MimeType = mediaProfile.MimeType;
- }
-
- var transcodingProfile = state.IsVideoRequest ?
- profile.GetAudioTranscodingProfile(outputContainer, audioCodec) :
- profile.GetVideoTranscodingProfile(outputContainer, audioCodec, videoCodec);
-
- if (transcodingProfile != null)
- {
- state.EstimateContentLength = transcodingProfile.EstimateContentLength;
- //state.EnableMpegtsM2TsMode = transcodingProfile.EnableMpegtsM2TsMode;
- state.TranscodeSeekInfo = transcodingProfile.TranscodeSeekInfo;
-
- state.Options.CopyTimestamps = transcodingProfile.CopyTimestamps;
- }
- }
- }
-}
diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
index 54344424d..d922f1068 100644
--- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
+++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
@@ -878,49 +878,6 @@ namespace MediaBrowser.MediaEncoding.Encoder
}
}
- public async Task<string> EncodeAudio(EncodingJobOptions options,
- IProgress<double> progress,
- CancellationToken cancellationToken)
- {
- var job = await new AudioEncoder(this,
- _logger,
- ConfigurationManager,
- FileSystem,
- IsoManager,
- LibraryManager,
- SessionManager,
- SubtitleEncoder(),
- MediaSourceManager(),
- _processFactory)
- .Start(options, progress, cancellationToken).ConfigureAwait(false);
-
- await job.TaskCompletionSource.Task.ConfigureAwait(false);
-
- return job.OutputFilePath;
- }
-
- public async Task<string> EncodeVideo(EncodingJobOptions options,
- IProgress<double> progress,
- CancellationToken cancellationToken)
- {
- _logger.LogError("EncodeVideo");
- var job = await new VideoEncoder(this,
- _logger,
- ConfigurationManager,
- FileSystem,
- IsoManager,
- LibraryManager,
- SessionManager,
- SubtitleEncoder(),
- MediaSourceManager(),
- _processFactory)
- .Start(options, progress, cancellationToken).ConfigureAwait(false);
-
- await job.TaskCompletionSource.Task.ConfigureAwait(false);
-
- return job.OutputFilePath;
- }
-
private void StartProcess(ProcessWrapper process)
{
process.Process.Start();
diff --git a/MediaBrowser.MediaEncoding/Encoder/VideoEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/VideoEncoder.cs
deleted file mode 100644
index bf23a73bd..000000000
--- a/MediaBrowser.MediaEncoding/Encoder/VideoEncoder.cs
+++ /dev/null
@@ -1,59 +0,0 @@
-using System;
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.MediaEncoding;
-using MediaBrowser.Controller.Session;
-using MediaBrowser.Model.Diagnostics;
-using MediaBrowser.Model.IO;
-using Microsoft.Extensions.Logging;
-
-namespace MediaBrowser.MediaEncoding.Encoder
-{
- public class VideoEncoder : BaseEncoder
- {
- public VideoEncoder(MediaEncoder mediaEncoder, ILogger logger, IServerConfigurationManager configurationManager, IFileSystem fileSystem, IIsoManager isoManager, ILibraryManager libraryManager, ISessionManager sessionManager, ISubtitleEncoder subtitleEncoder, IMediaSourceManager mediaSourceManager, IProcessFactory processFactory) : base(mediaEncoder, logger, configurationManager, fileSystem, isoManager, libraryManager, sessionManager, subtitleEncoder, mediaSourceManager, processFactory)
- {
- }
-
- protected override string GetCommandLineArguments(EncodingJob state)
- {
- // Get the output codec name
- var encodingOptions = GetEncodingOptions();
-
- return EncodingHelper.GetProgressiveVideoFullCommandLine(state, encodingOptions, state.OutputFilePath, "superfast");
- }
-
- protected override string GetOutputFileExtension(EncodingJob state)
- {
- var ext = base.GetOutputFileExtension(state);
-
- if (!string.IsNullOrEmpty(ext))
- {
- return ext;
- }
-
- var videoCodec = state.Options.VideoCodec;
-
- if (string.Equals(videoCodec, "h264", StringComparison.OrdinalIgnoreCase))
- {
- return ".ts";
- }
- if (string.Equals(videoCodec, "theora", StringComparison.OrdinalIgnoreCase))
- {
- return ".ogv";
- }
- if (string.Equals(videoCodec, "vpx", StringComparison.OrdinalIgnoreCase))
- {
- return ".webm";
- }
- if (string.Equals(videoCodec, "wmv", StringComparison.OrdinalIgnoreCase))
- {
- return ".asf";
- }
-
- return null;
- }
-
- protected override bool IsVideoEncoder => true;
- }
-}
diff --git a/MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs b/MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs
index 2c18a02ef..0d696b906 100644
--- a/MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs
+++ b/MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs
@@ -44,7 +44,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
if (!eventsStarted)
header.AppendLine(line);
- if (line.Trim().ToLower() == "[events]")
+ if (line.Trim().ToLowerInvariant() == "[events]")
{
eventsStarted = true;
}
@@ -54,25 +54,25 @@ namespace MediaBrowser.MediaEncoding.Subtitles
}
else if (eventsStarted && line.Trim().Length > 0)
{
- string s = line.Trim().ToLower();
+ string s = line.Trim().ToLowerInvariant();
if (s.StartsWith("format:"))
{
if (line.Length > 10)
{
- format = line.ToLower().Substring(8).Split(',');
+ format = line.ToLowerInvariant().Substring(8).Split(',');
for (int i = 0; i < format.Length; i++)
{
- if (format[i].Trim().ToLower() == "layer")
+ if (format[i].Trim().ToLowerInvariant() == "layer")
indexLayer = i;
- else if (format[i].Trim().ToLower() == "start")
+ else if (format[i].Trim().ToLowerInvariant() == "start")
indexStart = i;
- else if (format[i].Trim().ToLower() == "end")
+ else if (format[i].Trim().ToLowerInvariant() == "end")
indexEnd = i;
- else if (format[i].Trim().ToLower() == "text")
+ else if (format[i].Trim().ToLowerInvariant() == "text")
indexText = i;
- else if (format[i].Trim().ToLower() == "effect")
+ else if (format[i].Trim().ToLowerInvariant() == "effect")
indexEffect = i;
- else if (format[i].Trim().ToLower() == "style")
+ else if (format[i].Trim().ToLowerInvariant() == "style")
indexStyle = i;
}
}
@@ -222,7 +222,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
// switch to rrggbb from bbggrr
color = "#" + color.Remove(color.Length - 6) + color.Substring(color.Length - 2, 2) + color.Substring(color.Length - 4, 2) + color.Substring(color.Length - 6, 2);
- color = color.ToLower();
+ color = color.ToLowerInvariant();
text = text.Remove(start, end - start + 1);
if (italic)
@@ -252,7 +252,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
// switch to rrggbb from bbggrr
color = "#" + color.Remove(color.Length - 6) + color.Substring(color.Length - 2, 2) + color.Substring(color.Length - 4, 2) + color.Substring(color.Length - 6, 2);
- color = color.ToLower();
+ color = color.ToLowerInvariant();
text = text.Remove(start, end - start + 1);
if (italic)
@@ -367,7 +367,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
color = color.PadLeft(6, '0');
// switch to rrggbb from bbggrr
color = "#" + color.Remove(color.Length - 6) + color.Substring(color.Length - 2, 2) + color.Substring(color.Length - 4, 2) + color.Substring(color.Length - 6, 2);
- color = color.ToLower();
+ color = color.ToLowerInvariant();
extraTags += " color=\"" + color + "\"";
}
diff --git a/MediaBrowser.Model/Channels/ChannelMediaContentType.cs b/MediaBrowser.Model/Channels/ChannelMediaContentType.cs
index 010ff8048..fc7c21706 100644
--- a/MediaBrowser.Model/Channels/ChannelMediaContentType.cs
+++ b/MediaBrowser.Model/Channels/ChannelMediaContentType.cs
@@ -16,8 +16,6 @@ namespace MediaBrowser.Model.Channels
MovieExtra = 6,
- TvExtra = 7,
-
- GameExtra = 8
+ TvExtra = 7
}
}
diff --git a/MediaBrowser.Model/Configuration/UnratedItem.cs b/MediaBrowser.Model/Configuration/UnratedItem.cs
index 2d0bce47f..107b4e520 100644
--- a/MediaBrowser.Model/Configuration/UnratedItem.cs
+++ b/MediaBrowser.Model/Configuration/UnratedItem.cs
@@ -6,7 +6,6 @@ namespace MediaBrowser.Model.Configuration
Trailer,
Series,
Music,
- Game,
Book,
LiveTvChannel,
LiveTvProgram,
diff --git a/MediaBrowser.Model/Connect/ConnectAuthorization.cs b/MediaBrowser.Model/Connect/ConnectAuthorization.cs
deleted file mode 100644
index cdb3172d9..000000000
--- a/MediaBrowser.Model/Connect/ConnectAuthorization.cs
+++ /dev/null
@@ -1,21 +0,0 @@
-using System;
-
-namespace MediaBrowser.Model.Connect
-{
- public class ConnectAuthorization
- {
- public string ConnectUserId { get; set; }
- public string UserName { get; set; }
- public string ImageUrl { get; set; }
- public string Id { get; set; }
- public string[] EnabledLibraries { get; set; }
- public bool EnableLiveTv { get; set; }
- public string[] EnabledChannels { get; set; }
-
- public ConnectAuthorization()
- {
- EnabledLibraries = Array.Empty<string>();
- EnabledChannels = Array.Empty<string>();
- }
- }
-}
diff --git a/MediaBrowser.Model/Connect/ConnectUser.cs b/MediaBrowser.Model/Connect/ConnectUser.cs
deleted file mode 100644
index 4c536c6b0..000000000
--- a/MediaBrowser.Model/Connect/ConnectUser.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-namespace MediaBrowser.Model.Connect
-{
- public class ConnectUser
- {
- public string Id { get; set; }
- public string Name { get; set; }
- public string Email { get; set; }
- public bool IsActive { get; set; }
- public string ImageUrl { get; set; }
- }
-}
diff --git a/MediaBrowser.Model/Connect/ConnectUserQuery.cs b/MediaBrowser.Model/Connect/ConnectUserQuery.cs
deleted file mode 100644
index 4f04934d6..000000000
--- a/MediaBrowser.Model/Connect/ConnectUserQuery.cs
+++ /dev/null
@@ -1,10 +0,0 @@
-namespace MediaBrowser.Model.Connect
-{
- public class ConnectUserQuery
- {
- public string Id { get; set; }
- public string Name { get; set; }
- public string Email { get; set; }
- public string NameOrEmail { get; set; }
- }
-}
diff --git a/MediaBrowser.Model/Connect/UserLinkType.cs b/MediaBrowser.Model/Connect/UserLinkType.cs
deleted file mode 100644
index 19b4b67e6..000000000
--- a/MediaBrowser.Model/Connect/UserLinkType.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-namespace MediaBrowser.Model.Connect
-{
- public enum UserLinkType
- {
- /// <summary>
- /// The linked user
- /// </summary>
- LinkedUser = 0,
- /// <summary>
- /// The guest
- /// </summary>
- Guest = 1
- }
-}
diff --git a/MediaBrowser.Model/Dlna/StreamInfo.cs b/MediaBrowser.Model/Dlna/StreamInfo.cs
index 6d03a03b0..10efb9b38 100644
--- a/MediaBrowser.Model/Dlna/StreamInfo.cs
+++ b/MediaBrowser.Model/Dlna/StreamInfo.cs
@@ -223,7 +223,7 @@ namespace MediaBrowser.Model.Dlna
list.Add(new NameValuePair("DeviceProfileId", item.DeviceProfileId ?? string.Empty));
list.Add(new NameValuePair("DeviceId", item.DeviceId ?? string.Empty));
list.Add(new NameValuePair("MediaSourceId", item.MediaSourceId ?? string.Empty));
- list.Add(new NameValuePair("Static", item.IsDirectStream.ToString().ToLower()));
+ list.Add(new NameValuePair("Static", item.IsDirectStream.ToString(CultureInfo.InvariantCulture).ToLowerInvariant()));
list.Add(new NameValuePair("VideoCodec", videoCodecs));
list.Add(new NameValuePair("AudioCodec", audioCodecs));
list.Add(new NameValuePair("AudioStreamIndex", item.AudioStreamIndex.HasValue ? item.AudioStreamIndex.Value.ToString(CultureInfo.InvariantCulture) : string.Empty));
@@ -251,7 +251,7 @@ namespace MediaBrowser.Model.Dlna
list.Add(new NameValuePair("PlaySessionId", item.PlaySessionId ?? string.Empty));
list.Add(new NameValuePair("api_key", accessToken ?? string.Empty));
- string liveStreamId = item.MediaSource == null ? null : item.MediaSource.LiveStreamId;
+ string liveStreamId = item.MediaSource?.LiveStreamId;
list.Add(new NameValuePair("LiveStreamId", liveStreamId ?? string.Empty));
list.Add(new NameValuePair("SubtitleMethod", item.SubtitleStreamIndex.HasValue && item.SubtitleDeliveryMethod != SubtitleDeliveryMethod.External ? item.SubtitleDeliveryMethod.ToString() : string.Empty));
@@ -261,37 +261,37 @@ namespace MediaBrowser.Model.Dlna
{
if (item.RequireNonAnamorphic)
{
- list.Add(new NameValuePair("RequireNonAnamorphic", item.RequireNonAnamorphic.ToString().ToLower()));
+ list.Add(new NameValuePair("RequireNonAnamorphic", item.RequireNonAnamorphic.ToString(CultureInfo.InvariantCulture).ToLowerInvariant()));
}
list.Add(new NameValuePair("TranscodingMaxAudioChannels", item.TranscodingMaxAudioChannels.HasValue ? item.TranscodingMaxAudioChannels.Value.ToString(CultureInfo.InvariantCulture) : string.Empty));
if (item.EnableSubtitlesInManifest)
{
- list.Add(new NameValuePair("EnableSubtitlesInManifest", item.EnableSubtitlesInManifest.ToString().ToLower()));
+ list.Add(new NameValuePair("EnableSubtitlesInManifest", item.EnableSubtitlesInManifest.ToString(CultureInfo.InvariantCulture).ToLowerInvariant()));
}
if (item.EnableMpegtsM2TsMode)
{
- list.Add(new NameValuePair("EnableMpegtsM2TsMode", item.EnableMpegtsM2TsMode.ToString().ToLower()));
+ list.Add(new NameValuePair("EnableMpegtsM2TsMode", item.EnableMpegtsM2TsMode.ToString(CultureInfo.InvariantCulture).ToLowerInvariant()));
}
if (item.EstimateContentLength)
{
- list.Add(new NameValuePair("EstimateContentLength", item.EstimateContentLength.ToString().ToLower()));
+ list.Add(new NameValuePair("EstimateContentLength", item.EstimateContentLength.ToString(CultureInfo.InvariantCulture).ToLowerInvariant()));
}
if (item.TranscodeSeekInfo != TranscodeSeekInfo.Auto)
{
- list.Add(new NameValuePair("TranscodeSeekInfo", item.TranscodeSeekInfo.ToString().ToLower()));
+ list.Add(new NameValuePair("TranscodeSeekInfo", item.TranscodeSeekInfo.ToString().ToLowerInvariant()));
}
if (item.CopyTimestamps)
{
- list.Add(new NameValuePair("CopyTimestamps", item.CopyTimestamps.ToString().ToLower()));
+ list.Add(new NameValuePair("CopyTimestamps", item.CopyTimestamps.ToString(CultureInfo.InvariantCulture).ToLowerInvariant()));
}
- list.Add(new NameValuePair("RequireAvc", item.RequireAvc.ToString().ToLower()));
+ list.Add(new NameValuePair("RequireAvc", item.RequireAvc.ToString(CultureInfo.InvariantCulture).ToLowerInvariant()));
}
list.Add(new NameValuePair("Tag", item.MediaSource.ETag ?? string.Empty));
@@ -316,7 +316,7 @@ namespace MediaBrowser.Model.Dlna
list.Add(new NameValuePair("MinSegments", item.MinSegments.Value.ToString(CultureInfo.InvariantCulture)));
}
- list.Add(new NameValuePair("BreakOnNonKeyFrames", item.BreakOnNonKeyFrames.ToString()));
+ list.Add(new NameValuePair("BreakOnNonKeyFrames", item.BreakOnNonKeyFrames.ToString(CultureInfo.InvariantCulture)));
}
foreach (var pair in item.StreamOptions)
@@ -332,7 +332,7 @@ namespace MediaBrowser.Model.Dlna
if (!item.IsDirectStream)
{
- list.Add(new NameValuePair("TranscodeReasons", string.Join(",", item.TranscodeReasons.Distinct().Select(i => i.ToString()).ToArray())));
+ list.Add(new NameValuePair("TranscodeReasons", string.Join(",", item.TranscodeReasons.Distinct().Select(i => i.ToString()))));
}
return list;
diff --git a/MediaBrowser.Model/Drawing/ImageSize.cs b/MediaBrowser.Model/Drawing/ImageDimensions.cs
index 75591d83d..e7805ac49 100644
--- a/MediaBrowser.Model/Drawing/ImageSize.cs
+++ b/MediaBrowser.Model/Drawing/ImageDimensions.cs
@@ -1,7 +1,7 @@
namespace MediaBrowser.Model.Drawing
{
/// <summary>
- /// Struct ImageSize
+ /// Struct ImageDimensions
/// </summary>
public struct ImageDimensions
{
diff --git a/MediaBrowser.Model/Dto/BaseItemDto.cs b/MediaBrowser.Model/Dto/BaseItemDto.cs
index 3e267a39d..b382d9d4a 100644
--- a/MediaBrowser.Model/Dto/BaseItemDto.cs
+++ b/MediaBrowser.Model/Dto/BaseItemDto.cs
@@ -116,16 +116,8 @@ namespace MediaBrowser.Model.Dto
/// <value>The critic rating.</value>
public float? CriticRating { get; set; }
- /// <summary>
- /// Gets or sets the game system.
- /// </summary>
- /// <value>The game system.</value>
- public string GameSystem { get; set; }
-
public string[] ProductionLocations { get; set; }
- public string[] MultiPartGameFiles { get; set; }
-
/// <summary>
/// Gets or sets the path.
/// </summary>
@@ -604,11 +596,6 @@ namespace MediaBrowser.Model.Dto
/// <value>The episode count.</value>
public int? EpisodeCount { get; set; }
/// <summary>
- /// Gets or sets the game count.
- /// </summary>
- /// <value>The game count.</value>
- public int? GameCount { get; set; }
- /// <summary>
/// Gets or sets the song count.
/// </summary>
/// <value>The song count.</value>
diff --git a/MediaBrowser.Model/Dto/GameSystemSummary.cs b/MediaBrowser.Model/Dto/GameSystemSummary.cs
deleted file mode 100644
index e2400a744..000000000
--- a/MediaBrowser.Model/Dto/GameSystemSummary.cs
+++ /dev/null
@@ -1,48 +0,0 @@
-using System;
-
-namespace MediaBrowser.Model.Dto
-{
- /// <summary>
- /// Class GameSystemSummary
- /// </summary>
- public class GameSystemSummary
- {
- /// <summary>
- /// Gets or sets the name.
- /// </summary>
- /// <value>The name.</value>
- public string Name { get; set; }
-
- /// <summary>
- /// Gets or sets the name.
- /// </summary>
- /// <value>The name.</value>
- public string DisplayName { get; set; }
-
- /// <summary>
- /// Gets or sets the game count.
- /// </summary>
- /// <value>The game count.</value>
- public int GameCount { get; set; }
-
- /// <summary>
- /// Gets or sets the game extensions.
- /// </summary>
- /// <value>The game extensions.</value>
- public string[] GameFileExtensions { get; set; }
-
- /// <summary>
- /// Gets or sets the client installed game count.
- /// </summary>
- /// <value>The client installed game count.</value>
- public int ClientInstalledGameCount { get; set; }
-
- /// <summary>
- /// Initializes a new instance of the <see cref="GameSystemSummary"/> class.
- /// </summary>
- public GameSystemSummary()
- {
- GameFileExtensions = Array.Empty<string>();
- }
- }
-}
diff --git a/MediaBrowser.Model/Dto/ItemCounts.cs b/MediaBrowser.Model/Dto/ItemCounts.cs
index da941d258..ec5adab85 100644
--- a/MediaBrowser.Model/Dto/ItemCounts.cs
+++ b/MediaBrowser.Model/Dto/ItemCounts.cs
@@ -20,19 +20,9 @@ namespace MediaBrowser.Model.Dto
/// </summary>
/// <value>The episode count.</value>
public int EpisodeCount { get; set; }
- /// <summary>
- /// Gets or sets the game count.
- /// </summary>
- /// <value>The game count.</value>
- public int GameCount { get; set; }
public int ArtistCount { get; set; }
public int ProgramCount { get; set; }
/// <summary>
- /// Gets or sets the game system count.
- /// </summary>
- /// <value>The game system count.</value>
- public int GameSystemCount { get; set; }
- /// <summary>
/// Gets or sets the trailer count.
/// </summary>
/// <value>The trailer count.</value>
diff --git a/MediaBrowser.Model/Dto/UserDto.cs b/MediaBrowser.Model/Dto/UserDto.cs
index b00f5919f..13da018a6 100644
--- a/MediaBrowser.Model/Dto/UserDto.cs
+++ b/MediaBrowser.Model/Dto/UserDto.cs
@@ -1,6 +1,5 @@
using System;
using MediaBrowser.Model.Configuration;
-using MediaBrowser.Model.Connect;
using MediaBrowser.Model.Users;
namespace MediaBrowser.Model.Dto
@@ -30,22 +29,6 @@ namespace MediaBrowser.Model.Dto
public string ServerName { get; set; }
/// <summary>
- /// Gets or sets the name of the connect user.
- /// </summary>
- /// <value>The name of the connect user.</value>
- public string ConnectUserName { get; set; }
- /// <summary>
- /// Gets or sets the connect user identifier.
- /// </summary>
- /// <value>The connect user identifier.</value>
- public string ConnectUserId { get; set; }
- /// <summary>
- /// Gets or sets the type of the connect link.
- /// </summary>
- /// <value>The type of the connect link.</value>
- public UserLinkType? ConnectLinkType { get; set; }
-
- /// <summary>
/// Gets or sets the id.
/// </summary>
/// <value>The id.</value>
diff --git a/MediaBrowser.Model/Entities/CollectionType.cs b/MediaBrowser.Model/Entities/CollectionType.cs
index bda166118..e26d1b8c3 100644
--- a/MediaBrowser.Model/Entities/CollectionType.cs
+++ b/MediaBrowser.Model/Entities/CollectionType.cs
@@ -18,7 +18,6 @@ namespace MediaBrowser.Model.Entities
public const string Books = "books";
public const string Photos = "photos";
- public const string Games = "games";
public const string LiveTv = "livetv";
public const string Playlists = "playlists";
public const string Folders = "folders";
diff --git a/MediaBrowser.Model/Entities/MediaStream.cs b/MediaBrowser.Model/Entities/MediaStream.cs
index e0c3bead1..fc346df37 100644
--- a/MediaBrowser.Model/Entities/MediaStream.cs
+++ b/MediaBrowser.Model/Entities/MediaStream.cs
@@ -104,7 +104,7 @@ namespace MediaBrowser.Model.Entities
attributes.Add("Default");
}
- return string.Join(" ", attributes.ToArray());
+ return string.Join(" ", attributes);
}
if (Type == MediaStreamType.Video)
@@ -120,10 +120,10 @@ namespace MediaBrowser.Model.Entities
if (!string.IsNullOrEmpty(Codec))
{
- attributes.Add(Codec.ToUpper());
+ attributes.Add(Codec.ToUpperInvariant());
}
- return string.Join(" ", attributes.ToArray());
+ return string.Join(" ", attributes);
}
if (Type == MediaStreamType.Subtitle)
diff --git a/MediaBrowser.Model/Entities/MediaType.cs b/MediaBrowser.Model/Entities/MediaType.cs
index af233e61e..c56c8f8f2 100644
--- a/MediaBrowser.Model/Entities/MediaType.cs
+++ b/MediaBrowser.Model/Entities/MediaType.cs
@@ -14,10 +14,6 @@ namespace MediaBrowser.Model.Entities
/// </summary>
public const string Audio = "Audio";
/// <summary>
- /// The game
- /// </summary>
- public const string Game = "Game";
- /// <summary>
/// The photo
/// </summary>
public const string Photo = "Photo";
diff --git a/MediaBrowser.Model/Entities/MetadataProviders.cs b/MediaBrowser.Model/Entities/MetadataProviders.cs
index 399961603..e9802cf46 100644
--- a/MediaBrowser.Model/Entities/MetadataProviders.cs
+++ b/MediaBrowser.Model/Entities/MetadataProviders.cs
@@ -5,7 +5,6 @@ namespace MediaBrowser.Model.Entities
/// </summary>
public enum MetadataProviders
{
- Gamesdb = 1,
/// <summary>
/// The imdb
/// </summary>
diff --git a/MediaBrowser.Model/Extensions/LinqExtensions.cs b/MediaBrowser.Model/Extensions/LinqExtensions.cs
deleted file mode 100644
index f0febf1d0..000000000
--- a/MediaBrowser.Model/Extensions/LinqExtensions.cs
+++ /dev/null
@@ -1,85 +0,0 @@
-using System;
-using System.Collections.Generic;
-
-// TODO: @bond Remove
-namespace MediaBrowser.Model.Extensions
-{
- // MoreLINQ - Extensions to LINQ to Objects
- // Copyright (c) 2008 Jonathan Skeet. All rights reserved.
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
-
- public static class LinqExtensions
- {
- /// <summary>
- /// Returns all distinct elements of the given source, where "distinctness"
- /// is determined via a projection and the default equality comparer for the projected type.
- /// </summary>
- /// <remarks>
- /// This operator uses deferred execution and streams the results, although
- /// a set of already-seen keys is retained. If a key is seen multiple times,
- /// only the first element with that key is returned.
- /// </remarks>
- /// <typeparam name="TSource">Type of the source sequence</typeparam>
- /// <typeparam name="TKey">Type of the projected element</typeparam>
- /// <param name="source">Source sequence</param>
- /// <param name="keySelector">Projection for determining "distinctness"</param>
- /// <returns>A sequence consisting of distinct elements from the source sequence,
- /// comparing them by the specified key projection.</returns>
-
- public static IEnumerable<TSource> DistinctBy<TSource, TKey>(this IEnumerable<TSource> source,
- Func<TSource, TKey> keySelector)
- {
- return source.DistinctBy(keySelector, null);
- }
-
- /// <summary>
- /// Returns all distinct elements of the given source, where "distinctness"
- /// is determined via a projection and the specified comparer for the projected type.
- /// </summary>
- /// <remarks>
- /// This operator uses deferred execution and streams the results, although
- /// a set of already-seen keys is retained. If a key is seen multiple times,
- /// only the first element with that key is returned.
- /// </remarks>
- /// <typeparam name="TSource">Type of the source sequence</typeparam>
- /// <typeparam name="TKey">Type of the projected element</typeparam>
- /// <param name="source">Source sequence</param>
- /// <param name="keySelector">Projection for determining "distinctness"</param>
- /// <param name="comparer">The equality comparer to use to determine whether or not keys are equal.
- /// If null, the default equality comparer for <c>TSource</c> is used.</param>
- /// <returns>A sequence consisting of distinct elements from the source sequence,
- /// comparing them by the specified key projection.</returns>
-
- public static IEnumerable<TSource> DistinctBy<TSource, TKey>(this IEnumerable<TSource> source,
- Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer)
- {
- if (source == null) throw new ArgumentNullException(nameof(source));
- if (keySelector == null) throw new ArgumentNullException(nameof(keySelector));
- return DistinctByImpl(source, keySelector, comparer);
- }
-
- private static IEnumerable<TSource> DistinctByImpl<TSource, TKey>(IEnumerable<TSource> source,
- Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer)
- {
- var knownKeys = new HashSet<TKey>(comparer);
- foreach (var element in source)
- {
- if (knownKeys.Add(keySelector(element)))
- {
- yield return element;
- }
- }
- }
- }
-}
diff --git a/MediaBrowser.Model/Extensions/StringHelper.cs b/MediaBrowser.Model/Extensions/StringHelper.cs
index 78e23e767..75ba12a17 100644
--- a/MediaBrowser.Model/Extensions/StringHelper.cs
+++ b/MediaBrowser.Model/Extensions/StringHelper.cs
@@ -51,7 +51,7 @@ namespace MediaBrowser.Model.Extensions
public static string FirstToUpper(this string str)
{
- return string.IsNullOrEmpty(str) ? "" : str.Substring(0, 1).ToUpper() + str.Substring(1);
+ return string.IsNullOrEmpty(str) ? string.Empty : str.Substring(0, 1).ToUpperInvariant() + str.Substring(1);
}
}
}
diff --git a/MediaBrowser.Model/Globalization/ILocalizationManager.cs b/MediaBrowser.Model/Globalization/ILocalizationManager.cs
index 05efb6681..a9ce60a2a 100644
--- a/MediaBrowser.Model/Globalization/ILocalizationManager.cs
+++ b/MediaBrowser.Model/Globalization/ILocalizationManager.cs
@@ -1,4 +1,6 @@
+using System.Collections.Generic;
using System.Globalization;
+using System.Threading.Tasks;
using MediaBrowser.Model.Entities;
namespace MediaBrowser.Model.Globalization
@@ -17,12 +19,12 @@ namespace MediaBrowser.Model.Globalization
/// Gets the countries.
/// </summary>
/// <returns>IEnumerable{CountryInfo}.</returns>
- CountryInfo[] GetCountries();
+ Task<CountryInfo[]> GetCountries();
/// <summary>
/// Gets the parental ratings.
/// </summary>
/// <returns>IEnumerable{ParentalRating}.</returns>
- ParentalRating[] GetParentalRatings();
+ IEnumerable<ParentalRating> GetParentalRatings();
/// <summary>
/// Gets the rating level.
/// </summary>
@@ -51,8 +53,6 @@ namespace MediaBrowser.Model.Globalization
/// <returns>IEnumerable{LocalizatonOption}.</returns>
LocalizationOption[] GetLocalizationOptions();
- string RemoveDiacritics(string text);
-
string NormalizeFormKD(string text);
bool HasUnicodeCategory(string value, UnicodeCategory category);
diff --git a/MediaBrowser.Model/MediaInfo/AudioCodec.cs b/MediaBrowser.Model/MediaInfo/AudioCodec.cs
index 5ed67fd78..5ebdb99cb 100644
--- a/MediaBrowser.Model/MediaInfo/AudioCodec.cs
+++ b/MediaBrowser.Model/MediaInfo/AudioCodec.cs
@@ -8,9 +8,12 @@ namespace MediaBrowser.Model.MediaInfo
public static string GetFriendlyName(string codec)
{
- if (string.IsNullOrEmpty(codec)) return "";
+ if (string.IsNullOrEmpty(codec))
+ {
+ return string.Empty;
+ }
- switch (codec.ToLower())
+ switch (codec.ToLowerInvariant())
{
case "ac3":
return "Dolby Digital";
@@ -19,7 +22,7 @@ namespace MediaBrowser.Model.MediaInfo
case "dca":
return "DTS";
default:
- return codec.ToUpper();
+ return codec.ToUpperInvariant();
}
}
}
diff --git a/MediaBrowser.Model/Net/MimeTypes.cs b/MediaBrowser.Model/Net/MimeTypes.cs
index fe13413e2..659abe84c 100644
--- a/MediaBrowser.Model/Net/MimeTypes.cs
+++ b/MediaBrowser.Model/Net/MimeTypes.cs
@@ -158,7 +158,7 @@ namespace MediaBrowser.Model.Net
// Catch-all for all video types that don't require specific mime types
if (VideoFileExtensionsDictionary.ContainsKey(ext))
{
- return "video/" + ext.TrimStart('.').ToLower();
+ return "video/" + ext.TrimStart('.').ToLowerInvariant();
}
// Type text
diff --git a/MediaBrowser.Model/Notifications/NotificationType.cs b/MediaBrowser.Model/Notifications/NotificationType.cs
index 9d16e4a16..38b519a14 100644
--- a/MediaBrowser.Model/Notifications/NotificationType.cs
+++ b/MediaBrowser.Model/Notifications/NotificationType.cs
@@ -5,10 +5,8 @@ namespace MediaBrowser.Model.Notifications
ApplicationUpdateAvailable,
ApplicationUpdateInstalled,
AudioPlayback,
- GamePlayback,
VideoPlayback,
AudioPlaybackStopped,
- GamePlaybackStopped,
VideoPlaybackStopped,
InstallationFailed,
PluginError,
diff --git a/MediaBrowser.Model/Providers/RemoteSearchResult.cs b/MediaBrowser.Model/Providers/RemoteSearchResult.cs
index 88e3bc69c..6e46b1556 100644
--- a/MediaBrowser.Model/Providers/RemoteSearchResult.cs
+++ b/MediaBrowser.Model/Providers/RemoteSearchResult.cs
@@ -30,8 +30,6 @@ namespace MediaBrowser.Model.Providers
public string ImageUrl { get; set; }
public string SearchProviderName { get; set; }
-
- public string GameSystem { get; set; }
public string Overview { get; set; }
public RemoteSearchResult AlbumArtist { get; set; }
diff --git a/MediaBrowser.Model/Querying/ItemSortBy.cs b/MediaBrowser.Model/Querying/ItemSortBy.cs
index 1b20f43ac..6a71e3bb3 100644
--- a/MediaBrowser.Model/Querying/ItemSortBy.cs
+++ b/MediaBrowser.Model/Querying/ItemSortBy.cs
@@ -71,8 +71,6 @@ namespace MediaBrowser.Model.Querying
public const string VideoBitRate = "VideoBitRate";
public const string AirTime = "AirTime";
public const string Studio = "Studio";
- public const string Players = "Players";
- public const string GameSystem = "GameSystem";
public const string IsFavoriteOrLiked = "IsFavoriteOrLiked";
public const string DateLastContentAdded = "DateLastContentAdded";
public const string SeriesDatePlayed = "SeriesDatePlayed";
diff --git a/MediaBrowser.Model/Threading/ITimer.cs b/MediaBrowser.Model/Threading/ITimer.cs
deleted file mode 100644
index 2bec22266..000000000
--- a/MediaBrowser.Model/Threading/ITimer.cs
+++ /dev/null
@@ -1,10 +0,0 @@
-using System;
-
-namespace MediaBrowser.Model.Threading
-{
- public interface ITimer : IDisposable
- {
- void Change(TimeSpan dueTime, TimeSpan period);
- void Change(int dueTimeMs, int periodMs);
- }
-}
diff --git a/MediaBrowser.Model/Threading/ITimerFactory.cs b/MediaBrowser.Model/Threading/ITimerFactory.cs
deleted file mode 100644
index 1161958a4..000000000
--- a/MediaBrowser.Model/Threading/ITimerFactory.cs
+++ /dev/null
@@ -1,10 +0,0 @@
-using System;
-
-namespace MediaBrowser.Model.Threading
-{
- public interface ITimerFactory
- {
- ITimer Create(Action<object> callback, object state, TimeSpan dueTime, TimeSpan period);
- ITimer Create(Action<object> callback, object state, int dueTimeMs, int periodMs);
- }
-}
diff --git a/MediaBrowser.Providers/GameGenres/GameGenreMetadataService.cs b/MediaBrowser.Providers/GameGenres/GameGenreMetadataService.cs
deleted file mode 100644
index 2034848de..000000000
--- a/MediaBrowser.Providers/GameGenres/GameGenreMetadataService.cs
+++ /dev/null
@@ -1,23 +0,0 @@
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.Providers;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Providers.Manager;
-using Microsoft.Extensions.Logging;
-
-namespace MediaBrowser.Providers.GameGenres
-{
- public class GameGenreMetadataService : MetadataService<GameGenre, ItemLookupInfo>
- {
- protected override void MergeData(MetadataResult<GameGenre> source, MetadataResult<GameGenre> target, MetadataFields[] lockedFields, bool replaceData, bool mergeMetadataSettings)
- {
- ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
- }
-
- public GameGenreMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, fileSystem, userDataManager, libraryManager)
- {
- }
- }
-}
diff --git a/MediaBrowser.Providers/Games/GameMetadataService.cs b/MediaBrowser.Providers/Games/GameMetadataService.cs
deleted file mode 100644
index 764394a21..000000000
--- a/MediaBrowser.Providers/Games/GameMetadataService.cs
+++ /dev/null
@@ -1,36 +0,0 @@
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.Providers;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Providers.Manager;
-using Microsoft.Extensions.Logging;
-
-namespace MediaBrowser.Providers.Games
-{
- public class GameMetadataService : MetadataService<Game, GameInfo>
- {
- protected override void MergeData(MetadataResult<Game> source, MetadataResult<Game> target, MetadataFields[] lockedFields, bool replaceData, bool mergeMetadataSettings)
- {
- ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
-
- var sourceItem = source.Item;
- var targetItem = target.Item;
-
- if (replaceData || string.IsNullOrEmpty(targetItem.GameSystem))
- {
- targetItem.GameSystem = sourceItem.GameSystem;
- }
-
- if (replaceData || !targetItem.PlayersSupported.HasValue)
- {
- targetItem.PlayersSupported = sourceItem.PlayersSupported;
- }
- }
-
- public GameMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, fileSystem, userDataManager, libraryManager)
- {
- }
- }
-}
diff --git a/MediaBrowser.Providers/Games/GameSystemMetadataService.cs b/MediaBrowser.Providers/Games/GameSystemMetadataService.cs
deleted file mode 100644
index 5bca4731c..000000000
--- a/MediaBrowser.Providers/Games/GameSystemMetadataService.cs
+++ /dev/null
@@ -1,31 +0,0 @@
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.Providers;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Providers.Manager;
-using Microsoft.Extensions.Logging;
-
-namespace MediaBrowser.Providers.Games
-{
- public class GameSystemMetadataService : MetadataService<GameSystem, GameSystemInfo>
- {
- protected override void MergeData(MetadataResult<GameSystem> source, MetadataResult<GameSystem> target, MetadataFields[] lockedFields, bool replaceData, bool mergeMetadataSettings)
- {
- ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
-
- var sourceItem = source.Item;
- var targetItem = target.Item;
-
- if (replaceData || string.IsNullOrEmpty(targetItem.GameSystemName))
- {
- targetItem.GameSystemName = sourceItem.GameSystemName;
- }
- }
-
- public GameSystemMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, fileSystem, userDataManager, libraryManager)
- {
- }
- }
-}
diff --git a/MediaBrowser.Providers/Manager/GenericPriorityQueue.cs b/MediaBrowser.Providers/Manager/GenericPriorityQueue.cs
index b87f688e1..10ff2515c 100644
--- a/MediaBrowser.Providers/Manager/GenericPriorityQueue.cs
+++ b/MediaBrowser.Providers/Manager/GenericPriorityQueue.cs
@@ -3,6 +3,7 @@ using System.Collections;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
+//TODO Fix namespace or replace
namespace Priority_Queue
{
/// <summary>
diff --git a/MediaBrowser.Providers/Manager/ImageSaver.cs b/MediaBrowser.Providers/Manager/ImageSaver.cs
index dee473374..ab906809f 100644
--- a/MediaBrowser.Providers/Manager/ImageSaver.cs
+++ b/MediaBrowser.Providers/Manager/ImageSaver.cs
@@ -420,7 +420,7 @@ namespace MediaBrowser.Providers.Manager
filename = GetBackdropSaveFilename(item.GetImages(type), "screenshot", "screenshot", imageIndex);
break;
default:
- filename = type.ToString().ToLower();
+ filename = type.ToString().ToLowerInvariant();
break;
}
@@ -429,7 +429,7 @@ namespace MediaBrowser.Providers.Manager
extension = ".jpg";
}
- extension = extension.ToLower();
+ extension = extension.ToLowerInvariant();
string path = null;
diff --git a/MediaBrowser.Providers/Manager/ItemImageProvider.cs b/MediaBrowser.Providers/Manager/ItemImageProvider.cs
index 493c97b6e..033aea146 100644
--- a/MediaBrowser.Providers/Manager/ItemImageProvider.cs
+++ b/MediaBrowser.Providers/Manager/ItemImageProvider.cs
@@ -148,7 +148,7 @@ namespace MediaBrowser.Providers.Manager
}
else
{
- var mimeType = "image/" + response.Format.ToString().ToLower();
+ var mimeType = "image/" + response.Format.ToString().ToLowerInvariant();
await _providerManager.SaveImage(item, response.Stream, mimeType, imageType, null, cancellationToken).ConfigureAwait(false);
}
diff --git a/MediaBrowser.Providers/Manager/MetadataService.cs b/MediaBrowser.Providers/Manager/MetadataService.cs
index 1972ad290..77028e526 100644
--- a/MediaBrowser.Providers/Manager/MetadataService.cs
+++ b/MediaBrowser.Providers/Manager/MetadataService.cs
@@ -566,8 +566,7 @@ namespace MediaBrowser.Providers.Manager
var providersWithChanges = providers
.Where(i =>
{
- var hasFileChangeMonitor = i as IHasItemChangeMonitor;
- if (hasFileChangeMonitor != null)
+ if (i is IHasItemChangeMonitor hasFileChangeMonitor)
{
return HasChanged(item, hasFileChangeMonitor, options.DirectoryService);
}
diff --git a/MediaBrowser.Providers/Manager/ProviderManager.cs b/MediaBrowser.Providers/Manager/ProviderManager.cs
index eda5163f0..f26087fda 100644
--- a/MediaBrowser.Providers/Manager/ProviderManager.cs
+++ b/MediaBrowser.Providers/Manager/ProviderManager.cs
@@ -471,8 +471,6 @@ namespace MediaBrowser.Providers.Manager
{
return new MetadataPluginSummary[]
{
- GetPluginSummary<Game>(),
- GetPluginSummary<GameSystem>(),
GetPluginSummary<Movie>(),
GetPluginSummary<BoxSet>(),
GetPluginSummary<Book>(),
diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs b/MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs
index afc760dd4..4e11fcbb2 100644
--- a/MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs
+++ b/MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs
@@ -74,17 +74,12 @@ namespace MediaBrowser.Providers.MediaInfo
}
}
- if (item.SupportsLocalMetadata)
+ if (item.SupportsLocalMetadata && video != null && !video.IsPlaceHolder
+ && !video.SubtitleFiles.SequenceEqual(
+ _subtitleResolver.GetExternalSubtitleFiles(video, directoryService, false), StringComparer.Ordinal))
{
- if (video != null && !video.IsPlaceHolder)
- {
- if (!video.SubtitleFiles
- .SequenceEqual(_subtitleResolver.GetExternalSubtitleFiles(video, directoryService, false), StringComparer.Ordinal))
- {
- _logger.LogDebug("Refreshing {0} due to external subtitles change.", item.Path);
- return true;
- }
- }
+ _logger.LogDebug("Refreshing {0} due to external subtitles change.", item.Path);
+ return true;
}
return false;
diff --git a/MediaBrowser.Providers/MediaInfo/SubtitleResolver.cs b/MediaBrowser.Providers/MediaInfo/SubtitleResolver.cs
index b6f862f9a..cd026b39b 100644
--- a/MediaBrowser.Providers/MediaInfo/SubtitleResolver.cs
+++ b/MediaBrowser.Providers/MediaInfo/SubtitleResolver.cs
@@ -119,7 +119,7 @@ namespace MediaBrowser.Providers.MediaInfo
continue;
}
- var codec = Path.GetExtension(fullName).ToLower().TrimStart('.');
+ var codec = Path.GetExtension(fullName).ToLowerInvariant().TrimStart('.');
if (string.Equals(codec, "txt", StringComparison.OrdinalIgnoreCase))
{
diff --git a/MediaBrowser.Providers/MediaInfo/SubtitleScheduledTask.cs b/MediaBrowser.Providers/MediaInfo/SubtitleScheduledTask.cs
index b7598ef22..74f41f9df 100644
--- a/MediaBrowser.Providers/MediaInfo/SubtitleScheduledTask.cs
+++ b/MediaBrowser.Providers/MediaInfo/SubtitleScheduledTask.cs
@@ -36,12 +36,6 @@ namespace MediaBrowser.Providers.MediaInfo
_json = json;
}
- public string Name => "Download missing subtitles";
-
- public string Description => "Searches the internet for missing subtitles based on metadata configuration.";
-
- public string Category => "Library";
-
private SubtitleOptions GetOptions()
{
return _config.GetConfiguration<SubtitleOptions>("subtitles");
@@ -204,6 +198,18 @@ namespace MediaBrowser.Providers.MediaInfo
};
}
+ public string Name => "Download missing subtitles";
+
+ public string Description => "Searches the internet for missing subtitles based on metadata configuration.";
+
+ public string Category => "Library";
+
public string Key => "DownloadSubtitles";
+
+ public bool IsHidden => false;
+
+ public bool IsEnabled => true;
+
+ public bool IsLogged => true;
}
}
diff --git a/MediaBrowser.Providers/Movies/FanartMovieImageProvider.cs b/MediaBrowser.Providers/Movies/FanartMovieImageProvider.cs
index 4a94bcb1a..70d187bf5 100644
--- a/MediaBrowser.Providers/Movies/FanartMovieImageProvider.cs
+++ b/MediaBrowser.Providers/Movies/FanartMovieImageProvider.cs
@@ -20,6 +20,7 @@ using MediaBrowser.Model.Providers;
using MediaBrowser.Model.Serialization;
using MediaBrowser.Providers.Music;
using MediaBrowser.Providers.TV;
+using MediaBrowser.Providers.TV.FanArt;
namespace MediaBrowser.Providers.Movies
{
diff --git a/MediaBrowser.Providers/Movies/MovieDbProvider.cs b/MediaBrowser.Providers/Movies/MovieDbProvider.cs
index c5af5ef36..3ff63a4bf 100644
--- a/MediaBrowser.Providers/Movies/MovieDbProvider.cs
+++ b/MediaBrowser.Providers/Movies/MovieDbProvider.cs
@@ -285,7 +285,7 @@ namespace MediaBrowser.Providers.Movies
if (parts.Length == 2)
{
- language = parts[0] + "-" + parts[1].ToUpper();
+ language = parts[0] + "-" + parts[1].ToUpperInvariant();
}
}
diff --git a/MediaBrowser.Providers/Movies/MovieDbSearch.cs b/MediaBrowser.Providers/Movies/MovieDbSearch.cs
index 47d3d21bd..e466d40a0 100644
--- a/MediaBrowser.Providers/Movies/MovieDbSearch.cs
+++ b/MediaBrowser.Providers/Movies/MovieDbSearch.cs
@@ -72,7 +72,7 @@ namespace MediaBrowser.Providers.Movies
}
_logger.LogInformation("MovieDbProvider: Finding id for item: " + name);
- var language = idInfo.MetadataLanguage.ToLower();
+ var language = idInfo.MetadataLanguage.ToLowerInvariant();
//nope - search for it
//var searchType = item is BoxSet ? "collection" : "movie";
diff --git a/MediaBrowser.Providers/Music/FanArtArtistProvider.cs b/MediaBrowser.Providers/Music/FanArtArtistProvider.cs
index 2efeb6985..75b4213c5 100644
--- a/MediaBrowser.Providers/Music/FanArtArtistProvider.cs
+++ b/MediaBrowser.Providers/Music/FanArtArtistProvider.cs
@@ -20,6 +20,7 @@ using MediaBrowser.Model.Net;
using MediaBrowser.Model.Providers;
using MediaBrowser.Model.Serialization;
using MediaBrowser.Providers.TV;
+using MediaBrowser.Providers.TV.FanArt;
namespace MediaBrowser.Providers.Music
{
diff --git a/MediaBrowser.Providers/People/TvdbPersonImageProvider.cs b/MediaBrowser.Providers/People/TvdbPersonImageProvider.cs
index cf2acdf49..181e88820 100644
--- a/MediaBrowser.Providers/People/TvdbPersonImageProvider.cs
+++ b/MediaBrowser.Providers/People/TvdbPersonImageProvider.cs
@@ -18,6 +18,7 @@ using MediaBrowser.Model.IO;
using MediaBrowser.Model.Providers;
using MediaBrowser.Model.Xml;
using MediaBrowser.Providers.TV;
+using MediaBrowser.Providers.TV.TheTVDB;
namespace MediaBrowser.Providers.People
{
diff --git a/MediaBrowser.Providers/Subtitles/SubtitleManager.cs b/MediaBrowser.Providers/Subtitles/SubtitleManager.cs
index e247c4f86..7fc6909f5 100644
--- a/MediaBrowser.Providers/Subtitles/SubtitleManager.cs
+++ b/MediaBrowser.Providers/Subtitles/SubtitleManager.cs
@@ -159,14 +159,14 @@ namespace MediaBrowser.Providers.Subtitles
memoryStream.Position = 0;
var savePaths = new List<string>();
- var saveFileName = Path.GetFileNameWithoutExtension(video.Path) + "." + response.Language.ToLower();
+ var saveFileName = Path.GetFileNameWithoutExtension(video.Path) + "." + response.Language.ToLowerInvariant();
if (response.IsForced)
{
saveFileName += ".forced";
}
- saveFileName += "." + response.Format.ToLower();
+ saveFileName += "." + response.Format.ToLowerInvariant();
if (saveInMediaFolder)
{
@@ -296,7 +296,7 @@ namespace MediaBrowser.Providers.Subtitles
private string GetProviderId(string name)
{
- return name.ToLower().GetMD5().ToString("N");
+ return name.ToLowerInvariant().GetMD5().ToString("N");
}
private ISubtitleProvider GetProvider(string id)
diff --git a/MediaBrowser.Providers/TV/FanArt/FanArtSeasonProvider.cs b/MediaBrowser.Providers/TV/FanArt/FanArtSeasonProvider.cs
index 493729446..58356910f 100644
--- a/MediaBrowser.Providers/TV/FanArt/FanArtSeasonProvider.cs
+++ b/MediaBrowser.Providers/TV/FanArt/FanArtSeasonProvider.cs
@@ -19,7 +19,7 @@ using MediaBrowser.Model.Net;
using MediaBrowser.Model.Providers;
using MediaBrowser.Model.Serialization;
-namespace MediaBrowser.Providers.TV
+namespace MediaBrowser.Providers.TV.FanArt
{
public class FanArtSeasonProvider : IRemoteImageProvider, IHasOrder
{
diff --git a/MediaBrowser.Providers/TV/FanArt/FanartSeriesProvider.cs b/MediaBrowser.Providers/TV/FanArt/FanartSeriesProvider.cs
index 172a7d2b8..49cd9596e 100644
--- a/MediaBrowser.Providers/TV/FanArt/FanartSeriesProvider.cs
+++ b/MediaBrowser.Providers/TV/FanArt/FanartSeriesProvider.cs
@@ -22,7 +22,7 @@ using MediaBrowser.Model.Providers;
using MediaBrowser.Model.Serialization;
using MediaBrowser.Providers.Music;
-namespace MediaBrowser.Providers.TV
+namespace MediaBrowser.Providers.TV.FanArt
{
public class FanartSeriesProvider : IRemoteImageProvider, IHasOrder
{
diff --git a/MediaBrowser.Providers/TV/MissingEpisodeProvider.cs b/MediaBrowser.Providers/TV/MissingEpisodeProvider.cs
index 4ac012399..25ad36620 100644
--- a/MediaBrowser.Providers/TV/MissingEpisodeProvider.cs
+++ b/MediaBrowser.Providers/TV/MissingEpisodeProvider.cs
@@ -16,6 +16,7 @@ using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Globalization;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Xml;
+using MediaBrowser.Providers.TV.TheTVDB;
using Microsoft.Extensions.Logging;
namespace MediaBrowser.Providers.TV
diff --git a/MediaBrowser.Providers/TV/Omdb/OmdbEpisodeProvider.cs b/MediaBrowser.Providers/TV/Omdb/OmdbEpisodeProvider.cs
index 6f7d9f791..d0749405b 100644
--- a/MediaBrowser.Providers/TV/Omdb/OmdbEpisodeProvider.cs
+++ b/MediaBrowser.Providers/TV/Omdb/OmdbEpisodeProvider.cs
@@ -14,7 +14,7 @@ using MediaBrowser.Model.Serialization;
using MediaBrowser.Providers.Omdb;
using Microsoft.Extensions.Logging;
-namespace MediaBrowser.Providers.TV
+namespace MediaBrowser.Providers.TV.Omdb
{
class OmdbEpisodeProvider :
IRemoteMetadataProvider<Episode, EpisodeInfo>,
diff --git a/MediaBrowser.Providers/TV/TheMovieDb/MovieDbEpisodeImageProvider.cs b/MediaBrowser.Providers/TV/TheMovieDb/MovieDbEpisodeImageProvider.cs
index 2482aa8d4..e4248afe1 100644
--- a/MediaBrowser.Providers/TV/TheMovieDb/MovieDbEpisodeImageProvider.cs
+++ b/MediaBrowser.Providers/TV/TheMovieDb/MovieDbEpisodeImageProvider.cs
@@ -16,7 +16,7 @@ using MediaBrowser.Model.Serialization;
using MediaBrowser.Providers.Movies;
using Microsoft.Extensions.Logging;
-namespace MediaBrowser.Providers.TV
+namespace MediaBrowser.Providers.TV.TheMovieDb
{
public class MovieDbEpisodeImageProvider :
MovieDbProviderBase,
diff --git a/MediaBrowser.Providers/TV/TheMovieDb/MovieDbEpisodeProvider.cs b/MediaBrowser.Providers/TV/TheMovieDb/MovieDbEpisodeProvider.cs
index 347c91742..44590515e 100644
--- a/MediaBrowser.Providers/TV/TheMovieDb/MovieDbEpisodeProvider.cs
+++ b/MediaBrowser.Providers/TV/TheMovieDb/MovieDbEpisodeProvider.cs
@@ -18,7 +18,7 @@ using MediaBrowser.Model.Providers;
using MediaBrowser.Model.Serialization;
using Microsoft.Extensions.Logging;
-namespace MediaBrowser.Providers.TV
+namespace MediaBrowser.Providers.TV.TheMovieDb
{
class MovieDbEpisodeProvider :
MovieDbProviderBase,
diff --git a/MediaBrowser.Providers/TV/TheMovieDb/MovieDbProviderBase.cs b/MediaBrowser.Providers/TV/TheMovieDb/MovieDbProviderBase.cs
index 9f1102946..6e438ebd8 100644
--- a/MediaBrowser.Providers/TV/TheMovieDb/MovieDbProviderBase.cs
+++ b/MediaBrowser.Providers/TV/TheMovieDb/MovieDbProviderBase.cs
@@ -12,7 +12,7 @@ using MediaBrowser.Model.Serialization;
using MediaBrowser.Providers.Movies;
using Microsoft.Extensions.Logging;
-namespace MediaBrowser.Providers.TV
+namespace MediaBrowser.Providers.TV.TheMovieDb
{
public abstract class MovieDbProviderBase
{
diff --git a/MediaBrowser.Providers/TV/TheMovieDb/MovieDbSeasonProvider.cs b/MediaBrowser.Providers/TV/TheMovieDb/MovieDbSeasonProvider.cs
index 790b38074..6be1b101d 100644
--- a/MediaBrowser.Providers/TV/TheMovieDb/MovieDbSeasonProvider.cs
+++ b/MediaBrowser.Providers/TV/TheMovieDb/MovieDbSeasonProvider.cs
@@ -18,7 +18,7 @@ using MediaBrowser.Model.Serialization;
using MediaBrowser.Providers.Movies;
using Microsoft.Extensions.Logging;
-namespace MediaBrowser.Providers.TV
+namespace MediaBrowser.Providers.TV.TheMovieDb
{
public class MovieDbSeasonProvider : IRemoteMetadataProvider<Season, SeasonInfo>
{
diff --git a/MediaBrowser.Providers/TV/TheMovieDb/MovieDbSeriesImageProvider.cs b/MediaBrowser.Providers/TV/TheMovieDb/MovieDbSeriesImageProvider.cs
index fdc8cd7f1..26686356f 100644
--- a/MediaBrowser.Providers/TV/TheMovieDb/MovieDbSeriesImageProvider.cs
+++ b/MediaBrowser.Providers/TV/TheMovieDb/MovieDbSeriesImageProvider.cs
@@ -14,7 +14,7 @@ using MediaBrowser.Model.Providers;
using MediaBrowser.Model.Serialization;
using MediaBrowser.Providers.Movies;
-namespace MediaBrowser.Providers.TV
+namespace MediaBrowser.Providers.TV.TheMovieDb
{
public class MovieDbSeriesImageProvider : IRemoteImageProvider, IHasOrder
{
diff --git a/MediaBrowser.Providers/TV/TheMovieDb/MovieDbSeriesProvider.cs b/MediaBrowser.Providers/TV/TheMovieDb/MovieDbSeriesProvider.cs
index 76031a7cd..b51fb6af8 100644
--- a/MediaBrowser.Providers/TV/TheMovieDb/MovieDbSeriesProvider.cs
+++ b/MediaBrowser.Providers/TV/TheMovieDb/MovieDbSeriesProvider.cs
@@ -20,7 +20,7 @@ using MediaBrowser.Model.Serialization;
using MediaBrowser.Providers.Movies;
using Microsoft.Extensions.Logging;
-namespace MediaBrowser.Providers.TV
+namespace MediaBrowser.Providers.TV.TheMovieDb
{
public class MovieDbSeriesProvider : IRemoteMetadataProvider<Series, SeriesInfo>, IHasOrder
{
diff --git a/MediaBrowser.Providers/TV/TheTVDB/TvdbEpisodeImageProvider.cs b/MediaBrowser.Providers/TV/TheTVDB/TvdbEpisodeImageProvider.cs
index 39d2fa77a..102a3d4ec 100644
--- a/MediaBrowser.Providers/TV/TheTVDB/TvdbEpisodeImageProvider.cs
+++ b/MediaBrowser.Providers/TV/TheTVDB/TvdbEpisodeImageProvider.cs
@@ -14,7 +14,7 @@ using MediaBrowser.Model.Entities;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Providers;
-namespace MediaBrowser.Providers.TV
+namespace MediaBrowser.Providers.TV.TheTVDB
{
public class TvdbEpisodeImageProvider : IRemoteImageProvider
{
diff --git a/MediaBrowser.Providers/TV/TheTVDB/TvdbEpisodeProvider.cs b/MediaBrowser.Providers/TV/TheTVDB/TvdbEpisodeProvider.cs
index 25fc214b5..be137e879 100644
--- a/MediaBrowser.Providers/TV/TheTVDB/TvdbEpisodeProvider.cs
+++ b/MediaBrowser.Providers/TV/TheTVDB/TvdbEpisodeProvider.cs
@@ -18,7 +18,7 @@ using MediaBrowser.Model.Providers;
using MediaBrowser.Model.Xml;
using Microsoft.Extensions.Logging;
-namespace MediaBrowser.Providers.TV
+namespace MediaBrowser.Providers.TV.TheTVDB
{
/// <summary>
diff --git a/MediaBrowser.Providers/TV/TheTVDB/TvdbPrescanTask.cs b/MediaBrowser.Providers/TV/TheTVDB/TvdbPrescanTask.cs
index 6f7cb72d3..d45696057 100644
--- a/MediaBrowser.Providers/TV/TheTVDB/TvdbPrescanTask.cs
+++ b/MediaBrowser.Providers/TV/TheTVDB/TvdbPrescanTask.cs
@@ -19,7 +19,7 @@ using MediaBrowser.Model.Net;
using MediaBrowser.Model.Xml;
using Microsoft.Extensions.Logging;
-namespace MediaBrowser.Providers.TV
+namespace MediaBrowser.Providers.TV.TheTVDB
{
/// <summary>
/// Class TvdbPrescanTask
diff --git a/MediaBrowser.Providers/TV/TheTVDB/TvdbSeasonImageProvider.cs b/MediaBrowser.Providers/TV/TheTVDB/TvdbSeasonImageProvider.cs
index af36d1ebf..01ede44bb 100644
--- a/MediaBrowser.Providers/TV/TheTVDB/TvdbSeasonImageProvider.cs
+++ b/MediaBrowser.Providers/TV/TheTVDB/TvdbSeasonImageProvider.cs
@@ -19,7 +19,7 @@ using MediaBrowser.Model.IO;
using MediaBrowser.Model.Providers;
using MediaBrowser.Model.Xml;
-namespace MediaBrowser.Providers.TV
+namespace MediaBrowser.Providers.TV.TheTVDB
{
public class TvdbSeasonImageProvider : IRemoteImageProvider, IHasOrder
{
diff --git a/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesImageProvider.cs b/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesImageProvider.cs
index 82fa14f49..2b4337ed1 100644
--- a/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesImageProvider.cs
+++ b/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesImageProvider.cs
@@ -19,7 +19,7 @@ using MediaBrowser.Model.IO;
using MediaBrowser.Model.Providers;
using MediaBrowser.Model.Xml;
-namespace MediaBrowser.Providers.TV
+namespace MediaBrowser.Providers.TV.TheTVDB
{
public class TvdbSeriesImageProvider : IRemoteImageProvider, IHasOrder
{
diff --git a/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesProvider.cs b/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesProvider.cs
index 496e0bb72..52e60a8ed 100644
--- a/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesProvider.cs
+++ b/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesProvider.cs
@@ -23,7 +23,7 @@ using MediaBrowser.Model.Providers;
using MediaBrowser.Model.Xml;
using Microsoft.Extensions.Logging;
-namespace MediaBrowser.Providers.TV
+namespace MediaBrowser.Providers.TV.TheTVDB
{
public class TvdbSeriesProvider : IRemoteMetadataProvider<Series, SeriesInfo>, IHasOrder
{
@@ -66,7 +66,7 @@ namespace MediaBrowser.Providers.TV
}
// pt-br is just pt to tvdb
- return language.Split('-')[0].ToLower();
+ return language.Split('-')[0].ToLowerInvariant();
}
public async Task<IEnumerable<RemoteSearchResult>> GetSearchResults(SeriesInfo searchInfo, CancellationToken cancellationToken)
@@ -776,7 +776,7 @@ namespace MediaBrowser.Providers.TV
/// <returns>System.String.</returns>
private string GetComparableName(string name)
{
- name = name.ToLower();
+ name = name.ToLowerInvariant();
name = _localizationManager.NormalizeFormKD(name);
var sb = new StringBuilder();
foreach (var c in name)
@@ -1620,7 +1620,7 @@ namespace MediaBrowser.Providers.TV
{
var seriesDataPath = GetSeriesDataPath(_config.ApplicationPaths, seriesProviderIds);
- var seriesXmlFilename = language.ToLower() + ".xml";
+ var seriesXmlFilename = language.ToLowerInvariant() + ".xml";
return Path.Combine(seriesDataPath, seriesXmlFilename);
}
diff --git a/MediaBrowser.Providers/TV/TvExternalIds.cs b/MediaBrowser.Providers/TV/TvExternalIds.cs
index 001ce1465..5c246e300 100644
--- a/MediaBrowser.Providers/TV/TvExternalIds.cs
+++ b/MediaBrowser.Providers/TV/TvExternalIds.cs
@@ -1,6 +1,7 @@
using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities;
+using MediaBrowser.Providers.TV.TheTVDB;
namespace MediaBrowser.Providers.TV
{
diff --git a/MediaBrowser.WebDashboard/Api/DashboardService.cs b/MediaBrowser.WebDashboard/Api/DashboardService.cs
index 2f4e21443..531978e1d 100644
--- a/MediaBrowser.WebDashboard/Api/DashboardService.cs
+++ b/MediaBrowser.WebDashboard/Api/DashboardService.cs
@@ -425,11 +425,9 @@ namespace MediaBrowser.WebDashboard.Api
private async Task DumpFile(PackageCreator packageCreator, string resourceVirtualPath, string destinationFilePath, string mode, string appVersion)
{
using (var stream = await packageCreator.GetResource(resourceVirtualPath, mode, null, appVersion).ConfigureAwait(false))
+ using (var fs = _fileSystem.GetFileStream(destinationFilePath, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read))
{
- using (var fs = _fileSystem.GetFileStream(destinationFilePath, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read))
- {
- stream.CopyTo(fs);
- }
+ await stream.CopyToAsync(fs);
}
}
diff --git a/MediaBrowser.WebDashboard/ServerEntryPoint.cs b/MediaBrowser.WebDashboard/ServerEntryPoint.cs
index 221fa62c7..18ed54a78 100644
--- a/MediaBrowser.WebDashboard/ServerEntryPoint.cs
+++ b/MediaBrowser.WebDashboard/ServerEntryPoint.cs
@@ -1,5 +1,6 @@
using System.Collections.Generic;
using System.Linq;
+using System.Threading.Tasks;
using MediaBrowser.Common;
using MediaBrowser.Controller.Plugins;
@@ -23,9 +24,11 @@ namespace MediaBrowser.WebDashboard
Instance = this;
}
- public void Run()
+ public Task RunAsync()
{
PluginConfigurationPages = _appHost.GetExports<IPluginConfigurationPage>().ToList();
+
+ return Task.CompletedTask;
}
public void Dispose()
diff --git a/MediaBrowser.XbmcMetadata/EntryPoint.cs b/MediaBrowser.XbmcMetadata/EntryPoint.cs
index 37a1d4c35..992991a7e 100644
--- a/MediaBrowser.XbmcMetadata/EntryPoint.cs
+++ b/MediaBrowser.XbmcMetadata/EntryPoint.cs
@@ -1,4 +1,5 @@
using System;
+using System.Threading.Tasks;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
@@ -28,9 +29,11 @@ namespace MediaBrowser.XbmcMetadata
_config = config;
}
- public void Run()
+ public Task RunAsync()
{
_userDataManager.UserDataSaved += _userDataManager_UserDataSaved;
+
+ return Task.CompletedTask;
}
void _userDataManager_UserDataSaved(object sender, UserDataSaveEventArgs e)
diff --git a/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs b/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs
index 96b906b3c..4925c7cd1 100644
--- a/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs
+++ b/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs
@@ -82,7 +82,6 @@ namespace MediaBrowser.XbmcMetadata.Savers
"lockedfields",
"zap2itid",
"tvrageid",
- "gamesdbid",
"musicbrainzartistid",
"musicbrainzalbumartistid",
@@ -290,7 +289,7 @@ namespace MediaBrowser.XbmcMetadata.Savers
foreach (var stream in mediaStreams)
{
- writer.WriteStartElement(stream.Type.ToString().ToLower());
+ writer.WriteStartElement(stream.Type.ToString().ToLowerInvariant());
if (!string.IsNullOrEmpty(stream.Codec))
{
@@ -471,7 +470,7 @@ namespace MediaBrowser.XbmcMetadata.Savers
writer.WriteElementString("customrating", item.CustomRating);
}
- writer.WriteElementString("lockdata", item.IsLocked.ToString().ToLower());
+ writer.WriteElementString("lockdata", item.IsLocked.ToString(CultureInfo.InvariantCulture).ToLowerInvariant());
if (item.LockedFields.Length > 0)
{
@@ -737,13 +736,6 @@ namespace MediaBrowser.XbmcMetadata.Savers
writtenProviderIds.Add(MetadataProviders.MusicBrainzReleaseGroup.ToString());
}
- externalId = item.GetProviderId(MetadataProviders.Gamesdb);
- if (!string.IsNullOrEmpty(externalId))
- {
- writer.WriteElementString("gamesdbid", externalId);
- writtenProviderIds.Add(MetadataProviders.Gamesdb.ToString());
- }
-
externalId = item.GetProviderId(MetadataProviders.TvRage);
if (!string.IsNullOrEmpty(externalId))
{
@@ -871,21 +863,21 @@ namespace MediaBrowser.XbmcMetadata.Savers
var userdata = userDataRepo.GetUserData(user, item);
- writer.WriteElementString("isuserfavorite", userdata.IsFavorite.ToString().ToLower());
+ writer.WriteElementString("isuserfavorite", userdata.IsFavorite.ToString(CultureInfo.InvariantCulture).ToLowerInvariant());
if (userdata.Rating.HasValue)
{
- writer.WriteElementString("userrating", userdata.Rating.Value.ToString(CultureInfo.InvariantCulture).ToLower());
+ writer.WriteElementString("userrating", userdata.Rating.Value.ToString(CultureInfo.InvariantCulture).ToLowerInvariant());
}
if (!item.IsFolder)
{
writer.WriteElementString("playcount", userdata.PlayCount.ToString(UsCulture));
- writer.WriteElementString("watched", userdata.Played.ToString().ToLower());
+ writer.WriteElementString("watched", userdata.Played.ToString(CultureInfo.InvariantCulture).ToLowerInvariant());
if (userdata.LastPlayedDate.HasValue)
{
- writer.WriteElementString("lastplayed", userdata.LastPlayedDate.Value.ToLocalTime().ToString("yyyy-MM-dd HH:mm:ss").ToLower());
+ writer.WriteElementString("lastplayed", userdata.LastPlayedDate.Value.ToLocalTime().ToString("yyyy-MM-dd HH:mm:ss").ToLowerInvariant());
}
writer.WriteStartElement("resume");
@@ -901,12 +893,13 @@ namespace MediaBrowser.XbmcMetadata.Savers
private void AddActors(List<PersonInfo> people, XmlWriter writer, ILibraryManager libraryManager, IFileSystem fileSystem, IServerConfigurationManager config, bool saveImagePath)
{
- var actors = people
- .Where(i => !IsPersonType(i, PersonType.Director) && !IsPersonType(i, PersonType.Writer))
- .ToList();
-
- foreach (var person in actors)
+ foreach (var person in people)
{
+ if (IsPersonType(person, PersonType.Director) || IsPersonType(person, PersonType.Writer))
+ {
+ continue;
+ }
+
writer.WriteStartElement("actor");
if (!string.IsNullOrWhiteSpace(person.Name))
@@ -1021,7 +1014,7 @@ namespace MediaBrowser.XbmcMetadata.Savers
private string GetTagForProviderKey(string providerKey)
{
- return providerKey.ToLower() + "id";
+ return providerKey.ToLowerInvariant() + "id";
}
}
}
diff --git a/README.md b/README.md
index dfa8457de..d869c8978 100644
--- a/README.md
+++ b/README.md
@@ -5,13 +5,17 @@
<p align="center">
<img alt="Logo banner" src="https://raw.githubusercontent.com/jellyfin/jellyfin-ux/master/branding/SVG/banner-logo-solid.svg?sanitize=true"/>
-<br/></br>
-<a href="https://github.com/jellyfin/jellyfin"><img alt="GPL 2.0 License" src="https://img.shields.io/github/license/jellyfin/jellyfin.svg"></a>
-<a href="https://cloud.drone.io/jellyfin/jellyfin"><img alt="Build Status" src="https://cloud.drone.io/api/badges/jellyfin/jellyfin/status.svg"></a>
-<a href="https://hub.docker.com/r/jellyfin/jellyfin"><img alt="Docker Pull Count" src="https://img.shields.io/docker/pulls/jellyfin/jellyfin.svg"></a>
-<a href="https://jellyfin.readthedocs.io"><img alt="Documentation" src="https://img.shields.io/readthedocs/jellyfin.svg"></a>
-<a href="https://matrix.to/#/+jellyfin:matrix.org"><img alt="Chat on Matrix" src="https://img.shields.io/matrix/jellyfin:matrix.org.svg?logo=matrix"></a>
-<a href="https://www.reddit.com/r/jellyfin/"><img alt="Join our Subreddit" src="https://img.shields.io/badge/reddit-r%2Fjellyfin-%23FF5700.svg"></a>
+<br/><br/>
+<a href="https://github.com/jellyfin/jellyfin"><img alt="GPL 2.0 License" src="https://img.shields.io/github/license/jellyfin/jellyfin.svg"/></a>
+<a href="https://github.com/jellyfin/jellyfin/releases"><img alt="Current Release" src="https://img.shields.io/github/release/jellyfin/jellyfin.svg"/></a>
+<a href="https://translate.jellyfin.org/engage/jellyfin/?utm_source=widget"><img alt="Translations" src="https://translate.jellyfin.org/widgets/jellyfin/-/svg-badge.svg"/></a>
+<a href="https://cloud.drone.io/jellyfin/jellyfin"><img alt="Build Status" src="https://cloud.drone.io/api/badges/jellyfin/jellyfin/status.svg"/></a>
+<a href="https://hub.docker.com/r/jellyfin/jellyfin"><img alt="Docker Pull Count" src="https://img.shields.io/docker/pulls/jellyfin/jellyfin.svg"/></a>
+</br>
+<a href="https://opencollective.com/jellyfin"><img alt="Donate" src="https://img.shields.io/opencollective/all/jellyfin.svg?label=backers"/></a>
+<a href="https://forum.jellyfin.org"/><img alt="Discuss on our Forum" src="https://img.shields.io/discourse/https/forum.jellyfin.org/users.svg"/></a>
+<a href="https://matrix.to/#/+jellyfin:matrix.org"><img alt="Chat on Matrix" src="https://img.shields.io/matrix/jellyfin:matrix.org.svg?logo=matrix"/></a>
+<a href="https://www.reddit.com/r/jellyfin/"><img alt="Join our Subreddit" src="https://img.shields.io/badge/reddit-r%2Fjellyfin-%23FF5700.svg"/></a>
</p>
---
@@ -24,13 +28,13 @@ For more information about the project, please see our [about page](https://jell
<p align="center">
<strong>Want to get started?</strong>
-<em>Choose from <a href="https://jellyfin.readthedocs.io/en/latest/user-docs/installing/">Prebuilt Packages</a> or <a href="https://jellyfin.readthedocs.io/en/latest/user-docs/building/">Build from Source</a>, then see our <a href="https://jellyfin.readthedocs.io/en/latest/user-docs/quick-start/">Quickstart guide</a>.</em>
+<em>Choose from <a href="https://jellyfin.readthedocs.io/en/latest/administrator-docs/installing/">Prebuilt Packages</a> or <a href="https://jellyfin.readthedocs.io/en/latest/administrator-docs/building/">Build from Source</a>, then see our <a href="https://jellyfin.readthedocs.io/en/latest/administrator-docs/first-time/">first-time setup guide</a>.</em>
</p>
<p align="center">
<strong>Want to contribute?</strong>
-<em>Check out <a href="https://jellyfin.readthedocs.io/en/latest/developer-docs/contributing/">our documentation for guidelines</a>.</em>
+<em>Check out <a href="https://jellyfin.readthedocs.io/en/latest/contributor-docs/contributing/">our documentation for guidelines</a>.</em>
</p>
<p align="center">
<strong>New idea or improvement? Something not working right?</strong>
-<em>Open an <a href="https://jellyfin.readthedocs.io/en/latest/developer-docs/issues/">Issue</a>.</em>
+<em>Open an <a href="https://jellyfin.readthedocs.io/en/latest/contributor-docs/issues/">Issue</a>.</em>
</p>
diff --git a/RSSDP/SsdpDeviceLocator.cs b/RSSDP/SsdpDeviceLocator.cs
index 1348cce8d..128bdfcbb 100644
--- a/RSSDP/SsdpDeviceLocator.cs
+++ b/RSSDP/SsdpDeviceLocator.cs
@@ -8,7 +8,6 @@ using System.Text;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Model.Net;
-using MediaBrowser.Model.Threading;
namespace Rssdp.Infrastructure
{
@@ -23,8 +22,7 @@ namespace Rssdp.Infrastructure
private List<DiscoveredSsdpDevice> _Devices;
private ISsdpCommunicationsServer _CommunicationsServer;
- private ITimer _BroadcastTimer;
- private ITimerFactory _timerFactory;
+ private Timer _BroadcastTimer;
private object _timerLock = new object();
private readonly TimeSpan DefaultSearchWaitTime = TimeSpan.FromSeconds(4);
@@ -37,12 +35,11 @@ namespace Rssdp.Infrastructure
/// <summary>
/// Default constructor.
/// </summary>
- public SsdpDeviceLocator(ISsdpCommunicationsServer communicationsServer, ITimerFactory timerFactory)
+ public SsdpDeviceLocator(ISsdpCommunicationsServer communicationsServer)
{
if (communicationsServer == null) throw new ArgumentNullException(nameof(communicationsServer));
_CommunicationsServer = communicationsServer;
- _timerFactory = timerFactory;
_CommunicationsServer.ResponseReceived += CommsServer_ResponseReceived;
_Devices = new List<DiscoveredSsdpDevice>();
@@ -94,7 +91,7 @@ namespace Rssdp.Infrastructure
{
if (_BroadcastTimer == null)
{
- _BroadcastTimer = _timerFactory.Create(OnBroadcastTimerCallback, null, dueTime, period);
+ _BroadcastTimer = new Timer(OnBroadcastTimerCallback, null, dueTime, period);
}
else
{
diff --git a/RSSDP/SsdpDevicePublisher.cs b/RSSDP/SsdpDevicePublisher.cs
index 8a73e6a2d..ce64ba117 100644
--- a/RSSDP/SsdpDevicePublisher.cs
+++ b/RSSDP/SsdpDevicePublisher.cs
@@ -7,7 +7,6 @@ using System.Text;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Model.Net;
-using MediaBrowser.Model.Threading;
using Rssdp;
namespace Rssdp.Infrastructure
@@ -27,8 +26,7 @@ namespace Rssdp.Infrastructure
private IList<SsdpRootDevice> _Devices;
private IReadOnlyList<SsdpRootDevice> _ReadOnlyDevices;
- private ITimer _RebroadcastAliveNotificationsTimer;
- private ITimerFactory _timerFactory;
+ private Timer _RebroadcastAliveNotificationsTimer;
private IDictionary<string, SearchRequest> _RecentSearchRequests;
@@ -39,7 +37,7 @@ namespace Rssdp.Infrastructure
/// <summary>
/// Default constructor.
/// </summary>
- public SsdpDevicePublisher(ISsdpCommunicationsServer communicationsServer, ITimerFactory timerFactory, string osName, string osVersion)
+ public SsdpDevicePublisher(ISsdpCommunicationsServer communicationsServer, string osName, string osVersion)
{
if (communicationsServer == null) throw new ArgumentNullException(nameof(communicationsServer));
if (osName == null) throw new ArgumentNullException(nameof(osName));
@@ -48,7 +46,6 @@ namespace Rssdp.Infrastructure
if (osVersion.Length == 0) throw new ArgumentException("osVersion cannot be an empty string.", nameof(osName));
_SupportPnpRootDevice = true;
- _timerFactory = timerFactory;
_Devices = new List<SsdpRootDevice>();
_ReadOnlyDevices = new ReadOnlyCollection<SsdpRootDevice>(_Devices);
_RecentSearchRequests = new Dictionary<string, SearchRequest>(StringComparer.OrdinalIgnoreCase);
@@ -64,7 +61,7 @@ namespace Rssdp.Infrastructure
public void StartBroadcastingAliveMessages(TimeSpan interval)
{
- _RebroadcastAliveNotificationsTimer = _timerFactory.Create(SendAllAliveNotifications, null, TimeSpan.FromSeconds(5), interval);
+ _RebroadcastAliveNotificationsTimer = new Timer(SendAllAliveNotifications, null, TimeSpan.FromSeconds(5), interval);
}
/// <summary>
diff --git a/SocketHttpListener/Ext.cs b/SocketHttpListener/Ext.cs
index b051b6718..a02b48061 100644
--- a/SocketHttpListener/Ext.cs
+++ b/SocketHttpListener/Ext.cs
@@ -486,7 +486,7 @@ namespace SocketHttpListener
if (method == CompressionMethod.None)
return string.Empty;
- var m = string.Format("permessage-{0}", method.ToString().ToLower());
+ var m = string.Format("permessage-{0}", method.ToString().ToLowerInvariant());
if (parameters == null || parameters.Length == 0)
return m;
diff --git a/SocketHttpListener/Net/HttpListenerRequest.cs b/SocketHttpListener/Net/HttpListenerRequest.cs
index faeca78b2..667d58ea7 100644
--- a/SocketHttpListener/Net/HttpListenerRequest.cs
+++ b/SocketHttpListener/Net/HttpListenerRequest.cs
@@ -155,7 +155,7 @@ namespace SocketHttpListener.Net
}
else
{
- header = header.ToLower(CultureInfo.InvariantCulture);
+ header = header.ToLowerInvariant();
_keepAlive =
header.IndexOf("close", StringComparison.OrdinalIgnoreCase) < 0 ||
header.IndexOf("keep-alive", StringComparison.OrdinalIgnoreCase) >= 0;
diff --git a/build b/build
index 7d49db72a..3b4167dae 100755
--- a/build
+++ b/build
@@ -23,8 +23,9 @@ usage() {
echo -e "Usage:"
echo -e " $ build --list-platforms"
echo -e " $ build --list-actions <platform>"
- echo -e " $ build [-b/--web-branch <web_branch>] <platform> <action>"
+ echo -e " $ build [-k/--keep-artifacts] [-b/--web-branch <web_branch>] <platform> <action>"
echo -e ""
+ echo -e "The 'keep-artifacts' option preserves build artifacts, e.g. Docker images for system package builds."
echo -e "The web_branch defaults to the same branch name as the current main branch."
echo -e "To build all platforms, use 'all'."
echo -e "To perform all build actions, use 'all'."
@@ -67,6 +68,14 @@ if [[ $1 == '--list-actions' ]]; then
exit 0
fi
+# Parse keep-artifacts option
+if [[ $1 == '-k' || $1 == '--keep-artifacts' ]]; then
+ keep_artifacts="y"
+ shift 1
+else
+ keep_artifacts="n"
+fi
+
# Parse branch option
if [[ $1 == '-b' || $1 == '--web-branch' ]]; then
web_branch="$2"
@@ -193,6 +202,13 @@ for target_platform in ${platform[@]}; do
echo -e "> Processing platform ${target_platform}"
date_start=$( date +%s )
pushd ${target_platform}
+ cleanup() {
+ echo -e ">> Processing action clean"
+ if [[ -f clean.sh && -x clean.sh ]]; then
+ ./clean.sh ${keep_artifacts}
+ fi
+ }
+ trap cleanup EXIT INT
for target_action in ${action[@]}; do
echo -e ">> Processing action ${target_action}"
if [[ -f ${target_action}.sh && -x ${target_action}.sh ]]; then
@@ -204,12 +220,8 @@ for target_platform in ${platform[@]}; do
target_dir="../../../jellyfin-build/${target_platform}"
mkdir -p ${target_dir}
mv pkg-dist/* ${target_dir}/
-
- echo -e ">> Processing action clean"
- if [[ -f clean.sh && -x clean.sh ]]; then
- ./clean.sh
- fi
fi
+ cleanup
date_end=$( date +%s )
echo -e "> Completed platform ${target_platform} in $( expr ${date_end} - ${date_start} ) seconds."
popd
diff --git a/bump_version b/bump_version
index c3f1a78d5..a63fbf735 100755
--- a/bump_version
+++ b/bump_version
@@ -68,8 +68,7 @@ new_version="$1"
# Parse the version from the AssemblyVersion
old_version="$(
grep "AssemblyVersion" ${shared_version_file} \
- | sed -E 's/\[assembly: ?AssemblyVersion\("([0-9\.]+)"\)\]/\1/' \
- | sed -E 's/.0$//'
+ | sed -E 's/\[assembly: ?AssemblyVersion\("([0-9\.]+)"\)\]/\1/'
)"
# Set the shared version to the specified new_version
diff --git a/deployment/README.md b/deployment/README.md
index 05b4ed51e..a00cd3e6c 100644
--- a/deployment/README.md
+++ b/deployment/README.md
@@ -55,6 +55,8 @@ These builds are not necessarily run from the `build` script, but are present fo
* The `clean` action should always `exit 0` even if no work is done or it fails.
+* The `clean` action can be passed a variable as argument 1, named `keep_artifacts`, containing either the value `y` or `n`. It is indended to handle situations when the user runs `build --keep-artifacts` and should be handled intelligently. Usually, this is used to preserve Docker images while still removing temporary directories.
+
### Output Files
* Upon completion of the defined actions, at least one output file must be created in the `<platform>/pkg-dist` directory.
diff --git a/deployment/centos-package-x64/Dockerfile b/deployment/centos-package-x64/Dockerfile
new file mode 100644
index 000000000..38853f173
--- /dev/null
+++ b/deployment/centos-package-x64/Dockerfile
@@ -0,0 +1,27 @@
+FROM centos:7
+# Docker build arguments
+ARG SOURCE_DIR=/jellyfin
+ARG PLATFORM_DIR=/jellyfin/deployment/centos-package-x64
+ARG ARTIFACT_DIR=/dist
+ARG SDK_VERSION=2.2
+# Docker run environment
+ENV SOURCE_DIR=/jellyfin
+ENV ARTIFACT_DIR=/dist
+
+# Prepare CentOS build environment
+RUN yum update -y \
+ && yum install -y @buildsys-build rpmdevtools yum-plugins-core libcurl-devel fontconfig-devel freetype-devel openssl-devel glibc-devel libicu-devel \
+ && rpm -Uvh https://packages.microsoft.com/config/rhel/7/packages-microsoft-prod.rpm \
+ && rpmdev-setuptree \
+ && yum install -y dotnet-sdk-${SDK_VERSION} \
+ && ln -sf ${PLATFORM_DIR}/docker-build.sh /docker-build.sh \
+ && mkdir -p ${SOURCE_DIR}/SPECS \
+ && ln -s ${PLATFORM_DIR}/pkg-src/jellyfin.spec ${SOURCE_DIR}/SPECS/jellyfin.spec \
+ && mkdir -p ${SOURCE_DIR}/SOURCES \
+ && ln -s ${PLATFORM_DIR}/pkg-src ${SOURCE_DIR}/SOURCES
+
+VOLUME ${ARTIFACT_DIR}/
+
+COPY . ${SOURCE_DIR}/
+
+ENTRYPOINT ["/docker-build.sh"]
diff --git a/deployment/centos-package-x64/clean.sh b/deployment/centos-package-x64/clean.sh
new file mode 100755
index 000000000..7278372e1
--- /dev/null
+++ b/deployment/centos-package-x64/clean.sh
@@ -0,0 +1,34 @@
+#!/usr/bin/env bash
+
+source ../common.build.sh
+
+keep_artifacts="${1}"
+
+WORKDIR="$( pwd )"
+VERSION="$( grep -A1 '^Version:' ${WORKDIR}/pkg-src/jellyfin.spec | awk '{ print $NF }' )"
+
+package_temporary_dir="${WORKDIR}/pkg-dist-tmp"
+package_source_dir="${WORKDIR}/pkg-src"
+output_dir="${WORKDIR}/pkg-dist"
+current_user="$( whoami )"
+image_name="jellyfin-centos-build"
+
+rm -f "${package_source_dir}/jellyfin-${VERSION}.tar.gz" &>/dev/null \
+ || sudo rm -f "${package_source_dir}/jellyfin-${VERSION}.tar.gz" &>/dev/null
+
+rm -rf "${package_temporary_dir}" &>/dev/null \
+ || sudo rm -rf "${package_temporary_dir}" &>/dev/null
+
+rm -rf "${output_dir}" &>/dev/null \
+ || sudo rm -rf "${output_dir}" &>/dev/null
+
+if [[ ${keep_artifacts} == 'n' ]]; then
+ docker_sudo=""
+ if [[ ! -z $(id -Gn | grep -q 'docker') ]] \
+ && [[ ! ${EUID:-1000} -eq 0 ]] \
+ && [[ ! ${USER} == "root" ]] \
+ && [[ ! -z $( echo "${OSTYPE}" | grep -q "darwin" ) ]]; then
+ docker_sudo=sudo
+ fi
+ ${docker_sudo} docker image rm ${image_name} --force
+fi
diff --git a/deployment/centos-package-x64/dependencies.txt b/deployment/centos-package-x64/dependencies.txt
new file mode 100644
index 000000000..bdb967096
--- /dev/null
+++ b/deployment/centos-package-x64/dependencies.txt
@@ -0,0 +1 @@
+docker
diff --git a/deployment/centos-package-x64/docker-build.sh b/deployment/centos-package-x64/docker-build.sh
new file mode 100755
index 000000000..3acf1ec0d
--- /dev/null
+++ b/deployment/centos-package-x64/docker-build.sh
@@ -0,0 +1,20 @@
+#!/bin/bash
+
+# Builds the RPM inside the Docker container
+
+set -o errexit
+set -o xtrace
+
+# Move to source directory
+pushd ${SOURCE_DIR}
+
+ls -al SOURCES/pkg-src/
+
+# Build RPM
+spectool -g -R SPECS/jellyfin.spec
+rpmbuild -bs SPECS/jellyfin.spec --define "_sourcedir ${SOURCE_DIR}/SOURCES/pkg-src/"
+rpmbuild -bb SPECS/jellyfin.spec --define "_sourcedir ${SOURCE_DIR}/SOURCES/pkg-src/"
+
+# Move the artifacts out
+mkdir -p ${ARTIFACT_DIR}/rpm
+mv /root/rpmbuild/RPMS/x86_64/jellyfin-*.rpm /root/rpmbuild/SRPMS/jellyfin-*.src.rpm ${ARTIFACT_DIR}/rpm/
diff --git a/deployment/centos-package-x64/package.sh b/deployment/centos-package-x64/package.sh
new file mode 100755
index 000000000..27d686e46
--- /dev/null
+++ b/deployment/centos-package-x64/package.sh
@@ -0,0 +1,80 @@
+#!/usr/bin/env bash
+
+source ../common.build.sh
+
+WORKDIR="$( pwd )"
+VERSION="$( grep '^Version:' ${WORKDIR}/pkg-src/jellyfin.spec | awk '{ print $NF }' )"
+
+package_temporary_dir="${WORKDIR}/pkg-dist-tmp"
+output_dir="${WORKDIR}/pkg-dist"
+pkg_src_dir="${WORKDIR}/pkg-src"
+current_user="$( whoami )"
+image_name="jellyfin-centos-build"
+
+# Determine if sudo should be used for Docker
+if [[ ! -z $(id -Gn | grep -q 'docker') ]] \
+ && [[ ! ${EUID:-1000} -eq 0 ]] \
+ && [[ ! ${USER} == "root" ]] \
+ && [[ ! -z $( echo "${OSTYPE}" | grep -q "darwin" ) ]]; then
+ docker_sudo="sudo"
+else
+ docker_sudo=""
+fi
+
+# Create RPM source archive
+GNU_TAR=1
+mkdir -p "${package_temporary_dir}"
+echo "Bundling all sources for RPM build."
+tar \
+--transform "s,^\.,jellyfin-${VERSION}," \
+--exclude='.git*' \
+--exclude='**/.git' \
+--exclude='**/.hg' \
+--exclude='**/.vs' \
+--exclude='**/.vscode' \
+--exclude='deployment' \
+--exclude='**/bin' \
+--exclude='**/obj' \
+--exclude='**/.nuget' \
+--exclude='*.deb' \
+--exclude='*.rpm' \
+-czf "${pkg_src_dir}/jellyfin-${VERSION}.tar.gz" \
+-C "../.." ./ || GNU_TAR=0
+
+if [ $GNU_TAR -eq 0 ]; then
+ echo "The installed tar binary did not support --transform. Using workaround."
+ mkdir -p "${package_temporary_dir}/jellyfin"
+ # Not GNU tar
+ tar \
+ --exclude='.git*' \
+ --exclude='**/.git' \
+ --exclude='**/.hg' \
+ --exclude='**/.vs' \
+ --exclude='**/.vscode' \
+ --exclude='deployment' \
+ --exclude='**/bin' \
+ --exclude='**/obj' \
+ --exclude='**/.nuget' \
+ --exclude='*.deb' \
+ --exclude='*.rpm' \
+ -zcf \
+ "${package_temporary_dir}/jellyfin/jellyfin-${VERSION}.tar.gz" \
+ -C "../.." ./
+ echo "Extracting filtered package."
+ tar -xzf "${package_temporary_dir}/jellyfin/jellyfin-${VERSION}.tar.gz" -C "${package_temporary_dir}/jellyfin-${VERSION}"
+ echo "Removing filtered package."
+ rm -f "${package_temporary_dir}/jellyfin/jellyfin-${VERSION}.tar.gz"
+ echo "Repackaging package into final tarball."
+ tar -czf "${pkg_src_dir}/jellyfin-${VERSION}.tar.gz" -C "${package_temporary_dir}" "jellyfin-${VERSION}"
+fi
+
+# Set up the build environment Docker image
+${docker_sudo} docker build ../.. -t "${image_name}" -f ./Dockerfile
+# Build the RPMs and copy out to ${package_temporary_dir}
+${docker_sudo} docker run --rm -v "${package_temporary_dir}:/dist" "${image_name}"
+# Correct ownership on the RPMs (as current user, then as root if that fails)
+chown -R "${current_user}" "${package_temporary_dir}" \
+ || sudo chown -R "${current_user}" "${package_temporary_dir}"
+# Move the RPMs to the output directory
+mkdir -p "${output_dir}"
+mv "${package_temporary_dir}"/rpm/* "${output_dir}"
diff --git a/deployment/centos-package-x64/pkg-src b/deployment/centos-package-x64/pkg-src
new file mode 120000
index 000000000..dfd6497cf
--- /dev/null
+++ b/deployment/centos-package-x64/pkg-src
@@ -0,0 +1 @@
+../fedora-package-x64/pkg-src \ No newline at end of file
diff --git a/deployment/debian-package-x64/Dockerfile b/deployment/debian-package-x64/Dockerfile
index 2afe6c1d3..9819cc20d 100644
--- a/deployment/debian-package-x64/Dockerfile
+++ b/deployment/debian-package-x64/Dockerfile
@@ -1,23 +1,21 @@
-FROM debian:9
-ARG SOURCEDIR=/repo
+FROM microsoft/dotnet:2.2-sdk-stretch
+# Docker build arguments
+ARG SOURCE_DIR=/jellyfin
+ARG PLATFORM_DIR=/jellyfin/deployment/debian-package-x64
+ARG ARTIFACT_DIR=/dist
+# Docker run environment
+ENV SOURCE_DIR=/jellyfin
+ENV ARTIFACT_DIR=/dist
ENV DEB_BUILD_OPTIONS=noddebs
-# https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current
+# Prepare Debian build environment
RUN apt-get update \
- && apt-get install -y apt-transport-https debhelper gnupg wget devscripts \
- && wget -qO- https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > microsoft.asc.gpg \
- && mv microsoft.asc.gpg /etc/apt/trusted.gpg.d/ \
- && wget -q https://packages.microsoft.com/config/debian/9/prod.list \
- && mv prod.list /etc/apt/sources.list.d/microsoft-prod.list \
- && chown root:root /etc/apt/trusted.gpg.d/microsoft.asc.gpg \
- && chown root:root /etc/apt/sources.list.d/microsoft-prod.list \
- && apt-get update
+ && apt-get install -y apt-transport-https debhelper gnupg wget devscripts mmv libc6-dev libcurl4-openssl-dev libfontconfig1-dev libfreetype6-dev \
+ && ln -sf ${PLATFORM_DIR}/docker-build.sh /docker-build.sh \
+ && mkdir -p ${SOURCE_DIR} && ln -sf ${PLATFORM_DIR}/pkg-src ${SOURCE_DIR}/debian
-WORKDIR ${SOURCEDIR}
-COPY . .
-COPY ./deployment/debian-package-x64/pkg-src ./debian
+VOLUME ${ARTIFACT_DIR}/
-RUN yes | mk-build-deps -i debian/control \
- && dpkg-buildpackage -us -uc
+COPY . ${SOURCE_DIR}/
-WORKDIR /
+ENTRYPOINT ["/docker-build.sh"]
diff --git a/deployment/debian-package-x64/clean.sh b/deployment/debian-package-x64/clean.sh
index 3df2d7796..b2960fcb3 100755
--- a/deployment/debian-package-x64/clean.sh
+++ b/deployment/debian-package-x64/clean.sh
@@ -2,6 +2,28 @@
source ../common.build.sh
-VERSION=`get_version ../..`
+keep_artifacts="${1}"
-clean_jellyfin ../.. Release `pwd`/dist/jellyfin_${VERSION}
+WORKDIR="$( pwd )"
+
+package_temporary_dir="${WORKDIR}/pkg-dist-tmp"
+output_dir="${WORKDIR}/pkg-dist"
+current_user="$( whoami )"
+image_name="jellyfin-debian-build"
+
+rm -rf "${package_temporary_dir}" &>/dev/null \
+ || sudo rm -rf "${package_temporary_dir}" &>/dev/null
+
+rm -rf "${output_dir}" &>/dev/null \
+ || sudo rm -rf "${output_dir}" &>/dev/null
+
+if [[ ${keep_artifacts} == 'n' ]]; then
+ docker_sudo=""
+ if [[ ! -z $(id -Gn | grep -q 'docker') ]] \
+ && [[ ! ${EUID:-1000} -eq 0 ]] \
+ && [[ ! ${USER} == "root" ]] \
+ && [[ ! -z $( echo "${OSTYPE}" | grep -q "darwin" ) ]]; then
+ docker_sudo=sudo
+ fi
+ ${docker_sudo} docker image rm ${image_name} --force
+fi
diff --git a/deployment/debian-package-x64/docker-build.sh b/deployment/debian-package-x64/docker-build.sh
new file mode 100755
index 000000000..0590be097
--- /dev/null
+++ b/deployment/debian-package-x64/docker-build.sh
@@ -0,0 +1,19 @@
+#!/bin/bash
+
+# Builds the DEB inside the Docker container
+
+set -o errexit
+set -o xtrace
+
+# Move to source directory
+pushd ${SOURCE_DIR}
+
+# Remove build-dep for dotnet-sdk-2.2, since it's not a package in this image
+sed -i '/dotnet-sdk-2.2,/d' debian/control
+
+# Build DEB
+dpkg-buildpackage -us -uc
+
+# Move the artifacts out
+mkdir -p ${ARTIFACT_DIR}/deb
+mv /jellyfin_* ${ARTIFACT_DIR}/deb/
diff --git a/deployment/debian-package-x64/package.sh b/deployment/debian-package-x64/package.sh
index dec953961..d7c3f5809 100755
--- a/deployment/debian-package-x64/package.sh
+++ b/deployment/debian-package-x64/package.sh
@@ -2,30 +2,30 @@
source ../common.build.sh
-VERSION=`get_version ../..`
-
-# TODO get the version in the package automatically. And using the changelog to decide the debian package suffix version.
-
-# Build a Jellyfin .deb file with Docker on Linux
-# Places the output .deb file in the parent directory
-
-package_temporary_dir="`pwd`/pkg-dist-tmp"
-output_dir="`pwd`/pkg-dist"
-current_user="`whoami`"
-image_name="jellyfin-debuild"
-
-cleanup() {
- set +o errexit
- docker image rm $image_name --force
- rm -rf "$package_temporary_dir"
-}
-trap cleanup EXIT INT
-
-docker build ../.. -t "$image_name" -f ./Dockerfile --build-arg SOURCEDIR="/jellyfin-${VERSION}"
-mkdir -p "$package_temporary_dir"
-mkdir -p "$output_dir"
-docker run --rm -v "$package_temporary_dir:/temp" "$image_name" sh -c 'find / -maxdepth 1 -type f -name "jellyfin*" -exec mv {} /temp \;'
-chown -R "$current_user" "$package_temporary_dir" \
-|| sudo chown -R "$current_user" "$package_temporary_dir"
-
-mv "$package_temporary_dir"/* "$output_dir"
+WORKDIR="$( pwd )"
+
+package_temporary_dir="${WORKDIR}/pkg-dist-tmp"
+output_dir="${WORKDIR}/pkg-dist"
+current_user="$( whoami )"
+image_name="jellyfin-debian-build"
+
+# Determine if sudo should be used for Docker
+if [[ ! -z $(id -Gn | grep -q 'docker') ]] \
+ && [[ ! ${EUID:-1000} -eq 0 ]] \
+ && [[ ! ${USER} == "root" ]] \
+ && [[ ! -z $( echo "${OSTYPE}" | grep -q "darwin" ) ]]; then
+ docker_sudo="sudo"
+else
+ docker_sudo=""
+fi
+
+# Set up the build environment Docker image
+${docker_sudo} docker build ../.. -t "${image_name}" -f ./Dockerfile
+# Build the DEBs and copy out to ${package_temporary_dir}
+${docker_sudo} docker run --rm -v "${package_temporary_dir}:/dist" "${image_name}"
+# Correct ownership on the DEBs (as current user, then as root if that fails)
+chown -R "${current_user}" "${package_temporary_dir}" &>/dev/null \
+ || sudo chown -R "${current_user}" "${package_temporary_dir}" &>/dev/null
+# Move the DEBs to the output directory
+mkdir -p "${output_dir}"
+mv "${package_temporary_dir}"/deb/* "${output_dir}"
diff --git a/deployment/debian-package-x64/pkg-src/bin/restart.sh b/deployment/debian-package-x64/pkg-src/bin/restart.sh
index a6f4632ba..738f86727 100644
--- a/deployment/debian-package-x64/pkg-src/bin/restart.sh
+++ b/deployment/debian-package-x64/pkg-src/bin/restart.sh
@@ -2,10 +2,12 @@
NAME=jellyfin
-restart_cmds=("s6-svc -t /var/run/s6/services/${NAME}" \
- "systemctl restart ${NAME}" \
- "service ${NAME} restart" \
- "/etc/init.d/${NAME} restart")
+restart_cmds=(
+ "systemctl restart ${NAME}"
+ "service ${NAME} restart"
+ "/etc/init.d/${NAME} restart"
+ "s6-svc -t /var/run/s6/services/${NAME}"
+)
for restart_cmd in "${restart_cmds[@]}"; do
cmd=$(echo "$restart_cmd" | awk '{print $1}')
diff --git a/deployment/debian-package-x64/pkg-src/conf/jellyfin b/deployment/debian-package-x64/pkg-src/conf/jellyfin
index 861865aae..b052b2ec6 100644
--- a/deployment/debian-package-x64/pkg-src/conf/jellyfin
+++ b/deployment/debian-package-x64/pkg-src/conf/jellyfin
@@ -1,4 +1,5 @@
# Jellyfin default configuration options
+# This is a POSIX shell fragment
# Use this file to override the default configurations; add additional
# options with JELLYFIN_ADD_OPTS.
@@ -8,10 +9,6 @@
# to override the user or this config file's location.
#
-# This is a POSIX shell fragment
-#
-
-#
# General options
#
@@ -19,10 +16,20 @@
JELLYFIN_DATA_DIRECTORY="/var/lib/jellyfin"
JELLYFIN_CONFIG_DIRECTORY="/etc/jellyfin"
JELLYFIN_LOG_DIRECTORY="/var/log/jellyfin"
+JELLYFIN_CACHE_DIRECTORY="/var/cache/jellyfin"
+
# Restart script for in-app server control
-JELLYFIN_RESTART_SCRIPT="/usr/lib/jellyfin/restart.sh"
-# Additional options for the binary
-JELLYFIN_ADD_OPTS=""
+JELLYFIN_RESTART_OPT="--restartpath=/usr/lib/jellyfin/restart.sh"
+
+# [OPTIONAL] ffmpeg binary paths, overriding the UI-configured values
+#JELLYFIN_FFMPEG_OPT="--ffmpeg=/usr/bin/ffmpeg"
+#JELLYFIN_FFPROBE_OPT="--ffprobe=/usr/bin/ffprobe"
+
+# [OPTIONAL] run Jellyfin as a headless service
+#JELLYFIN_SERVICE_OPT="--service"
+
+# [OPTIONAL] run Jellyfin without the web app
+#JELLYFIN_NOWEBAPP_OPT="--noautorunwebapp"
#
# SysV init/Upstart options
@@ -31,4 +38,4 @@ JELLYFIN_ADD_OPTS=""
# Application username
JELLYFIN_USER="jellyfin"
# Full application command
-JELLYFIN_ARGS="-programdata $JELLYFIN_DATA_DIRECTORY -configdir $JELLYFIN_CONFIG_DIRECTORY -logdir $JELLYFIN_LOG_DIRECTORY -restartpath $JELLYFIN_RESTART_SCRIPT $JELLYFIN_ADD_OPTS"
+JELLYFIN_ARGS="--datadir=$JELLYFIN_DATA_DIRECTORY --configdir=$JELLYFIN_CONFIG_DIRECTORY --logdir=$JELLYFIN_LOG_DIRECTORY --cachedir=$JELLYFIN_CACHE_DIRECTORY $JELLYFIN_RESTART_OPT $JELLYFIN_FFMPEG_OPT $JELLYFIN_FFPROBE_OPT $JELLYFIN_SERVICE_OPT $JELLFIN_NOWEBAPP_OPT"
diff --git a/deployment/debian-package-x64/pkg-src/bin/jellyfin-sudoers b/deployment/debian-package-x64/pkg-src/conf/jellyfin-sudoers
index 4eb91366b..b481ba4ad 100644
--- a/deployment/debian-package-x64/pkg-src/bin/jellyfin-sudoers
+++ b/deployment/debian-package-x64/pkg-src/conf/jellyfin-sudoers
@@ -10,15 +10,15 @@ Cmnd_Alias STARTSERVER_INITD = /etc/init.d/jellyfin start
Cmnd_Alias STOPSERVER_INITD = /etc/init.d/jellyfin stop
-%jellyfin ALL=(ALL) NOPASSWD: RESTARTSERVER_SYSV
-%jellyfin ALL=(ALL) NOPASSWD: STARTSERVER_SYSV
-%jellyfin ALL=(ALL) NOPASSWD: STOPSERVER_SYSV
-%jellyfin ALL=(ALL) NOPASSWD: RESTARTSERVER_SYSTEMD
-%jellyfin ALL=(ALL) NOPASSWD: STARTSERVER_SYSTEMD
-%jellyfin ALL=(ALL) NOPASSWD: STOPSERVER_SYSTEMD
-%jellyfin ALL=(ALL) NOPASSWD: RESTARTSERVER_INITD
-%jellyfin ALL=(ALL) NOPASSWD: STARTSERVER_INITD
-%jellyfin ALL=(ALL) NOPASSWD: STOPSERVER_INITD
+jellyfin ALL=(ALL) NOPASSWD: RESTARTSERVER_SYSV
+jellyfin ALL=(ALL) NOPASSWD: STARTSERVER_SYSV
+jellyfin ALL=(ALL) NOPASSWD: STOPSERVER_SYSV
+jellyfin ALL=(ALL) NOPASSWD: RESTARTSERVER_SYSTEMD
+jellyfin ALL=(ALL) NOPASSWD: STARTSERVER_SYSTEMD
+jellyfin ALL=(ALL) NOPASSWD: STOPSERVER_SYSTEMD
+jellyfin ALL=(ALL) NOPASSWD: RESTARTSERVER_INITD
+jellyfin ALL=(ALL) NOPASSWD: STARTSERVER_INITD
+jellyfin ALL=(ALL) NOPASSWD: STOPSERVER_INITD
Defaults!RESTARTSERVER_SYSV !requiretty
Defaults!STARTSERVER_SYSV !requiretty
@@ -31,7 +31,7 @@ Defaults!STARTSERVER_INITD !requiretty
Defaults!STOPSERVER_INITD !requiretty
#Allow the server to mount iso images
-%jellyfin ALL=(ALL) NOPASSWD: /bin/mount
-%jellyfin ALL=(ALL) NOPASSWD: /bin/umount
+jellyfin ALL=(ALL) NOPASSWD: /bin/mount
+jellyfin ALL=(ALL) NOPASSWD: /bin/umount
-Defaults:%jellyfin !requiretty
+Defaults:jellyfin !requiretty
diff --git a/deployment/debian-package-x64/pkg-src/install b/deployment/debian-package-x64/pkg-src/install
index adaff7b26..994322d14 100644
--- a/deployment/debian-package-x64/pkg-src/install
+++ b/deployment/debian-package-x64/pkg-src/install
@@ -2,5 +2,5 @@ usr/lib/jellyfin usr/lib/
debian/conf/jellyfin etc/default/
debian/conf/logging.json etc/jellyfin/
debian/conf/jellyfin.service.conf etc/systemd/system/jellyfin.service.d/
-debian/bin/jellyfin-sudoers etc/sudoers.d/
+debian/conf/jellyfin-sudoers etc/sudoers.d/
debian/bin/restart.sh usr/lib/jellyfin/
diff --git a/deployment/debian-package-x64/pkg-src/jellyfin.service b/deployment/debian-package-x64/pkg-src/jellyfin.service
index c17422029..9c6c6667f 100644
--- a/deployment/debian-package-x64/pkg-src/jellyfin.service
+++ b/deployment/debian-package-x64/pkg-src/jellyfin.service
@@ -6,7 +6,7 @@ After = network.target
Type = simple
EnvironmentFile = /etc/default/jellyfin
User = jellyfin
-ExecStart = /usr/bin/jellyfin -programdata ${JELLYFIN_DATA_DIRECTORY} -configdir ${JELLYFIN_CONFIG_DIRECTORY} -logdir ${JELLYFIN_LOG_DIRECTORY} -restartpath ${JELLYFIN_RESTART_SCRIPT} ${JELLYFIN_ADD_OPTS}
+ExecStart = /usr/bin/jellyfin --datadir=${JELLYFIN_DATA_DIRECTORY} --configdir=${JELLYFIN_CONFIG_DIRECTORY} --logdir=${JELLYFIN_LOG_DIRECTORY} --cachedir=${JELLYFIN_CACHE_DIRECTORY} ${JELLYFIN_RESTART_OPT} ${JELLYFIN_FFMPEG_OPT} ${JELLYFIN_FFPROBE_OPT} ${JELLYFIN_SERVICE_OPT} ${JELLYFIN_NOWEBAPP_OPT}
Restart = on-failure
TimeoutSec = 15
diff --git a/deployment/debian-package-x64/pkg-src/postinst b/deployment/debian-package-x64/pkg-src/postinst
index 3690d20ba..860222e05 100644
--- a/deployment/debian-package-x64/pkg-src/postinst
+++ b/deployment/debian-package-x64/pkg-src/postinst
@@ -13,6 +13,7 @@ fi
PROGRAMDATA=${JELLYFIN_DATA_DIRECTORY-/var/lib/$NAME}
CONFIGDATA=${JELLYFIN_CONFIG_DIRECTORY-/etc/$NAME}
LOGDATA=${JELLYFIN_LOG_DIRECTORY-/var/log/$NAME}
+CACHEDATA=${JELLYFIN_CACHE_DIRECTORY-/var/cache/$NAME}
case "$1" in
configure)
@@ -37,10 +38,14 @@ case "$1" in
if [[ ! -d $LOGDATA ]]; then
mkdir $LOGDATA
fi
+ # ensure $CACHEDATA exists
+ if [[ ! -d $CACHEDATA ]]; then
+ mkdir $CACHEDATA
+ fi
# Ensure permissions are correct on all config directories
- chown -R jellyfin:jellyfin $PROGRAMDATA
- chown -R jellyfin:jellyfin $CONFIGDATA
- chown -R jellyfin:jellyfin $LOGDATA
+ chown -R jellyfin $PROGRAMDATA $CONFIGDATA $LOGDATA $CACHEDATA
+ chgrp adm $PROGRAMDATA $CONFIGDATA $LOGDATA $CACHEDATA
+ chmod 0750 $PROGRAMDATA $CONFIGDATA $LOGDATA $CACHEDATA
chmod +x /usr/lib/jellyfin/restart.sh > /dev/null 2>&1 || true
diff --git a/deployment/debian-package-x64/pkg-src/postrm b/deployment/debian-package-x64/pkg-src/postrm
index 690f5d587..1d00a984e 100644
--- a/deployment/debian-package-x64/pkg-src/postrm
+++ b/deployment/debian-package-x64/pkg-src/postrm
@@ -12,7 +12,8 @@ fi
# Data directories for program data (cache, db), configs, and logs
PROGRAMDATA=${JELLYFIN_DATA_DIRECTORY-/var/lib/$NAME}
CONFIGDATA=${JELLYFIN_CONFIG_DIRECTORY-/etc/$NAME}
-LOGDATA=${JELLYFIN_DATA_DIRECTORY-/var/log/$NAME}
+LOGDATA=${JELLYFIN_LOG_DIRECTORY-/var/log/$NAME}
+CACHEDATA=${JELLYFIN_CACHE_DIRECTORY-/var/cache/$NAME}
# In case this system is running systemd, we make systemd reload the unit files
# to pick up changes.
@@ -44,6 +45,10 @@ case "$1" in
if [[ -d $LOGDATA ]]; then
rm -rf $LOGDATA
fi
+ # Remove cache dir
+ if [[ -d $CACHEDATA ]]; then
+ rm -rf $CACHEDATA
+ fi
# Remove program data dir
if [[ -d $PROGRAMDATA ]]; then
rm -rf $PROGRAMDATA
@@ -55,6 +60,7 @@ case "$1" in
# Remove anything at the default locations; catches situations where the user moved the defaults
[[ -e /etc/jellyfin ]] && rm -rf /etc/jellyfin
[[ -e /var/log/jellyfin ]] && rm -rf /var/log/jellyfin
+ [[ -e /var/cache/jellyfin ]] && rm -rf /var/cache/jellyfin
[[ -e /var/lib/jellyfin ]] && rm -rf /var/lib/jellyfin
;;
remove)
diff --git a/deployment/debian-package-x64/pkg-src/preinst b/deployment/debian-package-x64/pkg-src/preinst
index 0063e0e63..2713fb9b8 100644
--- a/deployment/debian-package-x64/pkg-src/preinst
+++ b/deployment/debian-package-x64/pkg-src/preinst
@@ -12,7 +12,8 @@ fi
# Data directories for program data (cache, db), configs, and logs
PROGRAMDATA=${JELLYFIN_DATA_DIRECTORY-/var/lib/$NAME}
CONFIGDATA=${JELLYFIN_CONFIG_DIRECTORY-/etc/$NAME}
-LOGDATA=${JELLYFIN_DATA_DIRECTORY-/var/log/$NAME}
+LOGDATA=${JELLYFIN_LOG_DIRECTORY-/var/log/$NAME}
+CACHEDATA=${JELLYFIN_CACHE_DIRECTORY-/var/cache/$NAME}
# In case this system is running systemd, we make systemd reload the unit files
# to pick up changes.
@@ -53,13 +54,16 @@ case "$1" in
# Clean up old Emby cruft that can break the user's system
[[ -f /etc/sudoers.d/emby ]] && rm -f /etc/sudoers.d/emby
- # If we have existing config or log dirs in /var/lib/jellyfin, move them into the right place
+ # If we have existing config, log, or cache dirs in /var/lib/jellyfin, move them into the right place
if [[ -d $PROGRAMDATA/config ]]; then
mv $PROGRAMDATA/config $CONFIGDATA
fi
if [[ -d $PROGRAMDATA/logs ]]; then
mv $PROGRAMDATA/logs $LOGDATA
fi
+ if [[ -d $PROGRAMDATA/logs ]]; then
+ mv $PROGRAMDATA/cache $CACHEDATA
+ fi
;;
abort-upgrade)
diff --git a/deployment/debian-package-x64/pkg-src/prerm b/deployment/debian-package-x64/pkg-src/prerm
index 4770c03c4..e965cb7d7 100644
--- a/deployment/debian-package-x64/pkg-src/prerm
+++ b/deployment/debian-package-x64/pkg-src/prerm
@@ -12,7 +12,8 @@ fi
# Data directories for program data (cache, db), configs, and logs
PROGRAMDATA=${JELLYFIN_DATA_DIRECTORY-/var/lib/$NAME}
CONFIGDATA=${JELLYFIN_CONFIG_DIRECTORY-/etc/$NAME}
-LOGDATA=${JELLYFIN_DATA_DIRECTORY-/var/log/$NAME}
+LOGDATA=${JELLYFIN_LOG_DIRECTORY-/var/log/$NAME}
+CACHEDATA=${JELLYFIN_CACHE_DIRECTORY-/var/cache/$NAME}
case "$1" in
remove|upgrade|deconfigure)
diff --git a/deployment/fedora-package-x64/Dockerfile b/deployment/fedora-package-x64/Dockerfile
index e5deac29f..8bb1d527d 100644
--- a/deployment/fedora-package-x64/Dockerfile
+++ b/deployment/fedora-package-x64/Dockerfile
@@ -1,15 +1,27 @@
FROM fedora:29
-ARG HOME=/build
-RUN mkdir /build && \
- dnf install -y @buildsys-build rpmdevtools dnf-plugins-core && \
- dnf copr enable -y @dotnet-sig/dotnet && \
- rpmdev-setuptree
-
-WORKDIR /build/rpmbuild
-COPY ./deployment/fedora-package-x64/pkg-src/jellyfin.spec SPECS
-COPY ./deployment/fedora-package-x64/pkg-src/ SOURCES
-
-RUN spectool -g -R SPECS/jellyfin.spec && \
- rpmbuild -bs SPECS/jellyfin.spec && \
- dnf build-dep -y SRPMS/jellyfin-*.src.rpm && \
- rpmbuild -bb SPECS/jellyfin.spec; \ No newline at end of file
+# Docker build arguments
+ARG SOURCE_DIR=/jellyfin
+ARG PLATFORM_DIR=/jellyfin/deployment/fedora-package-x64
+ARG ARTIFACT_DIR=/dist
+ARG SDK_VERSION=2.2
+# Docker run environment
+ENV SOURCE_DIR=/jellyfin
+ENV ARTIFACT_DIR=/dist
+
+# Prepare Fedora build environment
+RUN dnf update -y \
+ && dnf install -y @buildsys-build rpmdevtools dnf-plugins-core libcurl-devel fontconfig-devel freetype-devel openssl-devel glibc-devel libicu-devel \
+ && dnf copr enable -y @dotnet-sig/dotnet \
+ && rpmdev-setuptree \
+ && dnf install -y dotnet-sdk-${SDK_VERSION} \
+ && ln -sf ${PLATFORM_DIR}/docker-build.sh /docker-build.sh \
+ && mkdir -p ${SOURCE_DIR}/SPECS \
+ && ln -s ${PLATFORM_DIR}/pkg-src/jellyfin.spec ${SOURCE_DIR}/SPECS/jellyfin.spec \
+ && mkdir -p ${SOURCE_DIR}/SOURCES \
+ && ln -s ${PLATFORM_DIR}/pkg-src ${SOURCE_DIR}/SOURCES
+
+VOLUME ${ARTIFACT_DIR}/
+
+COPY . ${SOURCE_DIR}/
+
+ENTRYPOINT ["/docker-build.sh"]
diff --git a/deployment/fedora-package-x64/clean.sh b/deployment/fedora-package-x64/clean.sh
index d7233208f..408167e49 100755
--- a/deployment/fedora-package-x64/clean.sh
+++ b/deployment/fedora-package-x64/clean.sh
@@ -2,17 +2,33 @@
source ../common.build.sh
-VERSION=`get_version ../..`
-
-package_temporary_dir="`pwd`/pkg-dist-tmp"
-pkg_src_dir="`pwd`/pkg-src"
-image_name="jellyfin-rpmbuild"
-docker_sudo=""
-if ! $(id -Gn | grep -q 'docker') && [ ! ${EUID:-1000} -eq 0 ] && \
- [ ! $USER == "root" ] && ! $(echo "$OSTYPE" | grep -q "darwin"); then
- docker_sudo=sudo
-fi
+keep_artifacts="${1}"
+
+WORKDIR="$( pwd )"
+VERSION="$( grep -A1 '^Version:' ${WORKDIR}/pkg-src/jellyfin.spec | awk '{ print $NF }' )"
+
+package_temporary_dir="${WORKDIR}/pkg-dist-tmp"
+package_source_dir="${WORKDIR}/pkg-src"
+output_dir="${WORKDIR}/pkg-dist"
+current_user="$( whoami )"
+image_name="jellyfin-fedora-build"
+
+rm -f "${package_source_dir}/jellyfin-${VERSION}.tar.gz" &>/dev/null \
+ || sudo rm -f "${package_source_dir}/jellyfin-${VERSION}.tar.gz" &>/dev/null
-$docker_sudo docker image rm $image_name --force
-rm -rf "$package_temporary_dir"
-rm -rf "$pkg_src_dir/jellyfin-${VERSION}.tar.gz"
+rm -rf "${package_temporary_dir}" &>/dev/null \
+ || sudo rm -rf "${package_temporary_dir}" &>/dev/null
+
+rm -rf "${output_dir}" &>/dev/null \
+ || sudo rm -rf "${output_dir}" &>/dev/null
+
+if [[ ${keep_artifacts} == 'n' ]]; then
+ docker_sudo=""
+ if [[ ! -z $(id -Gn | grep -q 'docker') ]] \
+ && [[ ! ${EUID:-1000} -eq 0 ]] \
+ && [[ ! ${USER} == "root" ]] \
+ && [[ ! -z $( echo "${OSTYPE}" | grep -q "darwin" ) ]]; then
+ docker_sudo=sudo
+ fi
+ ${docker_sudo} docker image rm ${image_name} --force
+fi
diff --git a/deployment/fedora-package-x64/docker-build.sh b/deployment/fedora-package-x64/docker-build.sh
new file mode 100755
index 000000000..3acf1ec0d
--- /dev/null
+++ b/deployment/fedora-package-x64/docker-build.sh
@@ -0,0 +1,20 @@
+#!/bin/bash
+
+# Builds the RPM inside the Docker container
+
+set -o errexit
+set -o xtrace
+
+# Move to source directory
+pushd ${SOURCE_DIR}
+
+ls -al SOURCES/pkg-src/
+
+# Build RPM
+spectool -g -R SPECS/jellyfin.spec
+rpmbuild -bs SPECS/jellyfin.spec --define "_sourcedir ${SOURCE_DIR}/SOURCES/pkg-src/"
+rpmbuild -bb SPECS/jellyfin.spec --define "_sourcedir ${SOURCE_DIR}/SOURCES/pkg-src/"
+
+# Move the artifacts out
+mkdir -p ${ARTIFACT_DIR}/rpm
+mv /root/rpmbuild/RPMS/x86_64/jellyfin-*.rpm /root/rpmbuild/SRPMS/jellyfin-*.src.rpm ${ARTIFACT_DIR}/rpm/
diff --git a/deployment/fedora-package-x64/package.sh b/deployment/fedora-package-x64/package.sh
index d459cdb24..74586417d 100755
--- a/deployment/fedora-package-x64/package.sh
+++ b/deployment/fedora-package-x64/package.sh
@@ -1,38 +1,29 @@
-#!/usr/bin/env sh
+#!/usr/bin/env bash
source ../common.build.sh
-VERSION=`get_version ../..`
+WORKDIR="$( pwd )"
+VERSION="$( grep '^Version:' ${WORKDIR}/pkg-src/jellyfin.spec | awk '{ print $NF }' )"
-# TODO get the version in the package automatically. And using the changelog to decide the debian package suffix version.
+package_temporary_dir="${WORKDIR}/pkg-dist-tmp"
+output_dir="${WORKDIR}/pkg-dist"
+pkg_src_dir="${WORKDIR}/pkg-src"
+current_user="$( whoami )"
+image_name="jellyfin-fedora-build"
-# Build a Jellyfin .rpm file with Docker on Linux
-# Places the output .rpm file in the parent directory
-
-set -o errexit
-set -o xtrace
-set -o nounset
-
-package_temporary_dir="`pwd`/pkg-dist-tmp"
-output_dir="`pwd`/pkg-dist"
-pkg_src_dir="`pwd`/pkg-src"
-current_user="`whoami`"
-image_name="jellyfin-rpmbuild"
-docker_sudo=""
-if ! $(id -Gn | grep -q 'docker') && [ ! ${EUID:-1000} -eq 0 ] && \
- [ ! $USER == "root" ] && ! $(echo "$OSTYPE" | grep -q "darwin"); then
- docker_sudo=sudo
+# Determine if sudo should be used for Docker
+if [[ ! -z $(id -Gn | grep -q 'docker') ]] \
+ && [[ ! ${EUID:-1000} -eq 0 ]] \
+ && [[ ! ${USER} == "root" ]] \
+ && [[ ! -z $( echo "${OSTYPE}" | grep -q "darwin" ) ]]; then
+ docker_sudo="sudo"
+else
+ docker_sudo=""
fi
-cleanup() {
- set +o errexit
- $docker_sudo docker image rm $image_name --force
- rm -rf "$package_temporary_dir"
- rm -rf "$pkg_src_dir/jellyfin-${VERSION}.tar.gz"
-}
-trap cleanup EXIT INT
+# Create RPM source archive
GNU_TAR=1
-mkdir -p "$package_temporary_dir"
+mkdir -p "${package_temporary_dir}"
echo "Bundling all sources for RPM build."
tar \
--transform "s,^\.,jellyfin-${VERSION}," \
@@ -47,12 +38,12 @@ tar \
--exclude='**/.nuget' \
--exclude='*.deb' \
--exclude='*.rpm' \
--zcf "$pkg_src_dir/jellyfin-${VERSION}.tar.gz" \
+-czf "${pkg_src_dir}/jellyfin-${VERSION}.tar.gz" \
-C "../.." ./ || GNU_TAR=0
if [ $GNU_TAR -eq 0 ]; then
echo "The installed tar binary did not support --transform. Using workaround."
- mkdir -p "$package_temporary_dir/jellyfin-${VERSION}"
+ mkdir -p "${package_temporary_dir}/jellyfin"
# Not GNU tar
tar \
--exclude='.git*' \
@@ -67,20 +58,23 @@ if [ $GNU_TAR -eq 0 ]; then
--exclude='*.deb' \
--exclude='*.rpm' \
-zcf \
- "$package_temporary_dir/jellyfin-${VERSION}/jellyfin.tar.gz" \
- -C "../.." \
- ./
+ "${package_temporary_dir}/jellyfin/jellyfin-${VERSION}.tar.gz" \
+ -C "../.." ./
echo "Extracting filtered package."
- tar -xzf "$package_temporary_dir/jellyfin-${VERSION}/jellyfin.tar.gz" -C "$package_temporary_dir/jellyfin-${VERSION}"
+ tar -xzf "${package_temporary_dir}/jellyfin/jellyfin-${VERSION}.tar.gz" -C "${package_temporary_dir}/jellyfin-${VERSION}"
echo "Removing filtered package."
- rm "$package_temporary_dir/jellyfin-${VERSION}/jellyfin.tar.gz"
+ rm -f "${package_temporary_dir}/jellyfin/jellyfin-${VERSION}.tar.gz"
echo "Repackaging package into final tarball."
- tar -zcf "$pkg_src_dir/jellyfin-${VERSION}.tar.gz" -C "$package_temporary_dir" "jellyfin-${VERSION}"
+ tar -czf "${pkg_src_dir}/jellyfin-${VERSION}.tar.gz" -C "${package_temporary_dir}" "jellyfin-${VERSION}"
fi
-$docker_sudo docker build ../.. -t "$image_name" -f ./Dockerfile
-mkdir -p "$output_dir"
-$docker_sudo docker run --rm -v "$package_temporary_dir:/temp" "$image_name" sh -c 'find /build/rpmbuild -maxdepth 3 -type f -name "jellyfin*.rpm" -exec mv {} /temp \;'
-chown -R "$current_user" "$package_temporary_dir" \
-|| sudo chown -R "$current_user" "$package_temporary_dir"
-mv "$package_temporary_dir"/*.rpm "$output_dir"
+# Set up the build environment Docker image
+${docker_sudo} docker build ../.. -t "${image_name}" -f ./Dockerfile
+# Build the RPMs and copy out to ${package_temporary_dir}
+${docker_sudo} docker run --rm -v "${package_temporary_dir}:/dist" "${image_name}"
+# Correct ownership on the RPMs (as current user, then as root if that fails)
+chown -R "${current_user}" "${package_temporary_dir}" \
+ || sudo chown -R "${current_user}" "${package_temporary_dir}"
+# Move the RPMs to the output directory
+mkdir -p "${output_dir}"
+mv "${package_temporary_dir}"/rpm/* "${output_dir}"
diff --git a/deployment/fedora-package-x64/pkg-src/jellyfin.env b/deployment/fedora-package-x64/pkg-src/jellyfin.env
index 827a33f46..abfa670e4 100644
--- a/deployment/fedora-package-x64/pkg-src/jellyfin.env
+++ b/deployment/fedora-package-x64/pkg-src/jellyfin.env
@@ -14,14 +14,22 @@
# General options
#
-# Tell jellyfin wich ffmpeg/ffprobe to use
-# JELLYFIN_FFMPEG="-ffmpeg /usr/bin/ffmpeg -ffprobe /usr/bin/ffprobe"
-
# Program directories
JELLYFIN_DATA_DIRECTORY="/var/lib/jellyfin"
JELLYFIN_CONFIG_DIRECTORY="/etc/jellyfin"
JELLYFIN_LOG_DIRECTORY="/var/log/jellyfin"
+JELLYFIN_CACHE_DIRECTORY="/var/cache/jellyfin"
+
# In-App service control
-JELLYFIN_RESTART_OPT="-restartpath /usr/libexec/jellyfin/restart.sh"
-# Additional options for the binary
-JELLYFIN_ADD_OPTS="" \ No newline at end of file
+JELLYFIN_RESTART_OPT="--restartpath=/usr/libexec/jellyfin/restart.sh"
+
+# [OPTIONAL] ffmpeg binary paths, overriding the UI-configured values
+#JELLYFIN_FFMPEG_OPT="--ffmpeg=/usr/bin/ffmpeg"
+#JELLYFIN_FFPROBE_OPT="--ffprobe=/usr/bin/ffprobe"
+
+# [OPTIONAL] run Jellyfin as a headless service
+#JELLYFIN_SERVICE_OPT="--service"
+
+# [OPTIONAL] run Jellyfin without the web app
+#JELLYFIN_NOWEBAPP_OPT="--noautorunwebapp"
+
diff --git a/deployment/fedora-package-x64/pkg-src/jellyfin.service b/deployment/fedora-package-x64/pkg-src/jellyfin.service
index 0ece5b57f..d58df9d94 100644
--- a/deployment/fedora-package-x64/pkg-src/jellyfin.service
+++ b/deployment/fedora-package-x64/pkg-src/jellyfin.service
@@ -5,7 +5,7 @@ Description=Jellyfin is a free software media system that puts you in control of
[Service]
EnvironmentFile=/etc/sysconfig/jellyfin
WorkingDirectory=/var/lib/jellyfin
-ExecStart=/usr/bin/jellyfin -programdata ${JELLYFIN_DATA_DIRECTORY} -configdir ${JELLYFIN_CONFIG_DIRECTORY} -logdir ${JELLYFIN_LOG_DIRECTORY} ${JELLYFIN_RESTART_OPT} ${JELLYFIN_ADD_OPTS} ${JELLYFIN_FFMPEG}
+ExecStart=/usr/bin/jellyfin --datadir=${JELLYFIN_DATA_DIRECTORY} --configdir=${JELLYFIN_CONFIG_DIRECTORY} --logdir=${JELLYFIN_LOG_DIRECTORY} --cachedir=${JELLYFIN_CACHE_DIRECTORY} ${JELLYFIN_RESTART_OPT} ${JELLYFIN_FFMPEG_OPT} ${JELLYFIN_FFPROBE_OPT} ${JELLYFIN_SERVICE_OPT} ${JELLYFIN_NOWEBAPP_OPT}
TimeoutSec=15
Restart=on-failure
User=jellyfin
diff --git a/deployment/fedora-package-x64/pkg-src/jellyfin.spec b/deployment/fedora-package-x64/pkg-src/jellyfin.spec
index 6a4a5870b..851c40044 100644
--- a/deployment/fedora-package-x64/pkg-src/jellyfin.spec
+++ b/deployment/fedora-package-x64/pkg-src/jellyfin.spec
@@ -1,11 +1,11 @@
%global debug_package %{nil}
-# jellyfin tag to package
-%global gittag v10.1.0
-# Taglib-sharp commit of the submodule since github archive doesn't include submodules
-%global taglib_commit ee5ab21742b71fd1b87ee24895582327e9e04776
-%global taglib_shortcommit %(c=%{taglib_commit}; echo ${c:0:7})
+# Set the dotnet runtime
+%if 0%{?fedora}
+%global dotnet_runtime fedora-x64
+%else
+%global dotnet_runtime centos-x64
+%endif
-AutoReq: no
Name: jellyfin
Version: 10.1.0
Release: 1%{?dist}
@@ -31,13 +31,11 @@ BuildRequires: dotnet-sdk-2.2
# RPMfusion free
Requires: ffmpeg
-# For the update-db-paths.sh script to fix emby paths to jellyfin
-%{?fedora:Recommends: sqlite}
-
# Fedora has openssl1.1 which is incompatible with dotnet
%{?fedora:Requires: compat-openssl10}
-# Disable Automatic Dependency Processing for Centos
-%{?el7:AutoReqProv: no}
+
+# Disable Automatic Dependency Processing
+AutoReqProv: no
%description
Jellyfin is a free software media system that puts you in control of managing and streaming your media.
@@ -51,7 +49,7 @@ Jellyfin is a free software media system that puts you in control of managing an
%install
export DOTNET_CLI_TELEMETRY_OPTOUT=1
export DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1
-dotnet publish --configuration Release --output='%{buildroot}%{_libdir}/jellyfin' --self-contained --runtime fedora-x64 Jellyfin.Server
+dotnet publish --configuration Release --output='%{buildroot}%{_libdir}/jellyfin' --self-contained --runtime %{dotnet_runtime} Jellyfin.Server
%{__install} -D -m 0644 LICENSE %{buildroot}%{_datadir}/licenses/%{name}/LICENSE
%{__install} -D -m 0644 %{SOURCE5} %{buildroot}%{_sysconfdir}/systemd/system/%{name}.service.d/override.conf
%{__install} -D -m 0644 Jellyfin.Server/Resources/Configuration/logging.json %{buildroot}%{_sysconfdir}/%{name}/logging.json
@@ -63,6 +61,7 @@ EOF
%{__mkdir} -p %{buildroot}%{_sharedstatedir}/jellyfin
%{__mkdir} -p %{buildroot}%{_sysconfdir}/%{name}
%{__mkdir} -p %{buildroot}%{_var}/log/jellyfin
+%{__mkdir} -p %{buildroot}%{_var}/cache/jellyfin
%{__install} -D -m 0644 %{SOURCE1} %{buildroot}%{_unitdir}/%{name}.service
%{__install} -D -m 0644 %{SOURCE2} %{buildroot}%{_sysconfdir}/sysconfig/%{name}
@@ -90,8 +89,9 @@ EOF
%config(noreplace) %attr(600,root,root) %{_sysconfdir}/sudoers.d/%{name}-sudoers
%config(noreplace) %{_sysconfdir}/systemd/system/%{name}.service.d/override.conf
%config(noreplace) %attr(644,jellyfin,jellyfin) %{_sysconfdir}/%{name}/logging.json
-%attr(-,jellyfin,jellyfin) %dir %{_sharedstatedir}/jellyfin
+%attr(750,jellyfin,jellyfin) %dir %{_sharedstatedir}/jellyfin
%attr(-,jellyfin,jellyfin) %dir %{_var}/log/jellyfin
+%attr(750,jellyfin,jellyfin) %dir %{_var}/cache/jellyfin
%if 0%{?fedora}
%license LICENSE
%else
@@ -106,7 +106,7 @@ getent passwd jellyfin >/dev/null || \
exit 0
%post
-# Move existing configuration to /etc/jellyfin and symlink config to /etc/jellyfin
+# Move existing configuration cache and logs to their new locations and symlink them.
if [ $1 -gt 1 ] ; then
service_state=$(systemctl is-active jellyfin.service)
if [ "${service_state}" = "active" ]; then
@@ -122,6 +122,11 @@ if [ $1 -gt 1 ] ; then
rmdir %{_sharedstatedir}/%{name}/logs
ln -sf %{_var}/log/jellyfin %{_sharedstatedir}/%{name}/logs
fi
+ if [ ! -L %{_sharedstatedir}/%{name}/cache ]; then
+ mv %{_sharedstatedir}/%{name}/cache/* %{_var}/cache/jellyfin
+ rmdir %{_sharedstatedir}/%{name}/cache
+ ln -sf %{_var}/cache/jellyfin %{_sharedstatedir}/%{name}/cache
+ fi
if [ "${service_state}" = "active" ]; then
systemctl start jellyfin.service
fi
diff --git a/deployment/fedora-package-x64/pkg-src/jellyfin.sudoers b/deployment/fedora-package-x64/pkg-src/jellyfin.sudoers
index b31d52f7e..dd245af4b 100644
--- a/deployment/fedora-package-x64/pkg-src/jellyfin.sudoers
+++ b/deployment/fedora-package-x64/pkg-src/jellyfin.sudoers
@@ -4,16 +4,16 @@ Cmnd_Alias STARTSERVER_SYSTEMD = /usr/bin/systemctl start jellyfin, /bin/systemc
Cmnd_Alias STOPSERVER_SYSTEMD = /usr/bin/systemctl stop jellyfin, /bin/systemctl stop jellyfin
-%jellyfin ALL=(ALL) NOPASSWD: RESTARTSERVER_SYSTEMD
-%jellyfin ALL=(ALL) NOPASSWD: STARTSERVER_SYSTEMD
-%jellyfin ALL=(ALL) NOPASSWD: STOPSERVER_SYSTEMD
+jellyfin ALL=(ALL) NOPASSWD: RESTARTSERVER_SYSTEMD
+jellyfin ALL=(ALL) NOPASSWD: STARTSERVER_SYSTEMD
+jellyfin ALL=(ALL) NOPASSWD: STOPSERVER_SYSTEMD
Defaults!RESTARTSERVER_SYSTEMD !requiretty
Defaults!STARTSERVER_SYSTEMD !requiretty
Defaults!STOPSERVER_SYSTEMD !requiretty
-# Uncomment to allow the server to mount iso images
-# %jellyfin ALL=(ALL) NOPASSWD: /bin/mount
-# %jellyfin ALL=(ALL) NOPASSWD: /bin/umount
+# Allow the server to mount iso images
+jellyfin ALL=(ALL) NOPASSWD: /bin/mount
+jellyfin ALL=(ALL) NOPASSWD: /bin/umount
-Defaults:%jellyfin !requiretty
+Defaults:jellyfin !requiretty
diff --git a/deployment/ubuntu-package-x64/Dockerfile b/deployment/ubuntu-package-x64/Dockerfile
new file mode 100644
index 000000000..485b6c42c
--- /dev/null
+++ b/deployment/ubuntu-package-x64/Dockerfile
@@ -0,0 +1,21 @@
+FROM microsoft/dotnet:2.2-sdk-bionic
+# Docker build arguments
+ARG SOURCE_DIR=/jellyfin
+ARG PLATFORM_DIR=/jellyfin/deployment/ubuntu-package-x64
+ARG ARTIFACT_DIR=/dist
+# Docker run environment
+ENV SOURCE_DIR=/jellyfin
+ENV ARTIFACT_DIR=/dist
+ENV DEB_BUILD_OPTIONS=noddebs
+
+# Prepare Ubuntu build environment
+RUN apt-get update \
+ && apt-get install -y apt-transport-https debhelper gnupg wget devscripts mmv libc6-dev libcurl4-openssl-dev libfontconfig1-dev libfreetype6-dev \
+ && ln -sf ${PLATFORM_DIR}/docker-build.sh /docker-build.sh \
+ && mkdir -p ${SOURCE_DIR} && ln -sf ${PLATFORM_DIR}/pkg-src ${SOURCE_DIR}/debian
+
+VOLUME ${ARTIFACT_DIR}/
+
+COPY . ${SOURCE_DIR}/
+
+ENTRYPOINT ["/docker-build.sh"]
diff --git a/deployment/ubuntu-package-x64/clean.sh b/deployment/ubuntu-package-x64/clean.sh
new file mode 100755
index 000000000..c92c7fdec
--- /dev/null
+++ b/deployment/ubuntu-package-x64/clean.sh
@@ -0,0 +1,29 @@
+#!/usr/bin/env bash
+
+source ../common.build.sh
+
+keep_artifacts="${1}"
+
+WORKDIR="$( pwd )"
+
+package_temporary_dir="${WORKDIR}/pkg-dist-tmp"
+output_dir="${WORKDIR}/pkg-dist"
+current_user="$( whoami )"
+image_name="jellyfin-ubuntu-build"
+
+rm -rf "${package_temporary_dir}" &>/dev/null \
+ || sudo rm -rf "${package_temporary_dir}" &>/dev/null
+
+rm -rf "${output_dir}" &>/dev/null \
+ || sudo rm -rf "${output_dir}" &>/dev/null
+
+if [[ ${keep_artifacts} == 'n' ]]; then
+ docker_sudo=""
+ if [[ ! -z $(id -Gn | grep -q 'docker') ]] \
+ && [[ ! ${EUID:-1000} -eq 0 ]] \
+ && [[ ! ${USER} == "root" ]] \
+ && [[ ! -z $( echo "${OSTYPE}" | grep -q "darwin" ) ]]; then
+ docker_sudo=sudo
+ fi
+ ${docker_sudo} docker image rm ${image_name} --force
+fi
diff --git a/deployment/ubuntu-package-x64/dependencies.txt b/deployment/ubuntu-package-x64/dependencies.txt
new file mode 100644
index 000000000..bdb967096
--- /dev/null
+++ b/deployment/ubuntu-package-x64/dependencies.txt
@@ -0,0 +1 @@
+docker
diff --git a/deployment/ubuntu-package-x64/docker-build.sh b/deployment/ubuntu-package-x64/docker-build.sh
new file mode 100755
index 000000000..0590be097
--- /dev/null
+++ b/deployment/ubuntu-package-x64/docker-build.sh
@@ -0,0 +1,19 @@
+#!/bin/bash
+
+# Builds the DEB inside the Docker container
+
+set -o errexit
+set -o xtrace
+
+# Move to source directory
+pushd ${SOURCE_DIR}
+
+# Remove build-dep for dotnet-sdk-2.2, since it's not a package in this image
+sed -i '/dotnet-sdk-2.2,/d' debian/control
+
+# Build DEB
+dpkg-buildpackage -us -uc
+
+# Move the artifacts out
+mkdir -p ${ARTIFACT_DIR}/deb
+mv /jellyfin_* ${ARTIFACT_DIR}/deb/
diff --git a/deployment/ubuntu-package-x64/package.sh b/deployment/ubuntu-package-x64/package.sh
new file mode 100755
index 000000000..6d4625a19
--- /dev/null
+++ b/deployment/ubuntu-package-x64/package.sh
@@ -0,0 +1,31 @@
+#!/usr/bin/env bash
+
+source ../common.build.sh
+
+WORKDIR="$( pwd )"
+
+package_temporary_dir="${WORKDIR}/pkg-dist-tmp"
+output_dir="${WORKDIR}/pkg-dist"
+current_user="$( whoami )"
+image_name="jellyfin-ubuntu-build"
+
+# Determine if sudo should be used for Docker
+if [[ ! -z $(id -Gn | grep -q 'docker') ]] \
+ && [[ ! ${EUID:-1000} -eq 0 ]] \
+ && [[ ! ${USER} == "root" ]] \
+ && [[ ! -z $( echo "${OSTYPE}" | grep -q "darwin" ) ]]; then
+ docker_sudo="sudo"
+else
+ docker_sudo=""
+fi
+
+# Set up the build environment Docker image
+${docker_sudo} docker build ../.. -t "${image_name}" -f ./Dockerfile
+# Build the DEBs and copy out to ${package_temporary_dir}
+${docker_sudo} docker run --rm -v "${package_temporary_dir}:/dist" "${image_name}"
+# Correct ownership on the DEBs (as current user, then as root if that fails)
+chown -R "${current_user}" "${package_temporary_dir}" &>/dev/null \
+ || sudo chown -R "${current_user}" "${package_temporary_dir}" &>/dev/null
+# Move the DEBs to the output directory
+mkdir -p "${output_dir}"
+mv "${package_temporary_dir}"/deb/* "${output_dir}"
diff --git a/deployment/ubuntu-package-x64/pkg-src b/deployment/ubuntu-package-x64/pkg-src
new file mode 120000
index 000000000..4c695fea1
--- /dev/null
+++ b/deployment/ubuntu-package-x64/pkg-src
@@ -0,0 +1 @@
+../debian-package-x64/pkg-src \ No newline at end of file
diff --git a/deployment/win-generic/install-jellyfin.ps1 b/deployment/win-generic/install-jellyfin.ps1
index 56c098462..b6e00e056 100644
--- a/deployment/win-generic/install-jellyfin.ps1
+++ b/deployment/win-generic/install-jellyfin.ps1
@@ -93,12 +93,12 @@ if($Quiet.IsPresent -or $Quiet -eq $true){
Copy-Item -Path $PSScriptRoot/* -DestinationPath "$Script:DefaultJellyfinInstallDirectory/" -Force -Recurse
if($Script:InstallAsService){
if($Script:InstallServiceAsUser){
- &"$Script:DefaultJellyfinInstallDirectory\nssm.exe" install Jellyfin `"$Script:DefaultJellyfinInstallDirectory\jellyfin.exe`" -programdata `"$Script:JellyfinDataDir`"
+ &"$Script:DefaultJellyfinInstallDirectory\nssm.exe" install Jellyfin `"$Script:DefaultJellyfinInstallDirectory\jellyfin.exe`" --datadir `"$Script:JellyfinDataDir`"
Start-Sleep -Milliseconds 500
&sc.exe config Jellyfin obj=".\$($Script:UserCredentials.UserName)" password="$($Script:UserCredentials.GetNetworkCredential().Password)"
&"$Script:DefaultJellyfinInstallDirectory\nssm.exe" set Jellyfin Start SERVICE_DELAYED_AUTO_START
}else{
- &"$Script:DefaultJellyfinInstallDirectory\nssm.exe" install Jellyfin `"$Script:DefaultJellyfinInstallDirectory\jellyfin.exe`" -programdata `"$Script:JellyfinDataDir`"
+ &"$Script:DefaultJellyfinInstallDirectory\nssm.exe" install Jellyfin `"$Script:DefaultJellyfinInstallDirectory\jellyfin.exe`" --datadir `"$Script:JellyfinDataDir`"
Start-Sleep -Milliseconds 500
#&"$Script:DefaultJellyfinInstallDirectory\nssm.exe" set Jellyfin ObjectName $Script:UserCredentials.UserName $Script:UserCredentials.GetNetworkCredential().Password
#Set-Service -Name Jellyfin -Credential $Script:UserCredentials
@@ -171,13 +171,13 @@ function InstallJellyfin {
if($Script:InstallAsService){
if($Script:InstallServiceAsUser){
Write-Host "Installing Service as user $($Script:UserCredentials.UserName)"
- &"$Script:DefaultJellyfinInstallDirectory\nssm.exe" install Jellyfin `"$Script:DefaultJellyfinInstallDirectory\jellyfin.exe`" -programdata `"$Script:JellyfinDataDir`"
+ &"$Script:DefaultJellyfinInstallDirectory\nssm.exe" install Jellyfin `"$Script:DefaultJellyfinInstallDirectory\jellyfin.exe`" --datadir `"$Script:JellyfinDataDir`"
Start-Sleep -Milliseconds 2000
&sc.exe config Jellyfin obj=".\$($Script:UserCredentials.UserName)" password="$($Script:UserCredentials.GetNetworkCredential().Password)"
&"$Script:DefaultJellyfinInstallDirectory\nssm.exe" set Jellyfin Start SERVICE_DELAYED_AUTO_START
}else{
Write-Host "Installing Service as LocalSystem"
- &"$Script:DefaultJellyfinInstallDirectory\nssm.exe" install Jellyfin `"$Script:DefaultJellyfinInstallDirectory\jellyfin.exe`" -programdata `"$Script:JellyfinDataDir`"
+ &"$Script:DefaultJellyfinInstallDirectory\nssm.exe" install Jellyfin `"$Script:DefaultJellyfinInstallDirectory\jellyfin.exe`" --datadir `"$Script:JellyfinDataDir`"
Start-Sleep -Milliseconds 2000
&"$Script:DefaultJellyfinInstallDirectory\nssm.exe" set Jellyfin Start SERVICE_DELAYED_AUTO_START
}
@@ -457,4 +457,4 @@ $StartProgramCheck.Add_CheckedChanged({StartJellyFinBoxCheckChanged})
#endregion GUI }
-[void]$InstallForm.ShowDialog() \ No newline at end of file
+[void]$InstallForm.ShowDialog()