aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.ci/azure-pipelines-main.yml8
-rw-r--r--.ci/azure-pipelines-test.yml9
-rw-r--r--.vscode/tasks.json2
-rw-r--r--CONTRIBUTORS.md1
-rw-r--r--Emby.Dlna/ConnectionManager/ConnectionManagerService.cs6
-rw-r--r--Emby.Dlna/ContentDirectory/ContentDirectoryService.cs4
-rw-r--r--Emby.Dlna/Emby.Dlna.csproj1
-rw-r--r--Emby.Dlna/Eventing/DlnaEventManager.cs30
-rw-r--r--Emby.Dlna/Main/DlnaEntryPoint.cs15
-rw-r--r--Emby.Dlna/MediaReceiverRegistrar/MediaReceiverRegistrarService.cs6
-rw-r--r--Emby.Dlna/PlayTo/Device.cs41
-rw-r--r--Emby.Dlna/PlayTo/PlayToManager.cs9
-rw-r--r--Emby.Dlna/PlayTo/SsdpHttpClient.cs116
-rw-r--r--Emby.Dlna/Service/BaseService.cs10
-rw-r--r--Emby.Server.Implementations/ApplicationHost.cs35
-rw-r--r--Emby.Server.Implementations/HttpClientManager/HttpClientManager.cs335
-rw-r--r--Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs50
-rw-r--r--Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs9
-rw-r--r--Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs378
-rw-r--r--Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs31
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs98
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs13
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs16
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs47
-rw-r--r--Emby.Server.Implementations/Updates/InstallationManager.cs88
-rw-r--r--Jellyfin.Api/Controllers/LiveTvController.cs3
-rw-r--r--Jellyfin.Api/Controllers/RemoteImageController.cs3
-rw-r--r--Jellyfin.Api/Controllers/VideosController.cs3
-rw-r--r--Jellyfin.Api/Helpers/AudioHelper.cs3
-rw-r--r--Jellyfin.Api/Helpers/FileStreamResponseHelpers.cs2
-rw-r--r--Jellyfin.Data/Entities/ActivityLog.cs78
-rw-r--r--Jellyfin.Data/Entities/DisplayPreferences.cs4
-rw-r--r--Jellyfin.Data/Entities/Group.cs61
-rw-r--r--Jellyfin.Data/Entities/ImageInfo.cs45
-rw-r--r--Jellyfin.Data/Entities/ItemDisplayPreferences.cs7
-rw-r--r--Jellyfin.Data/Entities/Libraries/Artwork.cs2
-rw-r--r--Jellyfin.Data/Entities/Libraries/Book.cs2
-rw-r--r--Jellyfin.Data/Entities/Libraries/BookMetadata.cs4
-rw-r--r--Jellyfin.Data/Entities/Libraries/Chapter.cs2
-rw-r--r--Jellyfin.Data/Entities/Libraries/Collection.cs2
-rw-r--r--Jellyfin.Data/Entities/Libraries/CollectionItem.cs4
-rw-r--r--Jellyfin.Data/Entities/Libraries/Company.cs2
-rw-r--r--Jellyfin.Data/Entities/Libraries/CompanyMetadata.cs2
-rw-r--r--Jellyfin.Data/Entities/Libraries/CustomItem.cs2
-rw-r--r--Jellyfin.Data/Entities/Libraries/CustomItemMetadata.cs2
-rw-r--r--Jellyfin.Data/Entities/Libraries/Episode.cs2
-rw-r--r--Jellyfin.Data/Entities/Libraries/EpisodeMetadata.cs2
-rw-r--r--Jellyfin.Data/Entities/Libraries/Genre.cs10
-rw-r--r--Jellyfin.Data/Entities/Libraries/ItemMetadata.cs (renamed from Jellyfin.Data/Entities/Libraries/Metadata.cs)12
-rw-r--r--Jellyfin.Data/Entities/Libraries/MediaFile.cs2
-rw-r--r--Jellyfin.Data/Entities/Libraries/MetadataProviderId.cs10
-rw-r--r--Jellyfin.Data/Entities/Libraries/Movie.cs2
-rw-r--r--Jellyfin.Data/Entities/Libraries/MovieMetadata.cs4
-rw-r--r--Jellyfin.Data/Entities/Libraries/MusicAlbum.cs2
-rw-r--r--Jellyfin.Data/Entities/Libraries/MusicAlbumMetadata.cs4
-rw-r--r--Jellyfin.Data/Entities/Libraries/Person.cs2
-rw-r--r--Jellyfin.Data/Entities/Libraries/PersonRole.cs12
-rw-r--r--Jellyfin.Data/Entities/Libraries/Photo.cs2
-rw-r--r--Jellyfin.Data/Entities/Libraries/PhotoMetadata.cs2
-rw-r--r--Jellyfin.Data/Entities/Libraries/Rating.cs10
-rw-r--r--Jellyfin.Data/Entities/Libraries/Release.cs2
-rw-r--r--Jellyfin.Data/Entities/Libraries/Season.cs2
-rw-r--r--Jellyfin.Data/Entities/Libraries/SeasonMetadata.cs2
-rw-r--r--Jellyfin.Data/Entities/Libraries/Series.cs2
-rw-r--r--Jellyfin.Data/Entities/Libraries/SeriesMetadata.cs4
-rw-r--r--Jellyfin.Data/Entities/Libraries/Track.cs2
-rw-r--r--Jellyfin.Data/Entities/Libraries/TrackMetadata.cs2
-rw-r--r--Jellyfin.Data/Entities/Permission.cs36
-rw-r--r--Jellyfin.Data/Entities/Preference.cs26
-rw-r--r--Jellyfin.Data/Entities/ProviderMapping.cs129
-rw-r--r--Jellyfin.Data/Entities/User.cs49
-rw-r--r--Jellyfin.Data/Enums/ArtKind.cs34
-rw-r--r--Jellyfin.Data/Enums/DynamicDayOfWeek.cs44
-rw-r--r--Jellyfin.Data/Enums/IndexingKind.cs7
-rw-r--r--Jellyfin.Data/Enums/MediaFileKind.cs34
-rw-r--r--Jellyfin.Data/Enums/PersonRoleType.cs76
-rw-r--r--Jellyfin.Data/Enums/SubtitlePlaybackMode.cs26
-rw-r--r--Jellyfin.Data/Enums/UnratedItem.cs58
-rw-r--r--Jellyfin.Data/Jellyfin.Data.csproj6
-rw-r--r--MediaBrowser.Common/Net/CacheMode.cs11
-rw-r--r--MediaBrowser.Common/Net/CompressionMethods.cs15
-rw-r--r--MediaBrowser.Common/Net/HttpRequestOptions.cs105
-rw-r--r--MediaBrowser.Common/Net/HttpResponseInfo.cs80
-rw-r--r--MediaBrowser.Common/Net/IHttpClient.cs53
-rw-r--r--MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj1
-rw-r--r--MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs27
-rw-r--r--MediaBrowser.Model/Net/MimeTypes.cs2
-rw-r--r--MediaBrowser.Providers/Manager/ProviderManager.cs2
-rw-r--r--MediaBrowser.Providers/Plugins/AudioDb/AlbumImageProvider.cs3
-rw-r--r--MediaBrowser.Providers/Plugins/AudioDb/AlbumProvider.cs3
-rw-r--r--MediaBrowser.Providers/Plugins/AudioDb/ArtistImageProvider.cs3
-rw-r--r--MediaBrowser.Providers/Plugins/AudioDb/ArtistProvider.cs3
-rw-r--r--MediaBrowser.Providers/Plugins/MusicBrainz/AlbumProvider.cs3
-rw-r--r--MediaBrowser.Providers/Plugins/Omdb/OmdbImageProvider.cs3
-rw-r--r--MediaBrowser.Providers/Plugins/Omdb/OmdbItemProvider.cs5
-rw-r--r--MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs5
-rw-r--r--MediaBrowser.Providers/Plugins/TheTvdb/TvdbEpisodeImageProvider.cs3
-rw-r--r--MediaBrowser.Providers/Plugins/TheTvdb/TvdbEpisodeProvider.cs10
-rw-r--r--MediaBrowser.Providers/Plugins/TheTvdb/TvdbPersonImageProvider.cs3
-rw-r--r--MediaBrowser.Providers/Plugins/TheTvdb/TvdbSeasonImageProvider.cs3
-rw-r--r--MediaBrowser.Providers/Plugins/TheTvdb/TvdbSeriesImageProvider.cs3
-rw-r--r--MediaBrowser.Providers/Plugins/TheTvdb/TvdbSeriesProvider.cs3
-rw-r--r--MediaBrowser.Providers/Plugins/Tmdb/BoxSets/TmdbBoxSetImageProvider.cs3
-rw-r--r--MediaBrowser.Providers/Plugins/Tmdb/BoxSets/TmdbBoxSetProvider.cs3
-rw-r--r--MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbImageProvider.cs3
-rw-r--r--MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieProvider.cs5
-rw-r--r--MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonImageProvider.cs3
-rw-r--r--MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonProvider.cs3
-rw-r--r--MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeProviderBase.cs3
-rw-r--r--MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeasonImageProvider.cs3
-rw-r--r--MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeasonProvider.cs3
-rw-r--r--MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeriesImageProvider.cs3
-rw-r--r--MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeriesProvider.cs3
-rw-r--r--MediaBrowser.Providers/Plugins/Tmdb/Trailers/TmdbTrailerProvider.cs3
-rw-r--r--MediaBrowser.Providers/Studios/StudiosImageProvider.cs5
-rw-r--r--MediaBrowser.sln6
-rw-r--r--tests/Jellyfin.Api.Tests/BrandingServiceTests.cs (renamed from tests/MediaBrowser.Api.Tests/BrandingServiceTests.cs)2
-rw-r--r--tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj1
-rw-r--r--tests/Jellyfin.Api.Tests/JellyfinApplicationFactory.cs (renamed from tests/MediaBrowser.Api.Tests/JellyfinApplicationFactory.cs)2
-rw-r--r--tests/Jellyfin.Api.Tests/OpenApiSpecTests.cs42
-rw-r--r--tests/MediaBrowser.Api.Tests/MediaBrowser.Api.Tests.csproj34
-rw-r--r--tests/jellyfin-tests.ruleset4
122 files changed, 958 insertions, 1735 deletions
diff --git a/.ci/azure-pipelines-main.yml b/.ci/azure-pipelines-main.yml
index 2a1c0e6f2..7617f0f5a 100644
--- a/.ci/azure-pipelines-main.yml
+++ b/.ci/azure-pipelines-main.yml
@@ -64,28 +64,28 @@ jobs:
arguments: '--configuration $(BuildConfiguration) --output $(Build.ArtifactStagingDirectory)'
zipAfterPublish: false
- - task: PublishPipelineArtifact@0
+ - task: PublishPipelineArtifact@1
displayName: 'Publish Artifact Naming'
condition: and(succeeded(), eq(variables['BuildConfiguration'], 'Release'))
inputs:
targetPath: '$(build.ArtifactStagingDirectory)/Jellyfin.Server/Emby.Naming.dll'
artifactName: 'Jellyfin.Naming'
- - task: PublishPipelineArtifact@0
+ - task: PublishPipelineArtifact@1
displayName: 'Publish Artifact Controller'
condition: and(succeeded(), eq(variables['BuildConfiguration'], 'Release'))
inputs:
targetPath: '$(build.ArtifactStagingDirectory)/Jellyfin.Server/MediaBrowser.Controller.dll'
artifactName: 'Jellyfin.Controller'
- - task: PublishPipelineArtifact@0
+ - task: PublishPipelineArtifact@1
displayName: 'Publish Artifact Model'
condition: and(succeeded(), eq(variables['BuildConfiguration'], 'Release'))
inputs:
targetPath: '$(build.ArtifactStagingDirectory)/Jellyfin.Server/MediaBrowser.Model.dll'
artifactName: 'Jellyfin.Model'
- - task: PublishPipelineArtifact@0
+ - task: PublishPipelineArtifact@1
displayName: 'Publish Artifact Common'
condition: and(succeeded(), eq(variables['BuildConfiguration'], 'Release'))
inputs:
diff --git a/.ci/azure-pipelines-test.yml b/.ci/azure-pipelines-test.yml
index a3c7f8526..eca8aa90f 100644
--- a/.ci/azure-pipelines-test.yml
+++ b/.ci/azure-pipelines-test.yml
@@ -74,7 +74,6 @@ jobs:
- task: Palmmedia.reportgenerator.reportgenerator-build-release-task.reportgenerator@4
condition: and(succeeded(), eq(variables['Agent.OS'], 'Linux')) # !! THIS is for V1 only V2 will/should support merging
displayName: 'Run ReportGenerator'
- enabled: false
inputs:
reports: "$(Agent.TempDirectory)/**/coverage.cobertura.xml"
targetdir: "$(Agent.TempDirectory)/merged/"
@@ -84,10 +83,16 @@ jobs:
- task: PublishCodeCoverageResults@1
condition: and(succeeded(), eq(variables['Agent.OS'], 'Linux')) # !! THIS is for V1 only V2 will/should support merging
displayName: 'Publish Code Coverage'
- enabled: false
inputs:
codeCoverageTool: "cobertura"
#summaryFileLocation: '$(Agent.TempDirectory)/**/coverage.cobertura.xml' # !!THIS IS FOR V2
summaryFileLocation: "$(Agent.TempDirectory)/merged/**.xml"
pathToSources: $(Build.SourcesDirectory)
failIfCoverageEmpty: true
+
+ - task: PublishPipelineArtifact@1
+ displayName: 'Publish OpenAPI Artifact'
+ condition: and(succeeded(), eq(variables['Agent.OS'], 'Linux'))
+ inputs:
+ targetPath: "tests/Jellyfin.Api.Tests/bin/Release/netcoreapp3.1/openapi.json"
+ artifactName: 'OpenAPI Spec'
diff --git a/.vscode/tasks.json b/.vscode/tasks.json
index 7ddc49d5c..09c523eb2 100644
--- a/.vscode/tasks.json
+++ b/.vscode/tasks.json
@@ -17,7 +17,7 @@
"type": "process",
"args": [
"test",
- "${workspaceFolder}/tests/MediaBrowser.Api.Tests/MediaBrowser.Api.Tests.csproj"
+ "${workspaceFolder}/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj"
],
"problemMatcher": "$msCompile"
}
diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md
index e383d02b7..f0724b412 100644
--- a/CONTRIBUTORS.md
+++ b/CONTRIBUTORS.md
@@ -57,6 +57,7 @@
- [Larvitar](https://github.com/Larvitar)
- [LeoVerto](https://github.com/LeoVerto)
- [Liggy](https://github.com/Liggy)
+ - [lmaonator](https://github.com/lmaonator)
- [LogicalPhallacy](https://github.com/LogicalPhallacy)
- [loli10K](https://github.com/loli10K)
- [lostmypillow](https://github.com/lostmypillow)
diff --git a/Emby.Dlna/ConnectionManager/ConnectionManagerService.cs b/Emby.Dlna/ConnectionManager/ConnectionManagerService.cs
index 12338e2b4..f5a7eca72 100644
--- a/Emby.Dlna/ConnectionManager/ConnectionManagerService.cs
+++ b/Emby.Dlna/ConnectionManager/ConnectionManagerService.cs
@@ -1,8 +1,8 @@
#pragma warning disable CS1591
+using System.Net.Http;
using System.Threading.Tasks;
using Emby.Dlna.Service;
-using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Dlna;
using Microsoft.Extensions.Logging;
@@ -18,8 +18,8 @@ namespace Emby.Dlna.ConnectionManager
IDlnaManager dlna,
IServerConfigurationManager config,
ILogger<ConnectionManagerService> logger,
- IHttpClient httpClient)
- : base(logger, httpClient)
+ IHttpClientFactory httpClientFactory)
+ : base(logger, httpClientFactory)
{
_dlna = dlna;
_config = config;
diff --git a/Emby.Dlna/ContentDirectory/ContentDirectoryService.cs b/Emby.Dlna/ContentDirectory/ContentDirectoryService.cs
index 72732823a..5760f260c 100644
--- a/Emby.Dlna/ContentDirectory/ContentDirectoryService.cs
+++ b/Emby.Dlna/ContentDirectory/ContentDirectoryService.cs
@@ -2,11 +2,11 @@
using System;
using System.Linq;
+using System.Net.Http;
using System.Threading.Tasks;
using Emby.Dlna.Service;
using Jellyfin.Data.Entities;
using Jellyfin.Data.Enums;
-using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Dlna;
using MediaBrowser.Controller.Drawing;
@@ -41,7 +41,7 @@ namespace Emby.Dlna.ContentDirectory
IServerConfigurationManager config,
IUserManager userManager,
ILogger<ContentDirectoryService> logger,
- IHttpClient httpClient,
+ IHttpClientFactory httpClient,
ILocalizationManager localization,
IMediaSourceManager mediaSourceManager,
IUserViewManager userViewManager,
diff --git a/Emby.Dlna/Emby.Dlna.csproj b/Emby.Dlna/Emby.Dlna.csproj
index 8538f580c..6ed49944c 100644
--- a/Emby.Dlna/Emby.Dlna.csproj
+++ b/Emby.Dlna/Emby.Dlna.csproj
@@ -80,6 +80,7 @@
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Http" Version="2.2.2" />
<PackageReference Include="Microsoft.AspNetCore.WebUtilities" Version="2.2.0" />
+ <PackageReference Include="Microsoft.Extensions.Http" Version="3.1.6" />
</ItemGroup>
</Project>
diff --git a/Emby.Dlna/Eventing/DlnaEventManager.cs b/Emby.Dlna/Eventing/DlnaEventManager.cs
index b66e966df..7d8da86ef 100644
--- a/Emby.Dlna/Eventing/DlnaEventManager.cs
+++ b/Emby.Dlna/Eventing/DlnaEventManager.cs
@@ -6,6 +6,7 @@ using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Net.Http;
+using System.Net.Mime;
using System.Text;
using System.Threading.Tasks;
using MediaBrowser.Common.Extensions;
@@ -20,13 +21,13 @@ namespace Emby.Dlna.Eventing
new ConcurrentDictionary<string, EventSubscription>(StringComparer.OrdinalIgnoreCase);
private readonly ILogger _logger;
- private readonly IHttpClient _httpClient;
+ private readonly IHttpClientFactory _httpClientFactory;
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
- public DlnaEventManager(ILogger logger, IHttpClient httpClient)
+ public DlnaEventManager(ILogger logger, IHttpClientFactory httpClientFactory)
{
- _httpClient = httpClient;
+ _httpClientFactory = httpClientFactory;
_logger = logger;
}
@@ -167,24 +168,17 @@ namespace Emby.Dlna.Eventing
builder.Append("</e:propertyset>");
- var options = new HttpRequestOptions
- {
- RequestContent = builder.ToString(),
- RequestContentType = "text/xml",
- Url = subscription.CallbackUrl,
- BufferContent = false
- };
-
- options.RequestHeaders.Add("NT", subscription.NotificationType);
- options.RequestHeaders.Add("NTS", "upnp:propchange");
- options.RequestHeaders.Add("SID", subscription.Id);
- options.RequestHeaders.Add("SEQ", subscription.TriggerCount.ToString(_usCulture));
+ using var options = new HttpRequestMessage(new HttpMethod("NOTIFY"), subscription.CallbackUrl);
+ options.Content = new StringContent(builder.ToString(), Encoding.UTF8, MediaTypeNames.Text.Xml);
+ options.Headers.TryAddWithoutValidation("NT", subscription.NotificationType);
+ options.Headers.TryAddWithoutValidation("NTS", "upnp:propchange");
+ options.Headers.TryAddWithoutValidation("SID", subscription.Id);
+ options.Headers.TryAddWithoutValidation("SEQ", subscription.TriggerCount.ToString(_usCulture));
try
{
- using (await _httpClient.SendAsync(options, new HttpMethod("NOTIFY")).ConfigureAwait(false))
- {
- }
+ using var response = await _httpClientFactory.CreateClient(NamedClient.Default)
+ .SendAsync(options, HttpCompletionOption.ResponseHeadersRead).ConfigureAwait(false);
}
catch (OperationCanceledException)
{
diff --git a/Emby.Dlna/Main/DlnaEntryPoint.cs b/Emby.Dlna/Main/DlnaEntryPoint.cs
index 0ad82022d..40c2cc0e0 100644
--- a/Emby.Dlna/Main/DlnaEntryPoint.cs
+++ b/Emby.Dlna/Main/DlnaEntryPoint.cs
@@ -2,6 +2,7 @@
using System;
using System.Globalization;
+using System.Net.Http;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;
@@ -36,7 +37,7 @@ namespace Emby.Dlna.Main
private readonly ILogger<DlnaEntryPoint> _logger;
private readonly IServerApplicationHost _appHost;
private readonly ISessionManager _sessionManager;
- private readonly IHttpClient _httpClient;
+ private readonly IHttpClientFactory _httpClientFactory;
private readonly ILibraryManager _libraryManager;
private readonly IUserManager _userManager;
private readonly IDlnaManager _dlnaManager;
@@ -61,7 +62,7 @@ namespace Emby.Dlna.Main
ILoggerFactory loggerFactory,
IServerApplicationHost appHost,
ISessionManager sessionManager,
- IHttpClient httpClient,
+ IHttpClientFactory httpClientFactory,
ILibraryManager libraryManager,
IUserManager userManager,
IDlnaManager dlnaManager,
@@ -79,7 +80,7 @@ namespace Emby.Dlna.Main
_config = config;
_appHost = appHost;
_sessionManager = sessionManager;
- _httpClient = httpClient;
+ _httpClientFactory = httpClientFactory;
_libraryManager = libraryManager;
_userManager = userManager;
_dlnaManager = dlnaManager;
@@ -101,7 +102,7 @@ namespace Emby.Dlna.Main
config,
userManager,
loggerFactory.CreateLogger<ContentDirectory.ContentDirectoryService>(),
- httpClient,
+ httpClientFactory,
localizationManager,
mediaSourceManager,
userViewManager,
@@ -112,11 +113,11 @@ namespace Emby.Dlna.Main
dlnaManager,
config,
loggerFactory.CreateLogger<ConnectionManager.ConnectionManagerService>(),
- httpClient);
+ httpClientFactory);
MediaReceiverRegistrar = new MediaReceiverRegistrar.MediaReceiverRegistrarService(
loggerFactory.CreateLogger<MediaReceiverRegistrar.MediaReceiverRegistrarService>(),
- httpClient,
+ httpClientFactory,
config);
Current = this;
}
@@ -364,7 +365,7 @@ namespace Emby.Dlna.Main
_appHost,
_imageProcessor,
_deviceDiscovery,
- _httpClient,
+ _httpClientFactory,
_config,
_userDataManager,
_localization,
diff --git a/Emby.Dlna/MediaReceiverRegistrar/MediaReceiverRegistrarService.cs b/Emby.Dlna/MediaReceiverRegistrar/MediaReceiverRegistrarService.cs
index 28de2fef5..e6d845e1e 100644
--- a/Emby.Dlna/MediaReceiverRegistrar/MediaReceiverRegistrarService.cs
+++ b/Emby.Dlna/MediaReceiverRegistrar/MediaReceiverRegistrarService.cs
@@ -1,8 +1,8 @@
#pragma warning disable CS1591
+using System.Net.Http;
using System.Threading.Tasks;
using Emby.Dlna.Service;
-using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Configuration;
using Microsoft.Extensions.Logging;
@@ -14,9 +14,9 @@ namespace Emby.Dlna.MediaReceiverRegistrar
public MediaReceiverRegistrarService(
ILogger<MediaReceiverRegistrarService> logger,
- IHttpClient httpClient,
+ IHttpClientFactory httpClientFactory,
IServerConfigurationManager config)
- : base(logger, httpClient)
+ : base(logger, httpClientFactory)
{
_config = config;
}
diff --git a/Emby.Dlna/PlayTo/Device.cs b/Emby.Dlna/PlayTo/Device.cs
index 5462e7abc..c97acdb02 100644
--- a/Emby.Dlna/PlayTo/Device.cs
+++ b/Emby.Dlna/PlayTo/Device.cs
@@ -4,6 +4,7 @@ using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
+using System.Net.Http;
using System.Security;
using System.Threading;
using System.Threading.Tasks;
@@ -21,7 +22,7 @@ namespace Emby.Dlna.PlayTo
{
private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
- private readonly IHttpClient _httpClient;
+ private readonly IHttpClientFactory _httpClientFactory;
private readonly ILogger _logger;
@@ -34,10 +35,10 @@ namespace Emby.Dlna.PlayTo
private int _connectFailureCount;
private bool _disposed;
- public Device(DeviceInfo deviceProperties, IHttpClient httpClient, ILogger logger)
+ public Device(DeviceInfo deviceProperties, IHttpClientFactory httpClientFactory, ILogger logger)
{
Properties = deviceProperties;
- _httpClient = httpClient;
+ _httpClientFactory = httpClientFactory;
_logger = logger;
}
@@ -236,7 +237,7 @@ namespace Emby.Dlna.PlayTo
_logger.LogDebug("Setting mute");
var value = mute ? 1 : 0;
- await new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, rendererCommands.BuildPost(command, service.ServiceType, value))
+ await new SsdpHttpClient(_httpClientFactory).SendCommandAsync(Properties.BaseUrl, service, command.Name, rendererCommands.BuildPost(command, service.ServiceType, value))
.ConfigureAwait(false);
IsMuted = mute;
@@ -271,7 +272,7 @@ namespace Emby.Dlna.PlayTo
// Remote control will perform better
Volume = value;
- await new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, rendererCommands.BuildPost(command, service.ServiceType, value))
+ await new SsdpHttpClient(_httpClientFactory).SendCommandAsync(Properties.BaseUrl, service, command.Name, rendererCommands.BuildPost(command, service.ServiceType, value))
.ConfigureAwait(false);
}
@@ -292,7 +293,7 @@ namespace Emby.Dlna.PlayTo
throw new InvalidOperationException("Unable to find service");
}
- await new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, avCommands.BuildPost(command, service.ServiceType, string.Format(CultureInfo.InvariantCulture, "{0:hh}:{0:mm}:{0:ss}", value), "REL_TIME"))
+ await new SsdpHttpClient(_httpClientFactory).SendCommandAsync(Properties.BaseUrl, service, command.Name, avCommands.BuildPost(command, service.ServiceType, string.Format(CultureInfo.InvariantCulture, "{0:hh}:{0:mm}:{0:ss}", value), "REL_TIME"))
.ConfigureAwait(false);
RestartTimer(true);
@@ -326,7 +327,7 @@ namespace Emby.Dlna.PlayTo
}
var post = avCommands.BuildPost(command, service.ServiceType, url, dictionary);
- await new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, post, header: header)
+ await new SsdpHttpClient(_httpClientFactory).SendCommandAsync(Properties.BaseUrl, service, command.Name, post, header: header)
.ConfigureAwait(false);
await Task.Delay(50).ConfigureAwait(false);
@@ -368,7 +369,7 @@ namespace Emby.Dlna.PlayTo
throw new InvalidOperationException("Unable to find service");
}
- return new SsdpHttpClient(_httpClient).SendCommandAsync(
+ return new SsdpHttpClient(_httpClientFactory).SendCommandAsync(
Properties.BaseUrl,
service,
command.Name,
@@ -397,7 +398,7 @@ namespace Emby.Dlna.PlayTo
var service = GetAvTransportService();
- await new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, avCommands.BuildPost(command, service.ServiceType, 1))
+ await new SsdpHttpClient(_httpClientFactory).SendCommandAsync(Properties.BaseUrl, service, command.Name, avCommands.BuildPost(command, service.ServiceType, 1))
.ConfigureAwait(false);
RestartTimer(true);
@@ -415,7 +416,7 @@ namespace Emby.Dlna.PlayTo
var service = GetAvTransportService();
- await new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, avCommands.BuildPost(command, service.ServiceType, 1))
+ await new SsdpHttpClient(_httpClientFactory).SendCommandAsync(Properties.BaseUrl, service, command.Name, avCommands.BuildPost(command, service.ServiceType, 1))
.ConfigureAwait(false);
TransportState = TransportState.Paused;
@@ -542,7 +543,7 @@ namespace Emby.Dlna.PlayTo
return;
}
- var result = await new SsdpHttpClient(_httpClient).SendCommandAsync(
+ var result = await new SsdpHttpClient(_httpClientFactory).SendCommandAsync(
Properties.BaseUrl,
service,
command.Name,
@@ -592,7 +593,7 @@ namespace Emby.Dlna.PlayTo
return;
}
- var result = await new SsdpHttpClient(_httpClient).SendCommandAsync(
+ var result = await new SsdpHttpClient(_httpClientFactory).SendCommandAsync(
Properties.BaseUrl,
service,
command.Name,
@@ -625,7 +626,7 @@ namespace Emby.Dlna.PlayTo
return null;
}
- var result = await new SsdpHttpClient(_httpClient).SendCommandAsync(
+ var result = await new SsdpHttpClient(_httpClientFactory).SendCommandAsync(
Properties.BaseUrl,
service,
command.Name,
@@ -667,7 +668,7 @@ namespace Emby.Dlna.PlayTo
var rendererCommands = await GetRenderingProtocolAsync(cancellationToken).ConfigureAwait(false);
- var result = await new SsdpHttpClient(_httpClient).SendCommandAsync(
+ var result = await new SsdpHttpClient(_httpClientFactory).SendCommandAsync(
Properties.BaseUrl,
service,
command.Name,
@@ -734,7 +735,7 @@ namespace Emby.Dlna.PlayTo
var rendererCommands = await GetRenderingProtocolAsync(cancellationToken).ConfigureAwait(false);
- var result = await new SsdpHttpClient(_httpClient).SendCommandAsync(
+ var result = await new SsdpHttpClient(_httpClientFactory).SendCommandAsync(
Properties.BaseUrl,
service,
command.Name,
@@ -912,7 +913,7 @@ namespace Emby.Dlna.PlayTo
string url = NormalizeUrl(Properties.BaseUrl, avService.ScpdUrl);
- var httpClient = new SsdpHttpClient(_httpClient);
+ var httpClient = new SsdpHttpClient(_httpClientFactory);
var document = await httpClient.GetDataAsync(url, cancellationToken).ConfigureAwait(false);
@@ -940,7 +941,7 @@ namespace Emby.Dlna.PlayTo
string url = NormalizeUrl(Properties.BaseUrl, avService.ScpdUrl);
- var httpClient = new SsdpHttpClient(_httpClient);
+ var httpClient = new SsdpHttpClient(_httpClientFactory);
_logger.LogDebug("Dlna Device.GetRenderingProtocolAsync");
var document = await httpClient.GetDataAsync(url, cancellationToken).ConfigureAwait(false);
@@ -969,9 +970,9 @@ namespace Emby.Dlna.PlayTo
return baseUrl + url;
}
- public static async Task<Device> CreateuPnpDeviceAsync(Uri url, IHttpClient httpClient, ILogger logger, CancellationToken cancellationToken)
+ public static async Task<Device> CreateuPnpDeviceAsync(Uri url, IHttpClientFactory httpClientFactory, ILogger logger, CancellationToken cancellationToken)
{
- var ssdpHttpClient = new SsdpHttpClient(httpClient);
+ var ssdpHttpClient = new SsdpHttpClient(httpClientFactory);
var document = await ssdpHttpClient.GetDataAsync(url.ToString(), cancellationToken).ConfigureAwait(false);
@@ -1079,7 +1080,7 @@ namespace Emby.Dlna.PlayTo
}
}
- return new Device(deviceProperties, httpClient, logger);
+ return new Device(deviceProperties, httpClientFactory, logger);
}
private static DeviceIcon CreateIcon(XElement element)
diff --git a/Emby.Dlna/PlayTo/PlayToManager.cs b/Emby.Dlna/PlayTo/PlayToManager.cs
index ff801f263..3d1dd3e73 100644
--- a/Emby.Dlna/PlayTo/PlayToManager.cs
+++ b/Emby.Dlna/PlayTo/PlayToManager.cs
@@ -4,6 +4,7 @@ using System;
using System.Globalization;
using System.Linq;
using System.Net;
+using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using Jellyfin.Data.Events;
@@ -33,7 +34,7 @@ namespace Emby.Dlna.PlayTo
private readonly IDlnaManager _dlnaManager;
private readonly IServerApplicationHost _appHost;
private readonly IImageProcessor _imageProcessor;
- private readonly IHttpClient _httpClient;
+ private readonly IHttpClientFactory _httpClientFactory;
private readonly IServerConfigurationManager _config;
private readonly IUserDataManager _userDataManager;
private readonly ILocalizationManager _localization;
@@ -46,7 +47,7 @@ namespace Emby.Dlna.PlayTo
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)
+ public PlayToManager(ILogger logger, ISessionManager sessionManager, ILibraryManager libraryManager, IUserManager userManager, IDlnaManager dlnaManager, IServerApplicationHost appHost, IImageProcessor imageProcessor, IDeviceDiscovery deviceDiscovery, IHttpClientFactory httpClientFactory, IServerConfigurationManager config, IUserDataManager userDataManager, ILocalizationManager localization, IMediaSourceManager mediaSourceManager, IMediaEncoder mediaEncoder)
{
_logger = logger;
_sessionManager = sessionManager;
@@ -56,7 +57,7 @@ namespace Emby.Dlna.PlayTo
_appHost = appHost;
_imageProcessor = imageProcessor;
_deviceDiscovery = deviceDiscovery;
- _httpClient = httpClient;
+ _httpClientFactory = httpClientFactory;
_config = config;
_userDataManager = userDataManager;
_localization = localization;
@@ -174,7 +175,7 @@ namespace Emby.Dlna.PlayTo
if (controller == null)
{
- var device = await Device.CreateuPnpDeviceAsync(uri, _httpClient, _logger, cancellationToken).ConfigureAwait(false);
+ var device = await Device.CreateuPnpDeviceAsync(uri, _httpClientFactory, _logger, cancellationToken).ConfigureAwait(false);
string deviceName = device.Properties.Name;
diff --git a/Emby.Dlna/PlayTo/SsdpHttpClient.cs b/Emby.Dlna/PlayTo/SsdpHttpClient.cs
index ab262bebf..8683c8997 100644
--- a/Emby.Dlna/PlayTo/SsdpHttpClient.cs
+++ b/Emby.Dlna/PlayTo/SsdpHttpClient.cs
@@ -4,6 +4,8 @@ using System;
using System.Globalization;
using System.IO;
using System.Net.Http;
+using System.Net.Http.Headers;
+using System.Net.Mime;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
@@ -20,11 +22,11 @@ namespace Emby.Dlna.PlayTo
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
- private readonly IHttpClient _httpClient;
+ private readonly IHttpClientFactory _httpClientFactory;
- public SsdpHttpClient(IHttpClient httpClient)
+ public SsdpHttpClient(IHttpClientFactory httpClientFactory)
{
- _httpClient = httpClient;
+ _httpClientFactory = httpClientFactory;
}
public async Task<XDocument> SendCommandAsync(
@@ -36,20 +38,18 @@ namespace Emby.Dlna.PlayTo
CancellationToken cancellationToken = default)
{
var url = NormalizeServiceUrl(baseUrl, service.ControlUrl);
- using (var response = await PostSoapDataAsync(
- url,
- $"\"{service.ServiceType}#{command}\"",
- postData,
- header,
- cancellationToken)
- .ConfigureAwait(false))
- using (var stream = response.Content)
- using (var reader = new StreamReader(stream, Encoding.UTF8))
- {
- return XDocument.Parse(
- await reader.ReadToEndAsync().ConfigureAwait(false),
- LoadOptions.PreserveWhitespace);
- }
+ using var response = await PostSoapDataAsync(
+ url,
+ $"\"{service.ServiceType}#{command}\"",
+ postData,
+ header,
+ cancellationToken)
+ .ConfigureAwait(false);
+ await using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false);
+ using var reader = new StreamReader(stream, Encoding.UTF8);
+ return XDocument.Parse(
+ await reader.ReadToEndAsync().ConfigureAwait(false),
+ LoadOptions.PreserveWhitespace);
}
private static string NormalizeServiceUrl(string baseUrl, string serviceUrl)
@@ -76,49 +76,32 @@ namespace Emby.Dlna.PlayTo
int eventport,
int timeOut = 3600)
{
- var options = new HttpRequestOptions
- {
- Url = url,
- UserAgent = USERAGENT,
- LogErrorResponseBody = true,
- BufferContent = false,
- };
-
- options.RequestHeaders["HOST"] = ip + ":" + port.ToString(_usCulture);
- options.RequestHeaders["CALLBACK"] = "<" + localIp + ":" + eventport.ToString(_usCulture) + ">";
- options.RequestHeaders["NT"] = "upnp:event";
- options.RequestHeaders["TIMEOUT"] = "Second-" + timeOut.ToString(_usCulture);
-
- using (await _httpClient.SendAsync(options, new HttpMethod("SUBSCRIBE")).ConfigureAwait(false))
- {
- }
+ using var options = new HttpRequestMessage(new HttpMethod("SUBSCRIBE"), url);
+ options.Headers.UserAgent.ParseAdd(USERAGENT);
+ options.Headers.TryAddWithoutValidation("HOST", ip + ":" + port.ToString(_usCulture));
+ options.Headers.TryAddWithoutValidation("CALLBACK", "<" + localIp + ":" + eventport.ToString(_usCulture) + ">");
+ options.Headers.TryAddWithoutValidation("NT", "upnp:event");
+ options.Headers.TryAddWithoutValidation("TIMEOUT", "Second-" + timeOut.ToString(_usCulture));
+
+ using var response = await _httpClientFactory.CreateClient(NamedClient.Default)
+ .SendAsync(options, HttpCompletionOption.ResponseHeadersRead)
+ .ConfigureAwait(false);
}
public async Task<XDocument> GetDataAsync(string url, CancellationToken cancellationToken)
{
- var options = new HttpRequestOptions
- {
- Url = url,
- UserAgent = USERAGENT,
- LogErrorResponseBody = true,
- BufferContent = false,
-
- CancellationToken = cancellationToken
- };
-
- options.RequestHeaders["FriendlyName.DLNA.ORG"] = FriendlyName;
-
- using (var response = await _httpClient.SendAsync(options, HttpMethod.Get).ConfigureAwait(false))
- using (var stream = response.Content)
- using (var reader = new StreamReader(stream, Encoding.UTF8))
- {
- return XDocument.Parse(
- await reader.ReadToEndAsync().ConfigureAwait(false),
- LoadOptions.PreserveWhitespace);
- }
+ using var options = new HttpRequestMessage(HttpMethod.Get, url);
+ options.Headers.UserAgent.ParseAdd(USERAGENT);
+ options.Headers.TryAddWithoutValidation("FriendlyName.DLNA.ORG", FriendlyName);
+ using var response = await _httpClientFactory.CreateClient(NamedClient.Default).SendAsync(options, HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false);
+ await using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false);
+ using var reader = new StreamReader(stream, Encoding.UTF8);
+ return XDocument.Parse(
+ await reader.ReadToEndAsync().ConfigureAwait(false),
+ LoadOptions.PreserveWhitespace);
}
- private Task<HttpResponseInfo> PostSoapDataAsync(
+ private Task<HttpResponseMessage> PostSoapDataAsync(
string url,
string soapAction,
string postData,
@@ -130,29 +113,20 @@ namespace Emby.Dlna.PlayTo
soapAction = $"\"{soapAction}\"";
}
- var options = new HttpRequestOptions
- {
- Url = url,
- UserAgent = USERAGENT,
- LogErrorResponseBody = true,
- BufferContent = false,
-
- CancellationToken = cancellationToken
- };
-
- options.RequestHeaders["SOAPAction"] = soapAction;
- options.RequestHeaders["Pragma"] = "no-cache";
- options.RequestHeaders["FriendlyName.DLNA.ORG"] = FriendlyName;
+ using var options = new HttpRequestMessage(HttpMethod.Post, url);
+ options.Headers.UserAgent.ParseAdd(USERAGENT);
+ options.Headers.TryAddWithoutValidation("SOAPACTION", soapAction);
+ options.Headers.TryAddWithoutValidation("Pragma", "no-cache");
+ options.Headers.TryAddWithoutValidation("FriendlyName.DLNA.ORG", FriendlyName);
if (!string.IsNullOrEmpty(header))
{
- options.RequestHeaders["contentFeatures.dlna.org"] = header;
+ options.Headers.TryAddWithoutValidation("contentFeatures.dlna.org", header);
}
- options.RequestContentType = "text/xml";
- options.RequestContent = postData;
+ options.Content = new StringContent(postData, Encoding.UTF8, MediaTypeNames.Text.Xml);
- return _httpClient.Post(options);
+ return _httpClientFactory.CreateClient(NamedClient.Default).SendAsync(options, HttpCompletionOption.ResponseHeadersRead, cancellationToken);
}
}
}
diff --git a/Emby.Dlna/Service/BaseService.cs b/Emby.Dlna/Service/BaseService.cs
index 40d069e7c..a97c4d63a 100644
--- a/Emby.Dlna/Service/BaseService.cs
+++ b/Emby.Dlna/Service/BaseService.cs
@@ -1,25 +1,21 @@
#pragma warning disable CS1591
+using System.Net.Http;
using Emby.Dlna.Eventing;
-using MediaBrowser.Common.Net;
using Microsoft.Extensions.Logging;
namespace Emby.Dlna.Service
{
public class BaseService : IDlnaEventManager
{
- protected BaseService(ILogger<BaseService> logger, IHttpClient httpClient)
+ protected BaseService(ILogger<BaseService> logger, IHttpClientFactory httpClientFactory)
{
Logger = logger;
- HttpClient = httpClient;
-
- EventManager = new DlnaEventManager(logger, HttpClient);
+ EventManager = new DlnaEventManager(logger, httpClientFactory);
}
protected IDlnaEventManager EventManager { get; }
- protected IHttpClient HttpClient { get; }
-
protected ILogger Logger { get; }
public EventSubscriptionResponse CancelEventSubscription(string subscriptionId)
diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs
index 155bdcf65..c37e87d96 100644
--- a/Emby.Server.Implementations/ApplicationHost.cs
+++ b/Emby.Server.Implementations/ApplicationHost.cs
@@ -49,6 +49,7 @@ using Jellyfin.Api.Helpers;
using MediaBrowser.Common;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Events;
+using MediaBrowser.Common.Json;
using MediaBrowser.Common.Net;
using MediaBrowser.Common.Plugins;
using MediaBrowser.Common.Updates;
@@ -122,8 +123,8 @@ namespace Emby.Server.Implementations
private IMediaEncoder _mediaEncoder;
private ISessionManager _sessionManager;
+ private IHttpClientFactory _httpClientFactory;
private IWebSocketManager _webSocketManager;
- private IHttpClient _httpClient;
private string[] _urlPrefixes;
@@ -526,8 +527,6 @@ namespace Emby.Server.Implementations
ServiceCollection.AddSingleton(_fileSystemManager);
ServiceCollection.AddSingleton<TvdbClientManager>();
- ServiceCollection.AddSingleton<IHttpClient, HttpClientManager.HttpClientManager>();
-
ServiceCollection.AddSingleton(_networkManager);
ServiceCollection.AddSingleton<IIsoManager, IsoManager>();
@@ -654,8 +653,8 @@ namespace Emby.Server.Implementations
_mediaEncoder = Resolve<IMediaEncoder>();
_sessionManager = Resolve<ISessionManager>();
+ _httpClientFactory = Resolve<IHttpClientFactory>();
_webSocketManager = Resolve<IWebSocketManager>();
- _httpClient = Resolve<IHttpClient>();
((AuthenticationRepository)Resolve<IAuthenticationRepository>()).Initialize();
@@ -1300,25 +1299,17 @@ namespace Emby.Server.Implementations
try
{
- using (var response = await _httpClient.SendAsync(
- new HttpRequestOptions
- {
- Url = apiUrl,
- LogErrorResponseBody = false,
- BufferContent = false,
- CancellationToken = cancellationToken
- }, HttpMethod.Post).ConfigureAwait(false))
- {
- using (var reader = new StreamReader(response.Content))
- {
- var result = await reader.ReadToEndAsync().ConfigureAwait(false);
- var valid = string.Equals(Name, result, StringComparison.OrdinalIgnoreCase);
+ using var request = new HttpRequestMessage(HttpMethod.Post, apiUrl);
+ using var response = await _httpClientFactory.CreateClient(NamedClient.Default)
+ .SendAsync(request, HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false);
- _validAddressResults.AddOrUpdate(apiUrl, valid, (k, v) => valid);
- Logger.LogDebug("Ping test result to {0}. Success: {1}", apiUrl, valid);
- return valid;
- }
- }
+ await using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false);
+ var result = await System.Text.Json.JsonSerializer.DeserializeAsync<string>(stream, JsonDefaults.GetOptions(), cancellationToken).ConfigureAwait(false);
+ var valid = string.Equals(Name, result, StringComparison.OrdinalIgnoreCase);
+
+ _validAddressResults.AddOrUpdate(apiUrl, valid, (k, v) => valid);
+ Logger.LogDebug("Ping test result to {0}. Success: {1}", apiUrl, valid);
+ return valid;
}
catch (OperationCanceledException)
{
diff --git a/Emby.Server.Implementations/HttpClientManager/HttpClientManager.cs b/Emby.Server.Implementations/HttpClientManager/HttpClientManager.cs
deleted file mode 100644
index 25adc5812..000000000
--- a/Emby.Server.Implementations/HttpClientManager/HttpClientManager.cs
+++ /dev/null
@@ -1,335 +0,0 @@
-using System;
-using System.Collections.Concurrent;
-using System.Globalization;
-using System.IO;
-using System.Linq;
-using System.Net;
-using System.Net.Http;
-using System.Threading.Tasks;
-using MediaBrowser.Common;
-using MediaBrowser.Common.Configuration;
-using MediaBrowser.Common.Extensions;
-using MediaBrowser.Common.Net;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Model.Net;
-using Microsoft.Extensions.Logging;
-using Microsoft.Net.Http.Headers;
-
-namespace Emby.Server.Implementations.HttpClientManager
-{
- /// <summary>
- /// Class HttpClientManager.
- /// </summary>
- public class HttpClientManager : IHttpClient
- {
- private readonly ILogger<HttpClientManager> _logger;
- private readonly IApplicationPaths _appPaths;
- private readonly IFileSystem _fileSystem;
- private readonly IApplicationHost _appHost;
-
- /// <summary>
- /// Holds a dictionary of http clients by host. Use GetHttpClient(host) to retrieve or create a client for web requests.
- /// DON'T dispose it after use.
- /// </summary>
- /// <value>The HTTP clients.</value>
- private readonly ConcurrentDictionary<string, HttpClient> _httpClients = new ConcurrentDictionary<string, HttpClient>();
-
- /// <summary>
- /// Initializes a new instance of the <see cref="HttpClientManager" /> class.
- /// </summary>
- public HttpClientManager(
- IApplicationPaths appPaths,
- ILogger<HttpClientManager> logger,
- IFileSystem fileSystem,
- IApplicationHost appHost)
- {
- _logger = logger ?? throw new ArgumentNullException(nameof(logger));
- _fileSystem = fileSystem;
- _appPaths = appPaths ?? throw new ArgumentNullException(nameof(appPaths));
- _appHost = appHost;
- }
-
- /// <summary>
- /// Gets the correct http client for the given url.
- /// </summary>
- /// <param name="url">The url.</param>
- /// <returns>HttpClient.</returns>
- private HttpClient GetHttpClient(string url)
- {
- var key = GetHostFromUrl(url);
-
- if (!_httpClients.TryGetValue(key, out var client))
- {
- client = new HttpClient()
- {
- BaseAddress = new Uri(url)
- };
-
- _httpClients.TryAdd(key, client);
- }
-
- return client;
- }
-
- private HttpRequestMessage GetRequestMessage(HttpRequestOptions options, HttpMethod method)
- {
- string url = options.Url;
- var uriAddress = new Uri(url);
- string userInfo = uriAddress.UserInfo;
- if (!string.IsNullOrWhiteSpace(userInfo))
- {
- _logger.LogWarning("Found userInfo in url: {0} ... url: {1}", userInfo, url);
- url = url.Replace(userInfo + '@', string.Empty, StringComparison.Ordinal);
- }
-
- var request = new HttpRequestMessage(method, url);
-
- foreach (var header in options.RequestHeaders)
- {
- request.Headers.TryAddWithoutValidation(header.Key, header.Value);
- }
-
- if (options.EnableDefaultUserAgent
- && !request.Headers.TryGetValues(HeaderNames.UserAgent, out _))
- {
- request.Headers.Add(HeaderNames.UserAgent, _appHost.ApplicationUserAgent);
- }
-
- switch (options.DecompressionMethod)
- {
- case CompressionMethods.Deflate | CompressionMethods.Gzip:
- request.Headers.Add(HeaderNames.AcceptEncoding, new[] { "gzip", "deflate" });
- break;
- case CompressionMethods.Deflate:
- request.Headers.Add(HeaderNames.AcceptEncoding, "deflate");
- break;
- case CompressionMethods.Gzip:
- request.Headers.Add(HeaderNames.AcceptEncoding, "gzip");
- break;
- default:
- break;
- }
-
- if (options.EnableKeepAlive)
- {
- request.Headers.Add(HeaderNames.Connection, "Keep-Alive");
- }
-
- // request.Headers.Add(HeaderNames.CacheControl, "no-cache");
-
- /*
- if (!string.IsNullOrWhiteSpace(userInfo))
- {
- var parts = userInfo.Split(':');
- if (parts.Length == 2)
- {
- request.Headers.Add(HeaderNames., GetCredential(url, parts[0], parts[1]);
- }
- }
- */
-
- return request;
- }
-
- /// <summary>
- /// Gets the response internal.
- /// </summary>
- /// <param name="options">The options.</param>
- /// <returns>Task{HttpResponseInfo}.</returns>
- public Task<HttpResponseInfo> GetResponse(HttpRequestOptions options)
- => SendAsync(options, HttpMethod.Get);
-
- /// <summary>
- /// Performs a GET request and returns the resulting stream.
- /// </summary>
- /// <param name="options">The options.</param>
- /// <returns>Task{Stream}.</returns>
- public async Task<Stream> Get(HttpRequestOptions options)
- {
- var response = await GetResponse(options).ConfigureAwait(false);
- return response.Content;
- }
-
- /// <summary>
- /// send as an asynchronous operation.
- /// </summary>
- /// <param name="options">The options.</param>
- /// <param name="httpMethod">The HTTP method.</param>
- /// <returns>Task{HttpResponseInfo}.</returns>
- public Task<HttpResponseInfo> SendAsync(HttpRequestOptions options, string httpMethod)
- => SendAsync(options, new HttpMethod(httpMethod));
-
- /// <summary>
- /// send as an asynchronous operation.
- /// </summary>
- /// <param name="options">The options.</param>
- /// <param name="httpMethod">The HTTP method.</param>
- /// <returns>Task{HttpResponseInfo}.</returns>
- public async Task<HttpResponseInfo> SendAsync(HttpRequestOptions options, HttpMethod httpMethod)
- {
- if (options.CacheMode == CacheMode.None)
- {
- return await SendAsyncInternal(options, httpMethod).ConfigureAwait(false);
- }
-
- var url = options.Url;
- var urlHash = url.ToUpperInvariant().GetMD5().ToString("N", CultureInfo.InvariantCulture);
-
- var responseCachePath = Path.Combine(_appPaths.CachePath, "httpclient", urlHash);
-
- var response = GetCachedResponse(responseCachePath, options.CacheLength, url);
- if (response != null)
- {
- return response;
- }
-
- response = await SendAsyncInternal(options, httpMethod).ConfigureAwait(false);
-
- if (response.StatusCode == HttpStatusCode.OK)
- {
- await CacheResponse(response, responseCachePath).ConfigureAwait(false);
- }
-
- return response;
- }
-
- private HttpResponseInfo GetCachedResponse(string responseCachePath, TimeSpan cacheLength, string url)
- {
- if (File.Exists(responseCachePath)
- && _fileSystem.GetLastWriteTimeUtc(responseCachePath).Add(cacheLength) > DateTime.UtcNow)
- {
- var stream = new FileStream(responseCachePath, FileMode.Open, FileAccess.Read, FileShare.Read, IODefaults.FileStreamBufferSize, true);
-
- return new HttpResponseInfo
- {
- ResponseUrl = url,
- Content = stream,
- StatusCode = HttpStatusCode.OK,
- ContentLength = stream.Length
- };
- }
-
- return null;
- }
-
- private async Task CacheResponse(HttpResponseInfo response, string responseCachePath)
- {
- Directory.CreateDirectory(Path.GetDirectoryName(responseCachePath));
-
- using (var fileStream = new FileStream(
- responseCachePath,
- FileMode.Create,
- FileAccess.Write,
- FileShare.None,
- IODefaults.FileStreamBufferSize,
- true))
- {
- await response.Content.CopyToAsync(fileStream).ConfigureAwait(false);
-
- response.Content.Position = 0;
- }
- }
-
- private async Task<HttpResponseInfo> SendAsyncInternal(HttpRequestOptions options, HttpMethod httpMethod)
- {
- ValidateParams(options);
-
- options.CancellationToken.ThrowIfCancellationRequested();
-
- var client = GetHttpClient(options.Url);
-
- var httpWebRequest = GetRequestMessage(options, httpMethod);
-
- if (!string.IsNullOrEmpty(options.RequestContent)
- || httpMethod == HttpMethod.Post)
- {
- if (options.RequestContent != null)
- {
- httpWebRequest.Content = new StringContent(
- options.RequestContent,
- null,
- options.RequestContentType);
- }
- else
- {
- httpWebRequest.Content = new ByteArrayContent(Array.Empty<byte>());
- }
- }
-
- options.CancellationToken.ThrowIfCancellationRequested();
-
- var response = await client.SendAsync(
- httpWebRequest,
- options.BufferContent || options.CacheMode == CacheMode.Unconditional ? HttpCompletionOption.ResponseContentRead : HttpCompletionOption.ResponseHeadersRead,
- options.CancellationToken).ConfigureAwait(false);
-
- await EnsureSuccessStatusCode(response, options).ConfigureAwait(false);
-
- options.CancellationToken.ThrowIfCancellationRequested();
-
- var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false);
- return new HttpResponseInfo(response.Headers, response.Content.Headers)
- {
- Content = stream,
- StatusCode = response.StatusCode,
- ContentType = response.Content.Headers.ContentType?.MediaType,
- ContentLength = response.Content.Headers.ContentLength,
- ResponseUrl = response.Content.Headers.ContentLocation?.ToString()
- };
- }
-
- /// <inheritdoc />
- public Task<HttpResponseInfo> Post(HttpRequestOptions options)
- => SendAsync(options, HttpMethod.Post);
-
- private void ValidateParams(HttpRequestOptions options)
- {
- if (string.IsNullOrEmpty(options.Url))
- {
- throw new ArgumentNullException(nameof(options));
- }
- }
-
- /// <summary>
- /// Gets the host from URL.
- /// </summary>
- /// <param name="url">The URL.</param>
- /// <returns>System.String.</returns>
- private static string GetHostFromUrl(string url)
- {
- var index = url.IndexOf("://", StringComparison.OrdinalIgnoreCase);
-
- if (index != -1)
- {
- url = url.Substring(index + 3);
- var host = url.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries).FirstOrDefault();
-
- if (!string.IsNullOrWhiteSpace(host))
- {
- return host;
- }
- }
-
- return url;
- }
-
- private async Task EnsureSuccessStatusCode(HttpResponseMessage response, HttpRequestOptions options)
- {
- if (response.IsSuccessStatusCode)
- {
- return;
- }
-
- if (options.LogErrorResponseBody)
- {
- string msg = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
- _logger.LogError("HTTP request failed with message: {Message}", msg);
- }
-
- throw new HttpException(response.ReasonPhrase)
- {
- StatusCode = response.StatusCode
- };
- }
- }
-}
diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs
index 0edd98031..44560d1e2 100644
--- a/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs
+++ b/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs
@@ -16,13 +16,13 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
public class DirectRecorder : IRecorder
{
private readonly ILogger _logger;
- private readonly IHttpClient _httpClient;
+ private readonly IHttpClientFactory _httpClientFactory;
private readonly IStreamHelper _streamHelper;
- public DirectRecorder(ILogger logger, IHttpClient httpClient, IStreamHelper streamHelper)
+ public DirectRecorder(ILogger logger, IHttpClientFactory httpClientFactory, IStreamHelper streamHelper)
{
_logger = logger;
- _httpClient = httpClient;
+ _httpClientFactory = httpClientFactory;
_streamHelper = streamHelper;
}
@@ -63,42 +63,28 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
private async Task RecordFromMediaSource(MediaSourceInfo mediaSource, string targetFile, TimeSpan duration, Action onStarted, CancellationToken cancellationToken)
{
- var httpRequestOptions = new HttpRequestOptions
- {
- Url = mediaSource.Path,
- BufferContent = false,
-
- // Some remote urls will expect a user agent to be supplied
- UserAgent = "Emby/3.0",
+ using var response = await _httpClientFactory.CreateClient(NamedClient.Default)
+ .GetAsync(mediaSource.Path, HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false);
- // Shouldn't matter but may cause issues
- DecompressionMethod = CompressionMethods.None,
- CancellationToken = cancellationToken
- };
+ _logger.LogInformation("Opened recording stream from tuner provider");
- using (var response = await _httpClient.SendAsync(httpRequestOptions, HttpMethod.Get).ConfigureAwait(false))
- {
- _logger.LogInformation("Opened recording stream from tuner provider");
+ Directory.CreateDirectory(Path.GetDirectoryName(targetFile));
- Directory.CreateDirectory(Path.GetDirectoryName(targetFile));
+ await using var output = new FileStream(targetFile, FileMode.Create, FileAccess.Write, FileShare.Read);
- using (var output = new FileStream(targetFile, FileMode.Create, FileAccess.Write, FileShare.Read))
- {
- onStarted();
+ onStarted();
- _logger.LogInformation("Copying recording stream to file {0}", targetFile);
+ _logger.LogInformation("Copying recording stream to file {0}", targetFile);
- // The media source if infinite so we need to handle stopping ourselves
- using var durationToken = new CancellationTokenSource(duration);
- using var cancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, durationToken.Token);
+ // The media source if infinite so we need to handle stopping ourselves
+ var durationToken = new CancellationTokenSource(duration);
+ cancellationToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, durationToken.Token).Token;
- await _streamHelper.CopyUntilCancelled(
- response.Content,
- output,
- IODefaults.CopyToBufferSize,
- cancellationTokenSource.Token).ConfigureAwait(false);
- }
- }
+ await _streamHelper.CopyUntilCancelled(
+ await response.Content.ReadAsStreamAsync().ConfigureAwait(false),
+ output,
+ IODefaults.CopyToBufferSize,
+ cancellationToken).ConfigureAwait(false);
_logger.LogInformation("Recording completed to file {0}", targetFile);
}
diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
index 5cf09b8e5..ca60c3366 100644
--- a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
+++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
@@ -7,6 +7,7 @@ using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
+using System.Net.Http;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
@@ -48,7 +49,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
private readonly IServerApplicationHost _appHost;
private readonly ILogger<EmbyTV> _logger;
- private readonly IHttpClient _httpClient;
+ private readonly IHttpClientFactory _httpClientFactory;
private readonly IServerConfigurationManager _config;
private readonly IJsonSerializer _jsonSerializer;
@@ -81,7 +82,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
IMediaSourceManager mediaSourceManager,
ILogger<EmbyTV> logger,
IJsonSerializer jsonSerializer,
- IHttpClient httpClient,
+ IHttpClientFactory httpClientFactory,
IServerConfigurationManager config,
ILiveTvManager liveTvManager,
IFileSystem fileSystem,
@@ -94,7 +95,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
_appHost = appHost;
_logger = logger;
- _httpClient = httpClient;
+ _httpClientFactory = httpClientFactory;
_config = config;
_fileSystem = fileSystem;
_libraryManager = libraryManager;
@@ -1637,7 +1638,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
return new EncodedRecorder(_logger, _mediaEncoder, _config.ApplicationPaths, _jsonSerializer);
}
- return new DirectRecorder(_logger, _httpClient, _streamHelper);
+ return new DirectRecorder(_logger, _httpClientFactory, _streamHelper);
}
private void OnSuccessfulRecording(TimerInfo timer, string path)
diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs
index 33331adaf..f9ae55af8 100644
--- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs
+++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs
@@ -8,6 +8,8 @@ using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
+using System.Net.Mime;
+using System.Text;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Common;
@@ -28,19 +30,19 @@ namespace Emby.Server.Implementations.LiveTv.Listings
private readonly ILogger<SchedulesDirect> _logger;
private readonly IJsonSerializer _jsonSerializer;
- private readonly IHttpClient _httpClient;
+ private readonly IHttpClientFactory _httpClientFactory;
private readonly SemaphoreSlim _tokenSemaphore = new SemaphoreSlim(1, 1);
private readonly IApplicationHost _appHost;
public SchedulesDirect(
ILogger<SchedulesDirect> logger,
IJsonSerializer jsonSerializer,
- IHttpClient httpClient,
+ IHttpClientFactory httpClientFactory,
IApplicationHost appHost)
{
_logger = logger;
_jsonSerializer = jsonSerializer;
- _httpClient = httpClient;
+ _httpClientFactory = httpClientFactory;
_appHost = appHost;
}
@@ -102,95 +104,78 @@ namespace Emby.Server.Implementations.LiveTv.Listings
var requestString = _jsonSerializer.SerializeToString(requestList);
_logger.LogDebug("Request string for schedules is: {RequestString}", requestString);
- var httpOptions = new HttpRequestOptions()
- {
- Url = ApiUrl + "/schedules",
- UserAgent = UserAgent,
- CancellationToken = cancellationToken,
- LogErrorResponseBody = true,
- RequestContent = requestString
- };
+ using var options = new HttpRequestMessage(HttpMethod.Post, ApiUrl + "/schedules");
+ options.Content = new StringContent(requestString, Encoding.UTF8, MediaTypeNames.Application.Json);
+ options.Headers.TryAddWithoutValidation("token", token);
+ using var response = await Send(options, true, info, cancellationToken).ConfigureAwait(false);
+ await using var responseStream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false);
+ var dailySchedules = await _jsonSerializer.DeserializeFromStreamAsync<List<ScheduleDirect.Day>>(responseStream).ConfigureAwait(false);
+ _logger.LogDebug("Found {ScheduleCount} programs on {ChannelID} ScheduleDirect", dailySchedules.Count, channelId);
- httpOptions.RequestHeaders["token"] = token;
+ using var programRequestOptions = new HttpRequestMessage(HttpMethod.Post, ApiUrl + "/programs");
+ programRequestOptions.Headers.TryAddWithoutValidation("token", token);
- using (var response = await Post(httpOptions, true, info).ConfigureAwait(false))
- {
- var dailySchedules = await _jsonSerializer.DeserializeFromStreamAsync<List<ScheduleDirect.Day>>(response.Content).ConfigureAwait(false);
- _logger.LogDebug("Found {ScheduleCount} programs on {ChannelID} ScheduleDirect", dailySchedules.Count, channelId);
+ var programsID = dailySchedules.SelectMany(d => d.programs.Select(s => s.programID)).Distinct();
+ programRequestOptions.Content = new StringContent("[\"" + string.Join("\", \"", programsID) + "\"]", Encoding.UTF8, MediaTypeNames.Application.Json);
- httpOptions = new HttpRequestOptions()
- {
- Url = ApiUrl + "/programs",
- UserAgent = UserAgent,
- CancellationToken = cancellationToken,
- LogErrorResponseBody = true
- };
-
- httpOptions.RequestHeaders["token"] = token;
+ using var innerResponse = await Send(programRequestOptions, true, info, cancellationToken).ConfigureAwait(false);
+ await using var innerResponseStream = await innerResponse.Content.ReadAsStreamAsync().ConfigureAwait(false);
+ var programDetails = await _jsonSerializer.DeserializeFromStreamAsync<List<ScheduleDirect.ProgramDetails>>(innerResponseStream).ConfigureAwait(false);
+ var programDict = programDetails.ToDictionary(p => p.programID, y => y);
- var programsID = dailySchedules.SelectMany(d => d.programs.Select(s => s.programID)).Distinct();
- httpOptions.RequestContent = "[\"" + string.Join("\", \"", programsID) + "\"]";
+ var programIdsWithImages =
+ programDetails.Where(p => p.hasImageArtwork).Select(p => p.programID)
+ .ToList();
- using (var innerResponse = await Post(httpOptions, true, info).ConfigureAwait(false))
- {
- var programDetails = await _jsonSerializer.DeserializeFromStreamAsync<List<ScheduleDirect.ProgramDetails>>(innerResponse.Content).ConfigureAwait(false);
- var programDict = programDetails.ToDictionary(p => p.programID, y => y);
+ var images = await GetImageForPrograms(info, programIdsWithImages, cancellationToken).ConfigureAwait(false);
- var programIdsWithImages =
- programDetails.Where(p => p.hasImageArtwork).Select(p => p.programID)
- .ToList();
-
- var images = await GetImageForPrograms(info, programIdsWithImages, cancellationToken).ConfigureAwait(false);
+ var programsInfo = new List<ProgramInfo>();
+ foreach (ScheduleDirect.Program schedule in dailySchedules.SelectMany(d => d.programs))
+ {
+ // _logger.LogDebug("Proccesing Schedule for statio ID " + stationID +
+ // " which corresponds to channel " + channelNumber + " and program id " +
+ // schedule.programID + " which says it has images? " +
+ // programDict[schedule.programID].hasImageArtwork);
- var programsInfo = new List<ProgramInfo>();
- foreach (ScheduleDirect.Program schedule in dailySchedules.SelectMany(d => d.programs))
+ if (images != null)
+ {
+ var imageIndex = images.FindIndex(i => i.programID == schedule.programID.Substring(0, 10));
+ if (imageIndex > -1)
{
- // _logger.LogDebug("Proccesing Schedule for statio ID " + stationID +
- // " which corresponds to channel " + channelNumber + " and program id " +
- // schedule.programID + " which says it has images? " +
- // programDict[schedule.programID].hasImageArtwork);
-
- if (images != null)
- {
- var imageIndex = images.FindIndex(i => i.programID == schedule.programID.Substring(0, 10));
- if (imageIndex > -1)
- {
- var programEntry = programDict[schedule.programID];
+ var programEntry = programDict[schedule.programID];
- var allImages = images[imageIndex].data ?? new List<ScheduleDirect.ImageData>();
- var imagesWithText = allImages.Where(i => string.Equals(i.text, "yes", StringComparison.OrdinalIgnoreCase));
- var imagesWithoutText = allImages.Where(i => string.Equals(i.text, "no", StringComparison.OrdinalIgnoreCase));
+ var allImages = images[imageIndex].data ?? new List<ScheduleDirect.ImageData>();
+ var imagesWithText = allImages.Where(i => string.Equals(i.text, "yes", StringComparison.OrdinalIgnoreCase));
+ var imagesWithoutText = allImages.Where(i => string.Equals(i.text, "no", StringComparison.OrdinalIgnoreCase));
- const double DesiredAspect = 2.0 / 3;
+ const double DesiredAspect = 2.0 / 3;
- programEntry.primaryImage = GetProgramImage(ApiUrl, imagesWithText, true, DesiredAspect) ??
- GetProgramImage(ApiUrl, allImages, true, DesiredAspect);
+ programEntry.primaryImage = GetProgramImage(ApiUrl, imagesWithText, true, DesiredAspect) ??
+ GetProgramImage(ApiUrl, allImages, true, DesiredAspect);
- const double WideAspect = 16.0 / 9;
+ const double WideAspect = 16.0 / 9;
- programEntry.thumbImage = GetProgramImage(ApiUrl, imagesWithText, true, WideAspect);
+ programEntry.thumbImage = GetProgramImage(ApiUrl, imagesWithText, true, WideAspect);
- // Don't supply the same image twice
- if (string.Equals(programEntry.primaryImage, programEntry.thumbImage, StringComparison.Ordinal))
- {
- programEntry.thumbImage = null;
- }
-
- programEntry.backdropImage = GetProgramImage(ApiUrl, imagesWithoutText, true, WideAspect);
-
- // programEntry.bannerImage = GetProgramImage(ApiUrl, data, "Banner", false) ??
- // GetProgramImage(ApiUrl, data, "Banner-L1", false) ??
- // GetProgramImage(ApiUrl, data, "Banner-LO", false) ??
- // GetProgramImage(ApiUrl, data, "Banner-LOT", false);
- }
+ // Don't supply the same image twice
+ if (string.Equals(programEntry.primaryImage, programEntry.thumbImage, StringComparison.Ordinal))
+ {
+ programEntry.thumbImage = null;
}
- programsInfo.Add(GetProgram(channelId, schedule, programDict[schedule.programID]));
- }
+ programEntry.backdropImage = GetProgramImage(ApiUrl, imagesWithoutText, true, WideAspect);
- return programsInfo;
+ // programEntry.bannerImage = GetProgramImage(ApiUrl, data, "Banner", false) ??
+ // GetProgramImage(ApiUrl, data, "Banner-L1", false) ??
+ // GetProgramImage(ApiUrl, data, "Banner-LO", false) ??
+ // GetProgramImage(ApiUrl, data, "Banner-LOT", false);
+ }
}
+
+ programsInfo.Add(GetProgram(channelId, schedule, programDict[schedule.programID]));
}
+
+ return programsInfo;
}
private static int GetSizeOrder(ScheduleDirect.ImageData image)
@@ -483,22 +468,15 @@ namespace Emby.Server.Implementations.LiveTv.Listings
imageIdString = imageIdString.TrimEnd(',') + "]";
- var httpOptions = new HttpRequestOptions()
- {
- Url = ApiUrl + "/metadata/programs",
- UserAgent = UserAgent,
- CancellationToken = cancellationToken,
- RequestContent = imageIdString,
- LogErrorResponseBody = true,
- };
+ using var message = new HttpRequestMessage(HttpMethod.Post, ApiUrl + "/metadata/programs");
+ message.Content = new StringContent(imageIdString, Encoding.UTF8, MediaTypeNames.Application.Json);
try
{
- using (var innerResponse2 = await Post(httpOptions, true, info).ConfigureAwait(false))
- {
- return await _jsonSerializer.DeserializeFromStreamAsync<List<ScheduleDirect.ShowImages>>(
- innerResponse2.Content).ConfigureAwait(false);
- }
+ using var innerResponse2 = await Send(message, true, info, cancellationToken).ConfigureAwait(false);
+ await using var response = await innerResponse2.Content.ReadAsStreamAsync();
+ return await _jsonSerializer.DeserializeFromStreamAsync<List<ScheduleDirect.ShowImages>>(
+ response).ConfigureAwait(false);
}
catch (Exception ex)
{
@@ -519,41 +497,33 @@ namespace Emby.Server.Implementations.LiveTv.Listings
return lineups;
}
- var options = new HttpRequestOptions()
- {
- Url = ApiUrl + "/headends?country=" + country + "&postalcode=" + location,
- UserAgent = UserAgent,
- CancellationToken = cancellationToken,
- LogErrorResponseBody = true
- };
-
- options.RequestHeaders["token"] = token;
+ using var options = new HttpRequestMessage(HttpMethod.Get, ApiUrl + "/headends?country=" + country + "&postalcode=" + location);
+ options.Headers.TryAddWithoutValidation("token", token);
try
{
- using (var httpResponse = await Get(options, false, info).ConfigureAwait(false))
- using (Stream responce = httpResponse.Content)
- {
- var root = await _jsonSerializer.DeserializeFromStreamAsync<List<ScheduleDirect.Headends>>(responce).ConfigureAwait(false);
+ using var httpResponse = await Send(options, false, info, cancellationToken).ConfigureAwait(false);
+ await using var response = await httpResponse.Content.ReadAsStreamAsync().ConfigureAwait(false);
+
+ var root = await _jsonSerializer.DeserializeFromStreamAsync<List<ScheduleDirect.Headends>>(response).ConfigureAwait(false);
- if (root != null)
+ if (root != null)
+ {
+ foreach (ScheduleDirect.Headends headend in root)
{
- foreach (ScheduleDirect.Headends headend in root)
+ foreach (ScheduleDirect.Lineup lineup in headend.lineups)
{
- foreach (ScheduleDirect.Lineup lineup in headend.lineups)
+ lineups.Add(new NameIdPair
{
- lineups.Add(new NameIdPair
- {
- Name = string.IsNullOrWhiteSpace(lineup.name) ? lineup.lineup : lineup.name,
- Id = lineup.uri.Substring(18)
- });
- }
+ Name = string.IsNullOrWhiteSpace(lineup.name) ? lineup.lineup : lineup.name,
+ Id = lineup.uri.Substring(18)
+ });
}
}
- else
- {
- _logger.LogInformation("No lineups available");
- }
+ }
+ else
+ {
+ _logger.LogInformation("No lineups available");
}
}
catch (Exception ex)
@@ -634,17 +604,16 @@ namespace Emby.Server.Implementations.LiveTv.Listings
}
}
- private async Task<HttpResponseInfo> Post(
- HttpRequestOptions options,
+ private async Task<HttpResponseMessage> Send(
+ HttpRequestMessage options,
bool enableRetry,
- ListingsProviderInfo providerInfo)
+ ListingsProviderInfo providerInfo,
+ CancellationToken cancellationToken,
+ HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead)
{
- // Schedules direct requires that the client support compression and will return a 400 response without it
- options.DecompressionMethod = CompressionMethods.Deflate;
-
try
{
- return await _httpClient.Post(options).ConfigureAwait(false);
+ return await _httpClientFactory.CreateClient(NamedClient.Default).SendAsync(options, completionOption, cancellationToken).ConfigureAwait(false);
}
catch (HttpException ex)
{
@@ -661,39 +630,8 @@ namespace Emby.Server.Implementations.LiveTv.Listings
}
}
- options.RequestHeaders["token"] = await GetToken(providerInfo, options.CancellationToken).ConfigureAwait(false);
- return await Post(options, false, providerInfo).ConfigureAwait(false);
- }
-
- private async Task<HttpResponseInfo> Get(
- HttpRequestOptions options,
- bool enableRetry,
- ListingsProviderInfo providerInfo)
- {
- // Schedules direct requires that the client support compression and will return a 400 response without it
- options.DecompressionMethod = CompressionMethods.Deflate;
-
- try
- {
- return await _httpClient.SendAsync(options, HttpMethod.Get).ConfigureAwait(false);
- }
- catch (HttpException ex)
- {
- _tokens.Clear();
-
- if (!ex.StatusCode.HasValue || (int)ex.StatusCode.Value >= 500)
- {
- enableRetry = false;
- }
-
- if (!enableRetry)
- {
- throw;
- }
- }
-
- options.RequestHeaders["token"] = await GetToken(providerInfo, options.CancellationToken).ConfigureAwait(false);
- return await Get(options, false, providerInfo).ConfigureAwait(false);
+ options.Headers.TryAddWithoutValidation("token", await GetToken(providerInfo, cancellationToken).ConfigureAwait(false));
+ return await Send(options, false, providerInfo, cancellationToken).ConfigureAwait(false);
}
private async Task<string> GetTokenInternal(
@@ -701,28 +639,19 @@ namespace Emby.Server.Implementations.LiveTv.Listings
string password,
CancellationToken cancellationToken)
{
- var httpOptions = new HttpRequestOptions()
- {
- Url = ApiUrl + "/token",
- UserAgent = UserAgent,
- RequestContent = "{\"username\":\"" + username + "\",\"password\":\"" + password + "\"}",
- CancellationToken = cancellationToken,
- LogErrorResponseBody = true
- };
- // _logger.LogInformation("Obtaining token from Schedules Direct from addres: " + httpOptions.Url + " with body " +
- // httpOptions.RequestContent);
+ using var options = new HttpRequestMessage(HttpMethod.Post, ApiUrl + "/token");
+ options.Content = new StringContent("{\"username\":\"" + username + "\",\"password\":\"" + password + "\"}", Encoding.UTF8, MediaTypeNames.Application.Json);
- using (var response = await Post(httpOptions, false, null).ConfigureAwait(false))
+ using var response = await Send(options, false, null, cancellationToken).ConfigureAwait(false);
+ await using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false);
+ var root = await _jsonSerializer.DeserializeFromStreamAsync<ScheduleDirect.Token>(stream).ConfigureAwait(false);
+ if (root.message == "OK")
{
- var root = await _jsonSerializer.DeserializeFromStreamAsync<ScheduleDirect.Token>(response.Content).ConfigureAwait(false);
- if (root.message == "OK")
- {
- _logger.LogInformation("Authenticated with Schedules Direct token: " + root.token);
- return root.token;
- }
-
- throw new Exception("Could not authenticate with Schedules Direct Error: " + root.message);
+ _logger.LogInformation("Authenticated with Schedules Direct token: " + root.token);
+ return root.token;
}
+
+ throw new Exception("Could not authenticate with Schedules Direct Error: " + root.message);
}
private async Task AddLineupToAccount(ListingsProviderInfo info, CancellationToken cancellationToken)
@@ -741,20 +670,9 @@ namespace Emby.Server.Implementations.LiveTv.Listings
_logger.LogInformation("Adding new LineUp ");
- var httpOptions = new HttpRequestOptions()
- {
- Url = ApiUrl + "/lineups/" + info.ListingsId,
- UserAgent = UserAgent,
- CancellationToken = cancellationToken,
- LogErrorResponseBody = true,
- BufferContent = false
- };
-
- httpOptions.RequestHeaders["token"] = token;
-
- using (await _httpClient.SendAsync(httpOptions, HttpMethod.Put).ConfigureAwait(false))
- {
- }
+ using var options = new HttpRequestMessage(HttpMethod.Put, ApiUrl + "/lineups/" + info.ListingsId);
+ options.Headers.TryAddWithoutValidation("token", token);
+ using var response = await _httpClientFactory.CreateClient(NamedClient.Default).SendAsync(options, HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false);
}
private async Task<bool> HasLineup(ListingsProviderInfo info, CancellationToken cancellationToken)
@@ -773,25 +691,17 @@ namespace Emby.Server.Implementations.LiveTv.Listings
_logger.LogInformation("Headends on account ");
- var options = new HttpRequestOptions()
- {
- Url = ApiUrl + "/lineups",
- UserAgent = UserAgent,
- CancellationToken = cancellationToken,
- LogErrorResponseBody = true
- };
-
- options.RequestHeaders["token"] = token;
+ using var options = new HttpRequestMessage(HttpMethod.Get, ApiUrl + "/lineups");
+ options.Headers.TryAddWithoutValidation("token", token);
try
{
- using (var httpResponse = await Get(options, false, null).ConfigureAwait(false))
- using (var response = httpResponse.Content)
- {
- var root = await _jsonSerializer.DeserializeFromStreamAsync<ScheduleDirect.Lineups>(response).ConfigureAwait(false);
+ using var httpResponse = await Send(options, false, null, cancellationToken).ConfigureAwait(false);
+ await using var stream = await httpResponse.Content.ReadAsStreamAsync().ConfigureAwait(false);
+ using var response = httpResponse.Content;
+ var root = await _jsonSerializer.DeserializeFromStreamAsync<ScheduleDirect.Lineups>(stream).ConfigureAwait(false);
- return root.lineups.Any(i => string.Equals(info.ListingsId, i.lineup, StringComparison.OrdinalIgnoreCase));
- }
+ return root.lineups.Any(i => string.Equals(info.ListingsId, i.lineup, StringComparison.OrdinalIgnoreCase));
}
catch (HttpException ex)
{
@@ -856,55 +766,43 @@ namespace Emby.Server.Implementations.LiveTv.Listings
throw new Exception("token required");
}
- var httpOptions = new HttpRequestOptions()
- {
- Url = ApiUrl + "/lineups/" + listingsId,
- UserAgent = UserAgent,
- CancellationToken = cancellationToken,
- LogErrorResponseBody = true,
- };
-
- httpOptions.RequestHeaders["token"] = token;
+ using var options = new HttpRequestMessage(HttpMethod.Get, ApiUrl + "/lineups/" + listingsId);
+ options.Headers.TryAddWithoutValidation("token", token);
var list = new List<ChannelInfo>();
- using (var httpResponse = await Get(httpOptions, true, info).ConfigureAwait(false))
- using (var response = httpResponse.Content)
- {
- var root = await _jsonSerializer.DeserializeFromStreamAsync<ScheduleDirect.Channel>(response).ConfigureAwait(false);
- _logger.LogInformation("Found {ChannelCount} channels on the lineup on ScheduleDirect", root.map.Count);
- _logger.LogInformation("Mapping Stations to Channel");
-
- var allStations = root.stations ?? Enumerable.Empty<ScheduleDirect.Station>();
+ using var httpResponse = await Send(options, true, info, cancellationToken).ConfigureAwait(false);
+ await using var stream = await httpResponse.Content.ReadAsStreamAsync().ConfigureAwait(false);
+ var root = await _jsonSerializer.DeserializeFromStreamAsync<ScheduleDirect.Channel>(stream).ConfigureAwait(false);
+ _logger.LogInformation("Found {ChannelCount} channels on the lineup on ScheduleDirect", root.map.Count);
+ _logger.LogInformation("Mapping Stations to Channel");
- foreach (ScheduleDirect.Map map in root.map)
- {
- var channelNumber = GetChannelNumber(map);
+ var allStations = root.stations ?? Enumerable.Empty<ScheduleDirect.Station>();
- var station = allStations.FirstOrDefault(item => string.Equals(item.stationID, map.stationID, StringComparison.OrdinalIgnoreCase));
- if (station == null)
- {
- station = new ScheduleDirect.Station
- {
- stationID = map.stationID
- };
- }
+ foreach (ScheduleDirect.Map map in root.map)
+ {
+ var channelNumber = GetChannelNumber(map);
- var channelInfo = new ChannelInfo
- {
- Id = station.stationID,
- CallSign = station.callsign,
- Number = channelNumber,
- Name = string.IsNullOrWhiteSpace(station.name) ? channelNumber : station.name
- };
+ var station = allStations.FirstOrDefault(item => string.Equals(item.stationID, map.stationID, StringComparison.OrdinalIgnoreCase));
+ if (station == null)
+ {
+ station = new ScheduleDirect.Station { stationID = map.stationID };
+ }
- if (station.logo != null)
- {
- channelInfo.ImageUrl = station.logo.URL;
- }
+ var channelInfo = new ChannelInfo
+ {
+ Id = station.stationID,
+ CallSign = station.callsign,
+ Number = channelNumber,
+ Name = string.IsNullOrWhiteSpace(station.name) ? channelNumber : station.name
+ };
- list.Add(channelInfo);
+ if (station.logo != null)
+ {
+ channelInfo.ImageUrl = station.logo.URL;
}
+
+ list.Add(channelInfo);
}
return list;
diff --git a/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs b/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs
index f33d07174..2d6f453bd 100644
--- a/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs
+++ b/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs
@@ -25,20 +25,20 @@ namespace Emby.Server.Implementations.LiveTv.Listings
public class XmlTvListingsProvider : IListingsProvider
{
private readonly IServerConfigurationManager _config;
- private readonly IHttpClient _httpClient;
+ private readonly IHttpClientFactory _httpClientFactory;
private readonly ILogger<XmlTvListingsProvider> _logger;
private readonly IFileSystem _fileSystem;
private readonly IZipClient _zipClient;
public XmlTvListingsProvider(
IServerConfigurationManager config,
- IHttpClient httpClient,
+ IHttpClientFactory httpClientFactory,
ILogger<XmlTvListingsProvider> logger,
IFileSystem fileSystem,
IZipClient zipClient)
{
_config = config;
- _httpClient = httpClient;
+ _httpClientFactory = httpClientFactory;
_logger = logger;
_fileSystem = fileSystem;
_zipClient = zipClient;
@@ -78,28 +78,11 @@ namespace Emby.Server.Implementations.LiveTv.Listings
Directory.CreateDirectory(Path.GetDirectoryName(cacheFile));
- using (var res = await _httpClient.SendAsync(
- new HttpRequestOptions
- {
- CancellationToken = cancellationToken,
- Url = path,
- DecompressionMethod = CompressionMethods.Gzip,
- },
- HttpMethod.Get).ConfigureAwait(false))
- using (var stream = res.Content)
- using (var fileStream = new FileStream(cacheFile, FileMode.CreateNew))
+ using var response = await _httpClientFactory.CreateClient(NamedClient.Default).GetAsync(path, cancellationToken).ConfigureAwait(false);
+ await using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false);
+ await using (var fileStream = new FileStream(cacheFile, FileMode.CreateNew))
{
- if (res.ContentHeaders.ContentEncoding.Contains("gzip"))
- {
- using (var gzStream = new GZipStream(stream, CompressionMode.Decompress))
- {
- await gzStream.CopyToAsync(fileStream, cancellationToken).ConfigureAwait(false);
- }
- }
- else
- {
- await stream.CopyToAsync(fileStream, cancellationToken).ConfigureAwait(false);
- }
+ await stream.CopyToAsync(fileStream, cancellationToken).ConfigureAwait(false);
}
return UnzipIfNeeded(path, cacheFile);
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs
index 2b5f69d41..28e30fac8 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs
@@ -31,7 +31,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
{
public class HdHomerunHost : BaseTunerHost, ITunerHost, IConfigurableTunerHost
{
- private readonly IHttpClient _httpClient;
+ private readonly IHttpClientFactory _httpClientFactory;
private readonly IServerApplicationHost _appHost;
private readonly ISocketFactory _socketFactory;
private readonly INetworkManager _networkManager;
@@ -43,7 +43,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
IServerConfigurationManager config,
ILogger<HdHomerunHost> logger,
IFileSystem fileSystem,
- IHttpClient httpClient,
+ IHttpClientFactory httpClientFactory,
IServerApplicationHost appHost,
ISocketFactory socketFactory,
INetworkManager networkManager,
@@ -51,7 +51,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
IMemoryCache memoryCache)
: base(config, logger, fileSystem, memoryCache)
{
- _httpClient = httpClient;
+ _httpClientFactory = httpClientFactory;
_appHost = appHost;
_socketFactory = socketFactory;
_networkManager = networkManager;
@@ -71,15 +71,8 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
{
var model = await GetModelInfo(info, false, cancellationToken).ConfigureAwait(false);
- var options = new HttpRequestOptions
- {
- Url = model.LineupURL,
- CancellationToken = cancellationToken,
- BufferContent = false
- };
-
- using var response = await _httpClient.SendAsync(options, HttpMethod.Get).ConfigureAwait(false);
- await using var stream = response.Content;
+ using var response = await _httpClientFactory.CreateClient(NamedClient.Default).GetAsync(model.LineupURL, HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false);
+ await using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false);
var lineup = await JsonSerializer.DeserializeAsync<List<Channels>>(stream, cancellationToken: cancellationToken)
.ConfigureAwait(false) ?? new List<Channels>();
@@ -133,14 +126,10 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
try
{
- using var response = await _httpClient.SendAsync(
- new HttpRequestOptions
- {
- Url = string.Format(CultureInfo.InvariantCulture, "{0}/discover.json", GetApiUrl(info)),
- CancellationToken = cancellationToken,
- BufferContent = false
- }, HttpMethod.Get).ConfigureAwait(false);
- await using var stream = response.Content;
+ using var response = await _httpClientFactory.CreateClient(NamedClient.Default)
+ .GetAsync(string.Format(CultureInfo.InvariantCulture, "{0}/discover.json", GetApiUrl(info)), HttpCompletionOption.ResponseHeadersRead, cancellationToken)
+ .ConfigureAwait(false);
+ await using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false);
var discoverResponse = await JsonSerializer.DeserializeAsync<DiscoverResponse>(stream, cancellationToken: cancellationToken)
.ConfigureAwait(false);
@@ -183,48 +172,41 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
{
var model = await GetModelInfo(info, false, cancellationToken).ConfigureAwait(false);
- using (var response = await _httpClient.SendAsync(
- new HttpRequestOptions()
- {
- Url = string.Format(CultureInfo.InvariantCulture, "{0}/tuners.html", GetApiUrl(info)),
- CancellationToken = cancellationToken,
- BufferContent = false
- },
- HttpMethod.Get).ConfigureAwait(false))
- using (var stream = response.Content)
- using (var sr = new StreamReader(stream, System.Text.Encoding.UTF8))
- {
- var tuners = new List<LiveTvTunerInfo>();
- while (!sr.EndOfStream)
+ using var response = await _httpClientFactory.CreateClient(NamedClient.Default)
+ .GetAsync(string.Format(CultureInfo.InvariantCulture, "{0}/tuners.html", GetApiUrl(info)), HttpCompletionOption.ResponseHeadersRead, cancellationToken)
+ .ConfigureAwait(false);
+ await using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false);
+ using var sr = new StreamReader(stream, System.Text.Encoding.UTF8);
+ var tuners = new List<LiveTvTunerInfo>();
+ while (!sr.EndOfStream)
+ {
+ string line = StripXML(sr.ReadLine());
+ if (line.Contains("Channel", StringComparison.Ordinal))
{
- string line = StripXML(sr.ReadLine());
- if (line.Contains("Channel", StringComparison.Ordinal))
+ LiveTvTunerStatus status;
+ var index = line.IndexOf("Channel", StringComparison.OrdinalIgnoreCase);
+ var name = line.Substring(0, index - 1);
+ var currentChannel = line.Substring(index + 7);
+ if (currentChannel != "none")
{
- LiveTvTunerStatus status;
- var index = line.IndexOf("Channel", StringComparison.OrdinalIgnoreCase);
- var name = line.Substring(0, index - 1);
- var currentChannel = line.Substring(index + 7);
- if (currentChannel != "none")
- {
- status = LiveTvTunerStatus.LiveTv;
- }
- else
- {
- status = LiveTvTunerStatus.Available;
- }
-
- tuners.Add(new LiveTvTunerInfo
- {
- Name = name,
- SourceType = string.IsNullOrWhiteSpace(model.ModelNumber) ? Name : model.ModelNumber,
- ProgramName = currentChannel,
- Status = status
- });
+ status = LiveTvTunerStatus.LiveTv;
+ }
+ else
+ {
+ status = LiveTvTunerStatus.Available;
}
- }
- return tuners;
+ tuners.Add(new LiveTvTunerInfo
+ {
+ Name = name,
+ SourceType = string.IsNullOrWhiteSpace(model.ModelNumber) ? Name : model.ModelNumber,
+ ProgramName = currentChannel,
+ Status = status
+ });
+ }
}
+
+ return tuners;
}
private static string StripXML(string source)
@@ -634,7 +616,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
info,
streamId,
FileSystem,
- _httpClient,
+ _httpClientFactory,
Logger,
Config,
_appHost,
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs
index 8fc29fb4a..8107bc427 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs
@@ -5,6 +5,7 @@ using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
+using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Common.Extensions;
@@ -26,7 +27,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
{
public class M3UTunerHost : BaseTunerHost, ITunerHost, IConfigurableTunerHost
{
- private readonly IHttpClient _httpClient;
+ private readonly IHttpClientFactory _httpClientFactory;
private readonly IServerApplicationHost _appHost;
private readonly INetworkManager _networkManager;
private readonly IMediaSourceManager _mediaSourceManager;
@@ -37,14 +38,14 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
IMediaSourceManager mediaSourceManager,
ILogger<M3UTunerHost> logger,
IFileSystem fileSystem,
- IHttpClient httpClient,
+ IHttpClientFactory httpClientFactory,
IServerApplicationHost appHost,
INetworkManager networkManager,
IStreamHelper streamHelper,
IMemoryCache memoryCache)
: base(config, logger, fileSystem, memoryCache)
{
- _httpClient = httpClient;
+ _httpClientFactory = httpClientFactory;
_appHost = appHost;
_networkManager = networkManager;
_mediaSourceManager = mediaSourceManager;
@@ -64,7 +65,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
{
var channelIdPrefix = GetFullChannelIdPrefix(info);
- return await new M3uParser(Logger, _httpClient, _appHost).Parse(info.Url, channelIdPrefix, info.Id, cancellationToken).ConfigureAwait(false);
+ return await new M3uParser(Logger, _httpClientFactory, _appHost).Parse(info.Url, channelIdPrefix, info.Id, cancellationToken).ConfigureAwait(false);
}
public Task<List<LiveTvTunerInfo>> GetTunerInfos(CancellationToken cancellationToken)
@@ -116,7 +117,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
if (!_disallowedSharedStreamExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase))
{
- return new SharedHttpStream(mediaSource, info, streamId, FileSystem, _httpClient, Logger, Config, _appHost, _streamHelper);
+ return new SharedHttpStream(mediaSource, info, streamId, FileSystem, _httpClientFactory, Logger, Config, _appHost, _streamHelper);
}
}
@@ -125,7 +126,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
public async Task Validate(TunerHostInfo info)
{
- using (var stream = await new M3uParser(Logger, _httpClient, _appHost).GetListingsStream(info.Url, CancellationToken.None).ConfigureAwait(false))
+ using (var stream = await new M3uParser(Logger, _httpClientFactory, _appHost).GetListingsStream(info.Url, CancellationToken.None).ConfigureAwait(false))
{
}
}
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs
index 875977219..f066a749e 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs
@@ -5,6 +5,7 @@ using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
+using System.Net.Http;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
@@ -19,13 +20,13 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
public class M3uParser
{
private readonly ILogger _logger;
- private readonly IHttpClient _httpClient;
+ private readonly IHttpClientFactory _httpClientFactory;
private readonly IServerApplicationHost _appHost;
- public M3uParser(ILogger logger, IHttpClient httpClient, IServerApplicationHost appHost)
+ public M3uParser(ILogger logger, IHttpClientFactory httpClientFactory, IServerApplicationHost appHost)
{
_logger = logger;
- _httpClient = httpClient;
+ _httpClientFactory = httpClientFactory;
_appHost = appHost;
}
@@ -51,13 +52,8 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
{
if (url.StartsWith("http", StringComparison.OrdinalIgnoreCase))
{
- return _httpClient.Get(new HttpRequestOptions
- {
- Url = url,
- CancellationToken = cancellationToken,
- // Some data providers will require a user agent
- UserAgent = _appHost.ApplicationUserAgent
- });
+ return _httpClientFactory.CreateClient(NamedClient.Default)
+ .GetStreamAsync(url);
}
return Task.FromResult((Stream)File.OpenRead(url));
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs
index bc4dcd894..6c10fca8c 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs
@@ -21,7 +21,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
{
public class SharedHttpStream : LiveStream, IDirectStreamProvider
{
- private readonly IHttpClient _httpClient;
+ private readonly IHttpClientFactory _httpClientFactory;
private readonly IServerApplicationHost _appHost;
public SharedHttpStream(
@@ -29,14 +29,14 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
TunerHostInfo tunerHostInfo,
string originalStreamId,
IFileSystem fileSystem,
- IHttpClient httpClient,
+ IHttpClientFactory httpClientFactory,
ILogger logger,
IConfigurationManager configurationManager,
IServerApplicationHost appHost,
IStreamHelper streamHelper)
: base(mediaSource, tunerHostInfo, fileSystem, logger, configurationManager, streamHelper)
{
- _httpClient = httpClient;
+ _httpClientFactory = httpClientFactory;
_appHost = appHost;
OriginalStreamId = originalStreamId;
EnableStreamSharing = true;
@@ -55,25 +55,14 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
var typeName = GetType().Name;
Logger.LogInformation("Opening " + typeName + " Live stream from {0}", url);
- var httpRequestOptions = new HttpRequestOptions
- {
- Url = url,
- CancellationToken = CancellationToken.None,
- BufferContent = false,
- DecompressionMethod = CompressionMethods.None
- };
-
- foreach (var header in mediaSource.RequiredHttpHeaders)
- {
- httpRequestOptions.RequestHeaders[header.Key] = header.Value;
- }
-
- var response = await _httpClient.SendAsync(httpRequestOptions, HttpMethod.Get).ConfigureAwait(false);
+ using var response = await _httpClientFactory.CreateClient(NamedClient.Default)
+ .GetAsync(url, HttpCompletionOption.ResponseHeadersRead, CancellationToken.None)
+ .ConfigureAwait(false);
var extension = "ts";
var requiresRemux = false;
- var contentType = response.ContentType ?? string.Empty;
+ var contentType = response.Content.Headers.ContentType.ToString();
if (contentType.IndexOf("matroska", StringComparison.OrdinalIgnoreCase) != -1)
{
requiresRemux = true;
@@ -132,24 +121,22 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
}
}
- private Task StartStreaming(HttpResponseInfo response, TaskCompletionSource<bool> openTaskCompletionSource, CancellationToken cancellationToken)
+ private Task StartStreaming(HttpResponseMessage response, TaskCompletionSource<bool> openTaskCompletionSource, CancellationToken cancellationToken)
{
return Task.Run(async () =>
{
try
{
Logger.LogInformation("Beginning {0} stream to {1}", GetType().Name, TempFilePath);
- using (response)
- using (var stream = response.Content)
- using (var fileStream = new FileStream(TempFilePath, FileMode.Create, FileAccess.Write, FileShare.Read))
- {
- await StreamHelper.CopyToAsync(
- stream,
- fileStream,
- IODefaults.CopyToBufferSize,
- () => Resolve(openTaskCompletionSource),
- cancellationToken).ConfigureAwait(false);
- }
+ using var message = response;
+ await using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false);
+ await using var fileStream = new FileStream(TempFilePath, FileMode.Create, FileAccess.Write, FileShare.Read);
+ await StreamHelper.CopyToAsync(
+ stream,
+ fileStream,
+ IODefaults.CopyToBufferSize,
+ () => Resolve(openTaskCompletionSource),
+ cancellationToken).ConfigureAwait(false);
}
catch (OperationCanceledException ex)
{
diff --git a/Emby.Server.Implementations/Updates/InstallationManager.cs b/Emby.Server.Implementations/Updates/InstallationManager.cs
index 4f54c06dd..f121a3493 100644
--- a/Emby.Server.Implementations/Updates/InstallationManager.cs
+++ b/Emby.Server.Implementations/Updates/InstallationManager.cs
@@ -34,7 +34,7 @@ namespace Emby.Server.Implementations.Updates
/// </summary>
private readonly ILogger<InstallationManager> _logger;
private readonly IApplicationPaths _appPaths;
- private readonly IHttpClient _httpClient;
+ private readonly IHttpClientFactory _httpClientFactory;
private readonly IJsonSerializer _jsonSerializer;
private readonly IServerConfigurationManager _config;
private readonly IFileSystem _fileSystem;
@@ -63,7 +63,7 @@ namespace Emby.Server.Implementations.Updates
ILogger<InstallationManager> logger,
IApplicationHost appHost,
IApplicationPaths appPaths,
- IHttpClient httpClient,
+ IHttpClientFactory httpClientFactory,
IJsonSerializer jsonSerializer,
IServerConfigurationManager config,
IFileSystem fileSystem,
@@ -80,7 +80,7 @@ namespace Emby.Server.Implementations.Updates
_logger = logger;
_applicationHost = appHost;
_appPaths = appPaths;
- _httpClient = httpClient;
+ _httpClientFactory = httpClientFactory;
_jsonSerializer = jsonSerializer;
_config = config;
_fileSystem = fileSystem;
@@ -116,26 +116,18 @@ namespace Emby.Server.Implementations.Updates
{
try
{
- using (var response = await _httpClient.SendAsync(
- new HttpRequestOptions
- {
- Url = manifest,
- CancellationToken = cancellationToken,
- CacheMode = CacheMode.Unconditional,
- CacheLength = TimeSpan.FromMinutes(3)
- },
- HttpMethod.Get).ConfigureAwait(false))
- using (Stream stream = response.Content)
+ using var response = await _httpClientFactory.CreateClient(NamedClient.Default)
+ .GetAsync(manifest, cancellationToken).ConfigureAwait(false);
+ await using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false);
+
+ try
{
- try
- {
- return await _jsonSerializer.DeserializeFromStreamAsync<IReadOnlyList<PackageInfo>>(stream).ConfigureAwait(false);
- }
- catch (SerializationException ex)
- {
- _logger.LogError(ex, "Failed to deserialize the plugin manifest retrieved from {Manifest}", manifest);
- return Array.Empty<PackageInfo>();
- }
+ return await _jsonSerializer.DeserializeFromStreamAsync<IReadOnlyList<PackageInfo>>(stream).ConfigureAwait(false);
+ }
+ catch (SerializationException ex)
+ {
+ _logger.LogError(ex, "Failed to deserialize the plugin manifest retrieved from {Manifest}", manifest);
+ return Array.Empty<PackageInfo>();
}
}
catch (UriFormatException ex)
@@ -360,42 +352,34 @@ namespace Emby.Server.Implementations.Updates
// Always override the passed-in target (which is a file) and figure it out again
string targetDir = Path.Combine(_appPaths.PluginsPath, package.Name);
+ using var response = await _httpClientFactory.CreateClient(NamedClient.Default)
+ .GetAsync(package.SourceUrl, cancellationToken).ConfigureAwait(false);
+ await using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false);
+
// CA5351: Do Not Use Broken Cryptographic Algorithms
#pragma warning disable CA5351
- using (var res = await _httpClient.SendAsync(
- new HttpRequestOptions
- {
- Url = package.SourceUrl,
- CancellationToken = cancellationToken,
- // We need it to be buffered for setting the position
- BufferContent = true
- },
- HttpMethod.Get).ConfigureAwait(false))
- using (var stream = res.Content)
- using (var md5 = MD5.Create())
- {
- cancellationToken.ThrowIfCancellationRequested();
+ using var md5 = MD5.Create();
+ cancellationToken.ThrowIfCancellationRequested();
- var hash = Hex.Encode(md5.ComputeHash(stream));
- if (!string.Equals(package.Checksum, hash, StringComparison.OrdinalIgnoreCase))
- {
- _logger.LogError(
- "The checksums didn't match while installing {Package}, expected: {Expected}, got: {Received}",
- package.Name,
- package.Checksum,
- hash);
- throw new InvalidDataException("The checksum of the received data doesn't match.");
- }
-
- if (Directory.Exists(targetDir))
- {
- Directory.Delete(targetDir, true);
- }
+ var hash = Hex.Encode(md5.ComputeHash(stream));
+ if (!string.Equals(package.Checksum, hash, StringComparison.OrdinalIgnoreCase))
+ {
+ _logger.LogError(
+ "The checksums didn't match while installing {Package}, expected: {Expected}, got: {Received}",
+ package.Name,
+ package.Checksum,
+ hash);
+ throw new InvalidDataException("The checksum of the received data doesn't match.");
+ }
- stream.Position = 0;
- _zipClient.ExtractAllFromZip(stream, targetDir, true);
+ if (Directory.Exists(targetDir))
+ {
+ Directory.Delete(targetDir, true);
}
+ stream.Position = 0;
+ _zipClient.ExtractAllFromZip(stream, targetDir, true);
+
#pragma warning restore CA5351
}
diff --git a/Jellyfin.Api/Controllers/LiveTvController.cs b/Jellyfin.Api/Controllers/LiveTvController.cs
index 3ccfc826d..eace0f911 100644
--- a/Jellyfin.Api/Controllers/LiveTvController.cs
+++ b/Jellyfin.Api/Controllers/LiveTvController.cs
@@ -16,6 +16,7 @@ using Jellyfin.Api.Models.LiveTvDtos;
using Jellyfin.Data.Enums;
using MediaBrowser.Common;
using MediaBrowser.Common.Configuration;
+using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.TV;
@@ -1069,7 +1070,7 @@ namespace Jellyfin.Api.Controllers
[ProducesResponseType(StatusCodes.Status200OK)]
public async Task<ActionResult> GetSchedulesDirectCountries()
{
- var client = _httpClientFactory.CreateClient();
+ var client = _httpClientFactory.CreateClient(NamedClient.Default);
// https://json.schedulesdirect.org/20141201/available/countries
// Can't dispose the response as it's required up the call chain.
var response = await client.GetAsync("https://json.schedulesdirect.org/20141201/available/countries")
diff --git a/Jellyfin.Api/Controllers/RemoteImageController.cs b/Jellyfin.Api/Controllers/RemoteImageController.cs
index 30a4f73fc..81aefd15c 100644
--- a/Jellyfin.Api/Controllers/RemoteImageController.cs
+++ b/Jellyfin.Api/Controllers/RemoteImageController.cs
@@ -9,6 +9,7 @@ using System.Threading;
using System.Threading.Tasks;
using Jellyfin.Api.Constants;
using MediaBrowser.Common.Extensions;
+using MediaBrowser.Common.Net;
using MediaBrowser.Controller;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Providers;
@@ -244,7 +245,7 @@ namespace Jellyfin.Api.Controllers
/// <returns>Task.</returns>
private async Task DownloadImage(string url, Guid urlHash, string pointerCachePath)
{
- var httpClient = _httpClientFactory.CreateClient();
+ var httpClient = _httpClientFactory.CreateClient(NamedClient.Default);
using var response = await httpClient.GetAsync(url).ConfigureAwait(false);
var ext = response.Content.Headers.ContentType.MediaType.Split('/').Last();
var fullCachePath = GetFullCachePath(urlHash + "." + ext);
diff --git a/Jellyfin.Api/Controllers/VideosController.cs b/Jellyfin.Api/Controllers/VideosController.cs
index 0978d44e9..83b03f965 100644
--- a/Jellyfin.Api/Controllers/VideosController.cs
+++ b/Jellyfin.Api/Controllers/VideosController.cs
@@ -11,6 +11,7 @@ using Jellyfin.Api.Extensions;
using Jellyfin.Api.Helpers;
using Jellyfin.Api.Models.StreamingDtos;
using MediaBrowser.Common.Configuration;
+using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Devices;
using MediaBrowser.Controller.Dlna;
@@ -473,7 +474,7 @@ namespace Jellyfin.Api.Controllers
{
StreamingHelpers.AddDlnaHeaders(state, Response.Headers, true, startTimeTicks, Request, _dlnaManager);
- var httpClient = _httpClientFactory.CreateClient();
+ var httpClient = _httpClientFactory.CreateClient(NamedClient.Default);
return await FileStreamResponseHelpers.GetStaticRemoteStreamResult(state, isHeadRequest, httpClient, HttpContext).ConfigureAwait(false);
}
diff --git a/Jellyfin.Api/Helpers/AudioHelper.cs b/Jellyfin.Api/Helpers/AudioHelper.cs
index eae2be05b..a3f2d88ce 100644
--- a/Jellyfin.Api/Helpers/AudioHelper.cs
+++ b/Jellyfin.Api/Helpers/AudioHelper.cs
@@ -3,6 +3,7 @@ using System.Threading;
using System.Threading.Tasks;
using Jellyfin.Api.Models.StreamingDtos;
using MediaBrowser.Common.Configuration;
+using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Devices;
using MediaBrowser.Controller.Dlna;
@@ -138,7 +139,7 @@ namespace Jellyfin.Api.Helpers
{
StreamingHelpers.AddDlnaHeaders(state, _httpContextAccessor.HttpContext.Response.Headers, true, streamingRequest.StartTimeTicks, _httpContextAccessor.HttpContext.Request, _dlnaManager);
- var httpClient = _httpClientFactory.CreateClient();
+ var httpClient = _httpClientFactory.CreateClient(NamedClient.Default);
return await FileStreamResponseHelpers.GetStaticRemoteStreamResult(state, isHeadRequest, httpClient, _httpContextAccessor.HttpContext).ConfigureAwait(false);
}
diff --git a/Jellyfin.Api/Helpers/FileStreamResponseHelpers.cs b/Jellyfin.Api/Helpers/FileStreamResponseHelpers.cs
index deb54dbe6..884bfbe44 100644
--- a/Jellyfin.Api/Helpers/FileStreamResponseHelpers.cs
+++ b/Jellyfin.Api/Helpers/FileStreamResponseHelpers.cs
@@ -72,7 +72,7 @@ namespace Jellyfin.Api.Helpers
return new NoContentResult();
}
- return new PhysicalFileResult(path, contentType);
+ return new PhysicalFileResult(path, contentType) { EnableRangeProcessing = true };
}
/// <summary>
diff --git a/Jellyfin.Data/Entities/ActivityLog.cs b/Jellyfin.Data/Entities/ActivityLog.cs
index 3858916d1..620e82830 100644
--- a/Jellyfin.Data/Entities/ActivityLog.cs
+++ b/Jellyfin.Data/Entities/ActivityLog.cs
@@ -1,5 +1,3 @@
-#pragma warning disable CS1591
-
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
@@ -11,7 +9,7 @@ namespace Jellyfin.Data.Entities
/// <summary>
/// An entity referencing an activity log entry.
/// </summary>
- public partial class ActivityLog : IHasConcurrencyToken
+ public class ActivityLog : IHasConcurrencyToken
{
/// <summary>
/// Initializes a new instance of the <see cref="ActivityLog"/> class.
@@ -32,13 +30,11 @@ namespace Jellyfin.Data.Entities
throw new ArgumentNullException(nameof(type));
}
- this.Name = name;
- this.Type = type;
- this.UserId = userId;
- this.DateCreated = DateTime.UtcNow;
- this.LogSeverity = LogLevel.Trace;
-
- Init();
+ Name = name;
+ Type = type;
+ UserId = userId;
+ DateCreated = DateTime.UtcNow;
+ LogSeverity = LogLevel.Trace;
}
/// <summary>
@@ -47,38 +43,21 @@ namespace Jellyfin.Data.Entities
/// </summary>
protected ActivityLog()
{
- Init();
- }
-
- /// <summary>
- /// Static create function (for use in LINQ queries, etc.)
- /// </summary>
- /// <param name="name">The name.</param>
- /// <param name="type">The type.</param>
- /// <param name="userId">The user's id.</param>
- /// <returns>The new <see cref="ActivityLog"/> instance.</returns>
- public static ActivityLog Create(string name, string type, Guid userId)
- {
- return new ActivityLog(name, type, userId);
}
- /*************************************************************************
- * Properties
- *************************************************************************/
-
/// <summary>
/// Gets or sets the identity of this instance.
/// This is the key in the backing database.
/// </summary>
- [Key]
- [Required]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; protected set; }
/// <summary>
/// Gets or sets the name.
- /// Required, Max length = 512.
/// </summary>
+ /// <remarks>
+ /// Required, Max length = 512.
+ /// </remarks>
[Required]
[MaxLength(512)]
[StringLength(512)]
@@ -86,24 +65,30 @@ namespace Jellyfin.Data.Entities
/// <summary>
/// Gets or sets the overview.
- /// Max length = 512.
/// </summary>
+ /// <remarks>
+ /// Max length = 512.
+ /// </remarks>
[MaxLength(512)]
[StringLength(512)]
public string Overview { get; set; }
/// <summary>
/// Gets or sets the short overview.
- /// Max length = 512.
/// </summary>
+ /// <remarks>
+ /// Max length = 512.
+ /// </remarks>
[MaxLength(512)]
[StringLength(512)]
public string ShortOverview { get; set; }
/// <summary>
/// Gets or sets the type.
- /// Required, Max length = 256.
/// </summary>
+ /// <remarks>
+ /// Required, Max length = 256.
+ /// </remarks>
[Required]
[MaxLength(256)]
[StringLength(256)]
@@ -111,43 +96,42 @@ namespace Jellyfin.Data.Entities
/// <summary>
/// Gets or sets the user id.
- /// Required.
/// </summary>
- [Required]
+ /// <remarks>
+ /// Required.
+ /// </remarks>
public Guid UserId { get; set; }
/// <summary>
/// Gets or sets the item id.
- /// Max length = 256.
/// </summary>
+ /// <remarks>
+ /// Max length = 256.
+ /// </remarks>
[MaxLength(256)]
[StringLength(256)]
public string ItemId { get; set; }
/// <summary>
/// Gets or sets the date created. This should be in UTC.
- /// Required.
/// </summary>
- [Required]
+ /// <remarks>
+ /// Required.
+ /// </remarks>
public DateTime DateCreated { get; set; }
/// <summary>
/// Gets or sets the log severity. Default is <see cref="LogLevel.Trace"/>.
- /// Required.
/// </summary>
- [Required]
+ /// <remarks>
+ /// Required.
+ /// </remarks>
public LogLevel LogSeverity { get; set; }
- /// <summary>
- /// Gets or sets the row version.
- /// Required, ConcurrencyToken.
- /// </summary>
+ /// <inheritdoc />
[ConcurrencyCheck]
- [Required]
public uint RowVersion { get; set; }
- partial void Init();
-
/// <inheritdoc />
public void OnSavingChanges()
{
diff --git a/Jellyfin.Data/Entities/DisplayPreferences.cs b/Jellyfin.Data/Entities/DisplayPreferences.cs
index cda83f6bb..701e4df00 100644
--- a/Jellyfin.Data/Entities/DisplayPreferences.cs
+++ b/Jellyfin.Data/Entities/DisplayPreferences.cs
@@ -1,4 +1,6 @@
-using System;
+#pragma warning disable CA2227
+
+using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
diff --git a/Jellyfin.Data/Entities/Group.cs b/Jellyfin.Data/Entities/Group.cs
index ca12ba421..878811e59 100644
--- a/Jellyfin.Data/Entities/Group.cs
+++ b/Jellyfin.Data/Entities/Group.cs
@@ -1,9 +1,8 @@
-#pragma warning disable CS1591
+#pragma warning disable CA2227
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
-using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using Jellyfin.Data.Enums;
using Jellyfin.Data.Interfaces;
@@ -13,11 +12,10 @@ namespace Jellyfin.Data.Entities
/// <summary>
/// An entity representing a group.
/// </summary>
- public partial class Group : IHasPermissions, IHasConcurrencyToken
+ public class Group : IHasPermissions, IHasConcurrencyToken
{
/// <summary>
/// Initializes a new instance of the <see cref="Group"/> class.
- /// Public constructor with required data.
/// </summary>
/// <param name="name">The name of the group.</param>
public Group(string name)
@@ -31,33 +29,25 @@ namespace Jellyfin.Data.Entities
Id = Guid.NewGuid();
Permissions = new HashSet<Permission>();
- ProviderMappings = new HashSet<ProviderMapping>();
Preferences = new HashSet<Preference>();
-
- Init();
}
/// <summary>
/// Initializes a new instance of the <see cref="Group"/> class.
- /// Default constructor. Protected due to required properties, but present because EF needs it.
/// </summary>
+ /// <remarks>
+ /// Default constructor. Protected due to required properties, but present because EF needs it.
+ /// </remarks>
protected Group()
{
- Init();
}
- /*************************************************************************
- * Properties
- *************************************************************************/
-
/// <summary>
/// Gets or sets the id of this group.
/// </summary>
/// <remarks>
/// Identity, Indexed, Required.
/// </remarks>
- [Key]
- [Required]
public Guid Id { get; protected set; }
/// <summary>
@@ -71,42 +61,19 @@ namespace Jellyfin.Data.Entities
[StringLength(255)]
public string Name { get; set; }
- /// <summary>
- /// Gets or sets the row version.
- /// </summary>
- /// <remarks>
- /// Required, Concurrency Token.
- /// </remarks>
+ /// <inheritdoc />
[ConcurrencyCheck]
- [Required]
public uint RowVersion { get; set; }
- public void OnSavingChanges()
- {
- RowVersion++;
- }
-
- /*************************************************************************
- * Navigation properties
- *************************************************************************/
-
- [ForeignKey("Permission_GroupPermissions_Id")]
+ /// <summary>
+ /// Gets or sets a collection containing the group's permissions.
+ /// </summary>
public virtual ICollection<Permission> Permissions { get; protected set; }
- [ForeignKey("ProviderMapping_ProviderMappings_Id")]
- public virtual ICollection<ProviderMapping> ProviderMappings { get; protected set; }
-
- [ForeignKey("Preference_Preferences_Id")]
- public virtual ICollection<Preference> Preferences { get; protected set; }
-
/// <summary>
- /// Static create function (for use in LINQ queries, etc.)
+ /// Gets or sets a collection containing the group's preferences.
/// </summary>
- /// <param name="name">The name of this group.</param>
- public static Group Create(string name)
- {
- return new Group(name);
- }
+ public virtual ICollection<Preference> Preferences { get; protected set; }
/// <inheritdoc/>
public bool HasPermission(PermissionKind kind)
@@ -120,6 +87,10 @@ namespace Jellyfin.Data.Entities
Permissions.First(p => p.Kind == kind).Value = value;
}
- partial void Init();
+ /// <inheritdoc />
+ public void OnSavingChanges()
+ {
+ RowVersion++;
+ }
}
}
diff --git a/Jellyfin.Data/Entities/ImageInfo.cs b/Jellyfin.Data/Entities/ImageInfo.cs
index cf0895ad4..ab8452e62 100644
--- a/Jellyfin.Data/Entities/ImageInfo.cs
+++ b/Jellyfin.Data/Entities/ImageInfo.cs
@@ -1,32 +1,65 @@
-#pragma warning disable CS1591
-
-using System;
+using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace Jellyfin.Data.Entities
{
+ /// <summary>
+ /// An entity representing an image.
+ /// </summary>
public class ImageInfo
{
+ /// <summary>
+ /// Initializes a new instance of the <see cref="ImageInfo"/> class.
+ /// </summary>
+ /// <param name="path">The path.</param>
public ImageInfo(string path)
{
Path = path;
LastModified = DateTime.UtcNow;
}
- [Key]
- [Required]
+ /// <summary>
+ /// Initializes a new instance of the <see cref="ImageInfo"/> class.
+ /// </summary>
+ /// <remarks>
+ /// Default constructor. Protected due to required properties, but present because EF needs it.
+ /// </remarks>
+ protected ImageInfo()
+ {
+ }
+
+ /// <summary>
+ /// Gets or sets the id.
+ /// </summary>
+ /// <remarks>
+ /// Identity, Indexed, Required.
+ /// </remarks>
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; protected set; }
+ /// <summary>
+ /// Gets or sets the user id.
+ /// </summary>
public Guid? UserId { get; protected set; }
+ /// <summary>
+ /// Gets or sets the path of the image.
+ /// </summary>
+ /// <remarks>
+ /// Required.
+ /// </remarks>
[Required]
[MaxLength(512)]
[StringLength(512)]
public string Path { get; set; }
- [Required]
+ /// <summary>
+ /// Gets or sets the date last modified.
+ /// </summary>
+ /// <remarks>
+ /// Required.
+ /// </remarks>
public DateTime LastModified { get; set; }
}
}
diff --git a/Jellyfin.Data/Entities/ItemDisplayPreferences.cs b/Jellyfin.Data/Entities/ItemDisplayPreferences.cs
index 023cdc740..d81e4a31c 100644
--- a/Jellyfin.Data/Entities/ItemDisplayPreferences.cs
+++ b/Jellyfin.Data/Entities/ItemDisplayPreferences.cs
@@ -1,12 +1,13 @@
-#pragma warning disable CS1591
-
-using System;
+using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using Jellyfin.Data.Enums;
namespace Jellyfin.Data.Entities
{
+ /// <summary>
+ /// An entity that represents a user's display preferences for a specific item.
+ /// </summary>
public class ItemDisplayPreferences
{
/// <summary>
diff --git a/Jellyfin.Data/Entities/Libraries/Artwork.cs b/Jellyfin.Data/Entities/Libraries/Artwork.cs
index 7be22af25..06cd33330 100644
--- a/Jellyfin.Data/Entities/Libraries/Artwork.cs
+++ b/Jellyfin.Data/Entities/Libraries/Artwork.cs
@@ -1,3 +1,5 @@
+#pragma warning disable CA2227
+
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
diff --git a/Jellyfin.Data/Entities/Libraries/Book.cs b/Jellyfin.Data/Entities/Libraries/Book.cs
index 8337788dd..2e63f75bd 100644
--- a/Jellyfin.Data/Entities/Libraries/Book.cs
+++ b/Jellyfin.Data/Entities/Libraries/Book.cs
@@ -1,3 +1,5 @@
+#pragma warning disable CA2227
+
using System.Collections.Generic;
using Jellyfin.Data.Interfaces;
diff --git a/Jellyfin.Data/Entities/Libraries/BookMetadata.cs b/Jellyfin.Data/Entities/Libraries/BookMetadata.cs
index bd716712b..4a3d290f0 100644
--- a/Jellyfin.Data/Entities/Libraries/BookMetadata.cs
+++ b/Jellyfin.Data/Entities/Libraries/BookMetadata.cs
@@ -1,3 +1,5 @@
+#pragma warning disable CA2227
+
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
@@ -8,7 +10,7 @@ namespace Jellyfin.Data.Entities.Libraries
/// <summary>
/// An entity containing metadata for a book.
/// </summary>
- public class BookMetadata : Metadata, IHasCompanies
+ public class BookMetadata : ItemMetadata, IHasCompanies
{
/// <summary>
/// Initializes a new instance of the <see cref="BookMetadata"/> class.
diff --git a/Jellyfin.Data/Entities/Libraries/Chapter.cs b/Jellyfin.Data/Entities/Libraries/Chapter.cs
index d9293c3cc..f503de379 100644
--- a/Jellyfin.Data/Entities/Libraries/Chapter.cs
+++ b/Jellyfin.Data/Entities/Libraries/Chapter.cs
@@ -1,3 +1,5 @@
+#pragma warning disable CA2227
+
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
diff --git a/Jellyfin.Data/Entities/Libraries/Collection.cs b/Jellyfin.Data/Entities/Libraries/Collection.cs
index 2e1bbcfb6..39eded752 100644
--- a/Jellyfin.Data/Entities/Libraries/Collection.cs
+++ b/Jellyfin.Data/Entities/Libraries/Collection.cs
@@ -1,3 +1,5 @@
+#pragma warning disable CA2227
+
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
diff --git a/Jellyfin.Data/Entities/Libraries/CollectionItem.cs b/Jellyfin.Data/Entities/Libraries/CollectionItem.cs
index c9306f630..4467c9bbd 100644
--- a/Jellyfin.Data/Entities/Libraries/CollectionItem.cs
+++ b/Jellyfin.Data/Entities/Libraries/CollectionItem.cs
@@ -73,7 +73,7 @@ namespace Jellyfin.Data.Entities.Libraries
/// Gets or sets the next item in the collection.
/// </summary>
/// <remarks>
- /// TODO check if this properly updated dependant and has the proper principal relationship
+ /// TODO check if this properly updated dependant and has the proper principal relationship.
/// </remarks>
public virtual CollectionItem Next { get; set; }
@@ -81,7 +81,7 @@ namespace Jellyfin.Data.Entities.Libraries
/// Gets or sets the previous item in the collection.
/// </summary>
/// <remarks>
- /// TODO check if this properly updated dependant and has the proper principal relationship
+ /// TODO check if this properly updated dependant and has the proper principal relationship.
/// </remarks>
public virtual CollectionItem Previous { get; set; }
diff --git a/Jellyfin.Data/Entities/Libraries/Company.cs b/Jellyfin.Data/Entities/Libraries/Company.cs
index 02da26bc2..3b6ed3309 100644
--- a/Jellyfin.Data/Entities/Libraries/Company.cs
+++ b/Jellyfin.Data/Entities/Libraries/Company.cs
@@ -1,3 +1,5 @@
+#pragma warning disable CA2227
+
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
diff --git a/Jellyfin.Data/Entities/Libraries/CompanyMetadata.cs b/Jellyfin.Data/Entities/Libraries/CompanyMetadata.cs
index 60cc96a34..8aa0486af 100644
--- a/Jellyfin.Data/Entities/Libraries/CompanyMetadata.cs
+++ b/Jellyfin.Data/Entities/Libraries/CompanyMetadata.cs
@@ -6,7 +6,7 @@ namespace Jellyfin.Data.Entities.Libraries
/// <summary>
/// An entity holding metadata for a <see cref="Company"/>.
/// </summary>
- public class CompanyMetadata : Metadata
+ public class CompanyMetadata : ItemMetadata
{
/// <summary>
/// Initializes a new instance of the <see cref="CompanyMetadata"/> class.
diff --git a/Jellyfin.Data/Entities/Libraries/CustomItem.cs b/Jellyfin.Data/Entities/Libraries/CustomItem.cs
index 6a4f0a537..115489c78 100644
--- a/Jellyfin.Data/Entities/Libraries/CustomItem.cs
+++ b/Jellyfin.Data/Entities/Libraries/CustomItem.cs
@@ -1,3 +1,5 @@
+#pragma warning disable CA2227
+
using System.Collections.Generic;
using Jellyfin.Data.Interfaces;
diff --git a/Jellyfin.Data/Entities/Libraries/CustomItemMetadata.cs b/Jellyfin.Data/Entities/Libraries/CustomItemMetadata.cs
index bc1835528..f0daedfbe 100644
--- a/Jellyfin.Data/Entities/Libraries/CustomItemMetadata.cs
+++ b/Jellyfin.Data/Entities/Libraries/CustomItemMetadata.cs
@@ -5,7 +5,7 @@ namespace Jellyfin.Data.Entities.Libraries
/// <summary>
/// An entity containing metadata for a custom item.
/// </summary>
- public class CustomItemMetadata : Metadata
+ public class CustomItemMetadata : ItemMetadata
{
/// <summary>
/// Initializes a new instance of the <see cref="CustomItemMetadata"/> class.
diff --git a/Jellyfin.Data/Entities/Libraries/Episode.cs b/Jellyfin.Data/Entities/Libraries/Episode.cs
index 430a11e3c..0bdc2d764 100644
--- a/Jellyfin.Data/Entities/Libraries/Episode.cs
+++ b/Jellyfin.Data/Entities/Libraries/Episode.cs
@@ -1,3 +1,5 @@
+#pragma warning disable CA2227
+
using System;
using System.Collections.Generic;
using Jellyfin.Data.Interfaces;
diff --git a/Jellyfin.Data/Entities/Libraries/EpisodeMetadata.cs b/Jellyfin.Data/Entities/Libraries/EpisodeMetadata.cs
index 348100cb4..7efb840f0 100644
--- a/Jellyfin.Data/Entities/Libraries/EpisodeMetadata.cs
+++ b/Jellyfin.Data/Entities/Libraries/EpisodeMetadata.cs
@@ -6,7 +6,7 @@ namespace Jellyfin.Data.Entities.Libraries
/// <summary>
/// An entity containing metadata for an <see cref="Episode"/>.
/// </summary>
- public class EpisodeMetadata : Metadata
+ public class EpisodeMetadata : ItemMetadata
{
/// <summary>
/// Initializes a new instance of the <see cref="EpisodeMetadata"/> class.
diff --git a/Jellyfin.Data/Entities/Libraries/Genre.cs b/Jellyfin.Data/Entities/Libraries/Genre.cs
index aeedd7bfd..2a2dbd1a5 100644
--- a/Jellyfin.Data/Entities/Libraries/Genre.cs
+++ b/Jellyfin.Data/Entities/Libraries/Genre.cs
@@ -14,8 +14,8 @@ namespace Jellyfin.Data.Entities.Libraries
/// Initializes a new instance of the <see cref="Genre"/> class.
/// </summary>
/// <param name="name">The name.</param>
- /// <param name="metadata">The metadata.</param>
- public Genre(string name, Metadata metadata)
+ /// <param name="itemMetadata">The metadata.</param>
+ public Genre(string name, ItemMetadata itemMetadata)
{
if (string.IsNullOrEmpty(name))
{
@@ -24,12 +24,12 @@ namespace Jellyfin.Data.Entities.Libraries
Name = name;
- if (metadata == null)
+ if (itemMetadata == null)
{
- throw new ArgumentNullException(nameof(metadata));
+ throw new ArgumentNullException(nameof(itemMetadata));
}
- metadata.Genres.Add(this);
+ itemMetadata.Genres.Add(this);
}
/// <summary>
diff --git a/Jellyfin.Data/Entities/Libraries/Metadata.cs b/Jellyfin.Data/Entities/Libraries/ItemMetadata.cs
index 877bb5fbd..1d2dc0f66 100644
--- a/Jellyfin.Data/Entities/Libraries/Metadata.cs
+++ b/Jellyfin.Data/Entities/Libraries/ItemMetadata.cs
@@ -1,3 +1,5 @@
+#pragma warning disable CA2227
+
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
@@ -9,14 +11,14 @@ namespace Jellyfin.Data.Entities.Libraries
/// <summary>
/// An abstract class that holds metadata.
/// </summary>
- public abstract class Metadata : IHasArtwork, IHasConcurrencyToken
+ public abstract class ItemMetadata : IHasArtwork, IHasConcurrencyToken
{
/// <summary>
- /// Initializes a new instance of the <see cref="Metadata"/> class.
+ /// Initializes a new instance of the <see cref="ItemMetadata"/> class.
/// </summary>
/// <param name="title">The title or name of the object.</param>
/// <param name="language">ISO-639-3 3-character language codes.</param>
- protected Metadata(string title, string language)
+ protected ItemMetadata(string title, string language)
{
if (string.IsNullOrEmpty(title))
{
@@ -41,12 +43,12 @@ namespace Jellyfin.Data.Entities.Libraries
}
/// <summary>
- /// Initializes a new instance of the <see cref="Metadata"/> class.
+ /// Initializes a new instance of the <see cref="ItemMetadata"/> class.
/// </summary>
/// <remarks>
/// Default constructor. Protected due to being abstract.
/// </remarks>
- protected Metadata()
+ protected ItemMetadata()
{
}
diff --git a/Jellyfin.Data/Entities/Libraries/MediaFile.cs b/Jellyfin.Data/Entities/Libraries/MediaFile.cs
index 8bc649c98..9924d5728 100644
--- a/Jellyfin.Data/Entities/Libraries/MediaFile.cs
+++ b/Jellyfin.Data/Entities/Libraries/MediaFile.cs
@@ -1,3 +1,5 @@
+#pragma warning disable CA2227
+
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
diff --git a/Jellyfin.Data/Entities/Libraries/MetadataProviderId.cs b/Jellyfin.Data/Entities/Libraries/MetadataProviderId.cs
index 6e6de598e..fcfb35bfa 100644
--- a/Jellyfin.Data/Entities/Libraries/MetadataProviderId.cs
+++ b/Jellyfin.Data/Entities/Libraries/MetadataProviderId.cs
@@ -14,8 +14,8 @@ namespace Jellyfin.Data.Entities.Libraries
/// Initializes a new instance of the <see cref="MetadataProviderId"/> class.
/// </summary>
/// <param name="providerId">The provider id.</param>
- /// <param name="metadata">The metadata entity.</param>
- public MetadataProviderId(string providerId, Metadata metadata)
+ /// <param name="itemMetadata">The metadata entity.</param>
+ public MetadataProviderId(string providerId, ItemMetadata itemMetadata)
{
if (string.IsNullOrEmpty(providerId))
{
@@ -24,12 +24,12 @@ namespace Jellyfin.Data.Entities.Libraries
ProviderId = providerId;
- if (metadata == null)
+ if (itemMetadata == null)
{
- throw new ArgumentNullException(nameof(metadata));
+ throw new ArgumentNullException(nameof(itemMetadata));
}
- metadata.Sources.Add(this);
+ itemMetadata.Sources.Add(this);
}
/// <summary>
diff --git a/Jellyfin.Data/Entities/Libraries/Movie.cs b/Jellyfin.Data/Entities/Libraries/Movie.cs
index 0a8cc83dd..08db904fa 100644
--- a/Jellyfin.Data/Entities/Libraries/Movie.cs
+++ b/Jellyfin.Data/Entities/Libraries/Movie.cs
@@ -1,3 +1,5 @@
+#pragma warning disable CA2227
+
using System.Collections.Generic;
using Jellyfin.Data.Interfaces;
diff --git a/Jellyfin.Data/Entities/Libraries/MovieMetadata.cs b/Jellyfin.Data/Entities/Libraries/MovieMetadata.cs
index 31102bf13..aa1501a5c 100644
--- a/Jellyfin.Data/Entities/Libraries/MovieMetadata.cs
+++ b/Jellyfin.Data/Entities/Libraries/MovieMetadata.cs
@@ -1,3 +1,5 @@
+#pragma warning disable CA2227
+
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
@@ -8,7 +10,7 @@ namespace Jellyfin.Data.Entities.Libraries
/// <summary>
/// An entity holding the metadata for a movie.
/// </summary>
- public class MovieMetadata : Metadata, IHasCompanies
+ public class MovieMetadata : ItemMetadata, IHasCompanies
{
/// <summary>
/// Initializes a new instance of the <see cref="MovieMetadata"/> class.
diff --git a/Jellyfin.Data/Entities/Libraries/MusicAlbum.cs b/Jellyfin.Data/Entities/Libraries/MusicAlbum.cs
index 2ed1f78c5..06aff6f45 100644
--- a/Jellyfin.Data/Entities/Libraries/MusicAlbum.cs
+++ b/Jellyfin.Data/Entities/Libraries/MusicAlbum.cs
@@ -1,3 +1,5 @@
+#pragma warning disable CA2227
+
using System.Collections.Generic;
namespace Jellyfin.Data.Entities.Libraries
diff --git a/Jellyfin.Data/Entities/Libraries/MusicAlbumMetadata.cs b/Jellyfin.Data/Entities/Libraries/MusicAlbumMetadata.cs
index cc5919bfe..05c0b0374 100644
--- a/Jellyfin.Data/Entities/Libraries/MusicAlbumMetadata.cs
+++ b/Jellyfin.Data/Entities/Libraries/MusicAlbumMetadata.cs
@@ -1,3 +1,5 @@
+#pragma warning disable CA2227
+
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
@@ -6,7 +8,7 @@ namespace Jellyfin.Data.Entities.Libraries
/// <summary>
/// An entity holding the metadata for a music album.
/// </summary>
- public class MusicAlbumMetadata : Metadata
+ public class MusicAlbumMetadata : ItemMetadata
{
/// <summary>
/// Initializes a new instance of the <see cref="MusicAlbumMetadata"/> class.
diff --git a/Jellyfin.Data/Entities/Libraries/Person.cs b/Jellyfin.Data/Entities/Libraries/Person.cs
index 8beb3dd08..af4c87b73 100644
--- a/Jellyfin.Data/Entities/Libraries/Person.cs
+++ b/Jellyfin.Data/Entities/Libraries/Person.cs
@@ -1,3 +1,5 @@
+#pragma warning disable CA2227
+
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
diff --git a/Jellyfin.Data/Entities/Libraries/PersonRole.cs b/Jellyfin.Data/Entities/Libraries/PersonRole.cs
index 5290228d6..cd38ee83d 100644
--- a/Jellyfin.Data/Entities/Libraries/PersonRole.cs
+++ b/Jellyfin.Data/Entities/Libraries/PersonRole.cs
@@ -1,3 +1,5 @@
+#pragma warning disable CA2227
+
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
@@ -16,17 +18,17 @@ namespace Jellyfin.Data.Entities.Libraries
/// Initializes a new instance of the <see cref="PersonRole"/> class.
/// </summary>
/// <param name="type">The role type.</param>
- /// <param name="metadata">The metadata.</param>
- public PersonRole(PersonRoleType type, Metadata metadata)
+ /// <param name="itemMetadata">The metadata.</param>
+ public PersonRole(PersonRoleType type, ItemMetadata itemMetadata)
{
Type = type;
- if (metadata == null)
+ if (itemMetadata == null)
{
- throw new ArgumentNullException(nameof(metadata));
+ throw new ArgumentNullException(nameof(itemMetadata));
}
- metadata.PersonRoles.Add(this);
+ itemMetadata.PersonRoles.Add(this);
Sources = new HashSet<MetadataProviderId>();
}
diff --git a/Jellyfin.Data/Entities/Libraries/Photo.cs b/Jellyfin.Data/Entities/Libraries/Photo.cs
index 44338a4ce..25562ec96 100644
--- a/Jellyfin.Data/Entities/Libraries/Photo.cs
+++ b/Jellyfin.Data/Entities/Libraries/Photo.cs
@@ -1,3 +1,5 @@
+#pragma warning disable CA2227
+
using System.Collections.Generic;
using Jellyfin.Data.Interfaces;
diff --git a/Jellyfin.Data/Entities/Libraries/PhotoMetadata.cs b/Jellyfin.Data/Entities/Libraries/PhotoMetadata.cs
index 1ef9dd5f9..ffc790b57 100644
--- a/Jellyfin.Data/Entities/Libraries/PhotoMetadata.cs
+++ b/Jellyfin.Data/Entities/Libraries/PhotoMetadata.cs
@@ -5,7 +5,7 @@ namespace Jellyfin.Data.Entities.Libraries
/// <summary>
/// An entity that holds metadata for a photo.
/// </summary>
- public class PhotoMetadata : Metadata
+ public class PhotoMetadata : ItemMetadata
{
/// <summary>
/// Initializes a new instance of the <see cref="PhotoMetadata"/> class.
diff --git a/Jellyfin.Data/Entities/Libraries/Rating.cs b/Jellyfin.Data/Entities/Libraries/Rating.cs
index ba054a39e..98226cd80 100644
--- a/Jellyfin.Data/Entities/Libraries/Rating.cs
+++ b/Jellyfin.Data/Entities/Libraries/Rating.cs
@@ -14,17 +14,17 @@ namespace Jellyfin.Data.Entities.Libraries
/// Initializes a new instance of the <see cref="Rating"/> class.
/// </summary>
/// <param name="value">The value.</param>
- /// <param name="metadata">The metadata.</param>
- public Rating(double value, Metadata metadata)
+ /// <param name="itemMetadata">The metadata.</param>
+ public Rating(double value, ItemMetadata itemMetadata)
{
Value = value;
- if (metadata == null)
+ if (itemMetadata == null)
{
- throw new ArgumentNullException(nameof(metadata));
+ throw new ArgumentNullException(nameof(itemMetadata));
}
- metadata.Ratings.Add(this);
+ itemMetadata.Ratings.Add(this);
}
/// <summary>
diff --git a/Jellyfin.Data/Entities/Libraries/Release.cs b/Jellyfin.Data/Entities/Libraries/Release.cs
index 43c7080d7..b633e08fb 100644
--- a/Jellyfin.Data/Entities/Libraries/Release.cs
+++ b/Jellyfin.Data/Entities/Libraries/Release.cs
@@ -1,3 +1,5 @@
+#pragma warning disable CA2227
+
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
diff --git a/Jellyfin.Data/Entities/Libraries/Season.cs b/Jellyfin.Data/Entities/Libraries/Season.cs
index eef788bad..eb6674dbc 100644
--- a/Jellyfin.Data/Entities/Libraries/Season.cs
+++ b/Jellyfin.Data/Entities/Libraries/Season.cs
@@ -1,3 +1,5 @@
+#pragma warning disable CA2227
+
using System;
using System.Collections.Generic;
diff --git a/Jellyfin.Data/Entities/Libraries/SeasonMetadata.cs b/Jellyfin.Data/Entities/Libraries/SeasonMetadata.cs
index eedeb089e..7ce79756b 100644
--- a/Jellyfin.Data/Entities/Libraries/SeasonMetadata.cs
+++ b/Jellyfin.Data/Entities/Libraries/SeasonMetadata.cs
@@ -6,7 +6,7 @@ namespace Jellyfin.Data.Entities.Libraries
/// <summary>
/// An entity that holds metadata for seasons.
/// </summary>
- public class SeasonMetadata : Metadata
+ public class SeasonMetadata : ItemMetadata
{
/// <summary>
/// Initializes a new instance of the <see cref="SeasonMetadata"/> class.
diff --git a/Jellyfin.Data/Entities/Libraries/Series.cs b/Jellyfin.Data/Entities/Libraries/Series.cs
index e959c1fe0..8c8317d14 100644
--- a/Jellyfin.Data/Entities/Libraries/Series.cs
+++ b/Jellyfin.Data/Entities/Libraries/Series.cs
@@ -1,3 +1,5 @@
+#pragma warning disable CA2227
+
using System;
using System.Collections.Generic;
diff --git a/Jellyfin.Data/Entities/Libraries/SeriesMetadata.cs b/Jellyfin.Data/Entities/Libraries/SeriesMetadata.cs
index 898f3006d..877dbfc69 100644
--- a/Jellyfin.Data/Entities/Libraries/SeriesMetadata.cs
+++ b/Jellyfin.Data/Entities/Libraries/SeriesMetadata.cs
@@ -1,3 +1,5 @@
+#pragma warning disable CA2227
+
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
@@ -9,7 +11,7 @@ namespace Jellyfin.Data.Entities.Libraries
/// <summary>
/// An entity representing series metadata.
/// </summary>
- public class SeriesMetadata : Metadata, IHasCompanies
+ public class SeriesMetadata : ItemMetadata, IHasCompanies
{
/// <summary>
/// Initializes a new instance of the <see cref="SeriesMetadata"/> class.
diff --git a/Jellyfin.Data/Entities/Libraries/Track.cs b/Jellyfin.Data/Entities/Libraries/Track.cs
index 09ce82a9b..782bfb5ce 100644
--- a/Jellyfin.Data/Entities/Libraries/Track.cs
+++ b/Jellyfin.Data/Entities/Libraries/Track.cs
@@ -1,3 +1,5 @@
+#pragma warning disable CA2227
+
using System;
using System.Collections.Generic;
using Jellyfin.Data.Interfaces;
diff --git a/Jellyfin.Data/Entities/Libraries/TrackMetadata.cs b/Jellyfin.Data/Entities/Libraries/TrackMetadata.cs
index 048068a1a..321f93bf2 100644
--- a/Jellyfin.Data/Entities/Libraries/TrackMetadata.cs
+++ b/Jellyfin.Data/Entities/Libraries/TrackMetadata.cs
@@ -5,7 +5,7 @@ namespace Jellyfin.Data.Entities.Libraries
/// <summary>
/// An entity holding metadata for a track.
/// </summary>
- public class TrackMetadata : Metadata
+ public class TrackMetadata : ItemMetadata
{
/// <summary>
/// Initializes a new instance of the <see cref="TrackMetadata"/> class.
diff --git a/Jellyfin.Data/Entities/Permission.cs b/Jellyfin.Data/Entities/Permission.cs
index c0f67f836..d92e5d9d2 100644
--- a/Jellyfin.Data/Entities/Permission.cs
+++ b/Jellyfin.Data/Entities/Permission.cs
@@ -1,5 +1,3 @@
-#pragma warning disable CS1591
-
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using Jellyfin.Data.Enums;
@@ -10,7 +8,7 @@ namespace Jellyfin.Data.Entities
/// <summary>
/// An entity representing whether the associated user has a specific permission.
/// </summary>
- public partial class Permission : IHasConcurrencyToken
+ public class Permission : IHasConcurrencyToken
{
/// <summary>
/// Initializes a new instance of the <see cref="Permission"/> class.
@@ -22,8 +20,6 @@ namespace Jellyfin.Data.Entities
{
Kind = kind;
Value = value;
-
- Init();
}
/// <summary>
@@ -32,21 +28,14 @@ namespace Jellyfin.Data.Entities
/// </summary>
protected Permission()
{
- Init();
}
- /*************************************************************************
- * Properties
- *************************************************************************/
-
/// <summary>
/// Gets or sets the id of this permission.
/// </summary>
/// <remarks>
/// Identity, Indexed, Required.
/// </remarks>
- [Key]
- [Required]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; protected set; }
@@ -56,7 +45,6 @@ namespace Jellyfin.Data.Entities
/// <remarks>
/// Required.
/// </remarks>
- [Required]
public PermissionKind Kind { get; protected set; }
/// <summary>
@@ -65,36 +53,16 @@ namespace Jellyfin.Data.Entities
/// <remarks>
/// Required.
/// </remarks>
- [Required]
public bool Value { get; set; }
- /// <summary>
- /// Gets or sets the row version.
- /// </summary>
- /// <remarks>
- /// Required, ConcurrencyToken.
- /// </remarks>
+ /// <inheritdoc />
[ConcurrencyCheck]
- [Required]
public uint RowVersion { get; set; }
- /// <summary>
- /// Static create function (for use in LINQ queries, etc.)
- /// </summary>
- /// <param name="kind">The permission kind.</param>
- /// <param name="value">The value of this permission.</param>
- /// <returns>The newly created instance.</returns>
- public static Permission Create(PermissionKind kind, bool value)
- {
- return new Permission(kind, value);
- }
-
/// <inheritdoc/>
public void OnSavingChanges()
{
RowVersion++;
}
-
- partial void Init();
}
}
diff --git a/Jellyfin.Data/Entities/Preference.cs b/Jellyfin.Data/Entities/Preference.cs
index 1797f0a40..4efddf2a4 100644
--- a/Jellyfin.Data/Entities/Preference.cs
+++ b/Jellyfin.Data/Entities/Preference.cs
@@ -31,18 +31,12 @@ namespace Jellyfin.Data.Entities
{
}
- /*************************************************************************
- * Properties
- *************************************************************************/
-
/// <summary>
/// Gets or sets the id of this preference.
/// </summary>
/// <remarks>
/// Identity, Indexed, Required.
/// </remarks>
- [Key]
- [Required]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; protected set; }
@@ -52,7 +46,6 @@ namespace Jellyfin.Data.Entities
/// <remarks>
/// Required.
/// </remarks>
- [Required]
public PreferenceKind Kind { get; protected set; }
/// <summary>
@@ -66,27 +59,10 @@ namespace Jellyfin.Data.Entities
[StringLength(65535)]
public string Value { get; set; }
- /// <summary>
- /// Gets or sets the row version.
- /// </summary>
- /// <remarks>
- /// Required, ConcurrencyToken.
- /// </remarks>
+ /// <inheritdoc/>
[ConcurrencyCheck]
- [Required]
public uint RowVersion { get; set; }
- /// <summary>
- /// Static create function (for use in LINQ queries, etc.)
- /// </summary>
- /// <param name="kind">The preference kind.</param>
- /// <param name="value">The value.</param>
- /// <returns>The new instance.</returns>
- public static Preference Create(PreferenceKind kind, string value)
- {
- return new Preference(kind, value);
- }
-
/// <inheritdoc/>
public void OnSavingChanges()
{
diff --git a/Jellyfin.Data/Entities/ProviderMapping.cs b/Jellyfin.Data/Entities/ProviderMapping.cs
deleted file mode 100644
index 44ebfba76..000000000
--- a/Jellyfin.Data/Entities/ProviderMapping.cs
+++ /dev/null
@@ -1,129 +0,0 @@
-#pragma warning disable CS1591
-
-using System;
-using System.ComponentModel.DataAnnotations;
-using System.ComponentModel.DataAnnotations.Schema;
-
-namespace Jellyfin.Data.Entities
-{
- public partial class ProviderMapping
- {
- partial void Init();
-
- /// <summary>
- /// Default constructor. Protected due to required properties, but present because EF needs it.
- /// </summary>
- protected ProviderMapping()
- {
- Init();
- }
-
- /// <summary>
- /// Replaces default constructor, since it's protected. Caller assumes responsibility for setting all required values before saving.
- /// </summary>
- public static ProviderMapping CreateProviderMappingUnsafe()
- {
- return new ProviderMapping();
- }
-
- /// <summary>
- /// Public constructor with required data.
- /// </summary>
- /// <param name="providername"></param>
- /// <param name="providersecrets"></param>
- /// <param name="providerdata"></param>
- /// <param name="_user0"></param>
- /// <param name="_group1"></param>
- public ProviderMapping(string providername, string providersecrets, string providerdata, User _user0, Group _group1)
- {
- if (string.IsNullOrEmpty(providername))
- {
- throw new ArgumentNullException(nameof(providername));
- }
-
- this.ProviderName = providername;
-
- if (string.IsNullOrEmpty(providersecrets))
- {
- throw new ArgumentNullException(nameof(providersecrets));
- }
-
- this.ProviderSecrets = providersecrets;
-
- if (string.IsNullOrEmpty(providerdata))
- {
- throw new ArgumentNullException(nameof(providerdata));
- }
-
- this.ProviderData = providerdata;
-
- Init();
- }
-
- /// <summary>
- /// Static create function (for use in LINQ queries, etc.)
- /// </summary>
- /// <param name="providername"></param>
- /// <param name="providersecrets"></param>
- /// <param name="providerdata"></param>
- /// <param name="_user0"></param>
- /// <param name="_group1"></param>
- public static ProviderMapping Create(string providername, string providersecrets, string providerdata, User _user0, Group _group1)
- {
- return new ProviderMapping(providername, providersecrets, providerdata, _user0, _group1);
- }
-
- /*************************************************************************
- * Properties
- *************************************************************************/
-
- /// <summary>
- /// Identity, Indexed, Required.
- /// </summary>
- [Key]
- [Required]
- [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
- public int Id { get; protected set; }
-
- /// <summary>
- /// Required, Max length = 255
- /// </summary>
- [Required]
- [MaxLength(255)]
- [StringLength(255)]
- public string ProviderName { get; set; }
-
- /// <summary>
- /// Required, Max length = 65535
- /// </summary>
- [Required]
- [MaxLength(65535)]
- [StringLength(65535)]
- public string ProviderSecrets { get; set; }
-
- /// <summary>
- /// Required, Max length = 65535
- /// </summary>
- [Required]
- [MaxLength(65535)]
- [StringLength(65535)]
- public string ProviderData { get; set; }
-
- /// <summary>
- /// Required, ConcurrenyToken.
- /// </summary>
- [ConcurrencyCheck]
- [Required]
- public uint RowVersion { get; set; }
-
- public void OnSavingChanges()
- {
- RowVersion++;
- }
-
- /*************************************************************************
- * Navigation properties
- *************************************************************************/
- }
-}
-
diff --git a/Jellyfin.Data/Entities/User.cs b/Jellyfin.Data/Entities/User.cs
index 7ea1f4498..f7ab57a1b 100644
--- a/Jellyfin.Data/Entities/User.cs
+++ b/Jellyfin.Data/Entities/User.cs
@@ -1,4 +1,4 @@
-#pragma warning disable CS1591
+#pragma warning disable CA2227
using System;
using System.Collections.Generic;
@@ -15,7 +15,7 @@ namespace Jellyfin.Data.Entities
/// <summary>
/// An entity representing a user.
/// </summary>
- public partial class User : IHasPermissions, IHasConcurrencyToken
+ public class User : IHasPermissions, IHasConcurrencyToken
{
/// <summary>
/// The values being delimited here are Guids, so commas work as they do not appear in Guids.
@@ -75,7 +75,6 @@ namespace Jellyfin.Data.Entities
AddDefaultPermissions();
AddDefaultPreferences();
- Init();
}
/// <summary>
@@ -84,21 +83,14 @@ namespace Jellyfin.Data.Entities
/// </summary>
protected User()
{
- Init();
}
- /*************************************************************************
- * Properties
- *************************************************************************/
-
/// <summary>
/// Gets or sets the Id of the user.
/// </summary>
/// <remarks>
/// Identity, Indexed, Required.
/// </remarks>
- [Key]
- [Required]
[JsonIgnore]
public Guid Id { get; set; }
@@ -139,7 +131,6 @@ namespace Jellyfin.Data.Entities
/// <remarks>
/// Required.
/// </remarks>
- [Required]
public bool MustUpdatePassword { get; set; }
/// <summary>
@@ -180,7 +171,6 @@ namespace Jellyfin.Data.Entities
/// <remarks>
/// Required.
/// </remarks>
- [Required]
public int InvalidLoginAttemptCount { get; set; }
/// <summary>
@@ -204,7 +194,6 @@ namespace Jellyfin.Data.Entities
/// <remarks>
/// Required.
/// </remarks>
- [Required]
public SubtitlePlaybackMode SubtitleMode { get; set; }
/// <summary>
@@ -213,7 +202,6 @@ namespace Jellyfin.Data.Entities
/// <remarks>
/// Required.
/// </remarks>
- [Required]
public bool PlayDefaultAudioTrack { get; set; }
/// <summary>
@@ -232,7 +220,6 @@ namespace Jellyfin.Data.Entities
/// <remarks>
/// Required.
/// </remarks>
- [Required]
public bool DisplayMissingEpisodes { get; set; }
/// <summary>
@@ -241,7 +228,6 @@ namespace Jellyfin.Data.Entities
/// <remarks>
/// Required.
/// </remarks>
- [Required]
public bool DisplayCollectionsView { get; set; }
/// <summary>
@@ -250,7 +236,6 @@ namespace Jellyfin.Data.Entities
/// <remarks>
/// Required.
/// </remarks>
- [Required]
public bool EnableLocalPassword { get; set; }
/// <summary>
@@ -259,7 +244,6 @@ namespace Jellyfin.Data.Entities
/// <remarks>
/// Required.
/// </remarks>
- [Required]
public bool HidePlayedInLatest { get; set; }
/// <summary>
@@ -268,7 +252,6 @@ namespace Jellyfin.Data.Entities
/// <remarks>
/// Required.
/// </remarks>
- [Required]
public bool RememberAudioSelections { get; set; }
/// <summary>
@@ -277,7 +260,6 @@ namespace Jellyfin.Data.Entities
/// <remarks>
/// Required.
/// </remarks>
- [Required]
public bool RememberSubtitleSelections { get; set; }
/// <summary>
@@ -286,7 +268,6 @@ namespace Jellyfin.Data.Entities
/// <remarks>
/// Required.
/// </remarks>
- [Required]
public bool EnableNextEpisodeAutoPlay { get; set; }
/// <summary>
@@ -295,7 +276,6 @@ namespace Jellyfin.Data.Entities
/// <remarks>
/// Required.
/// </remarks>
- [Required]
public bool EnableAutoLogin { get; set; }
/// <summary>
@@ -304,7 +284,6 @@ namespace Jellyfin.Data.Entities
/// <remarks>
/// Required.
/// </remarks>
- [Required]
public bool EnableUserPreferenceAccess { get; set; }
/// <summary>
@@ -322,7 +301,6 @@ namespace Jellyfin.Data.Entities
/// This is a temporary stopgap for until the library db is migrated.
/// This corresponds to the value of the index of this user in the library db.
/// </summary>
- [Required]
public long InternalId { get; set; }
/// <summary>
@@ -340,7 +318,9 @@ namespace Jellyfin.Data.Entities
[Required]
public virtual DisplayPreferences DisplayPreferences { get; set; }
- [Required]
+ /// <summary>
+ /// Gets or sets the level of sync play permissions this user has.
+ /// </summary>
public SyncPlayAccess SyncPlayAccess { get; set; }
/// <summary>
@@ -350,13 +330,8 @@ namespace Jellyfin.Data.Entities
/// Required, Concurrency Token.
/// </remarks>
[ConcurrencyCheck]
- [Required]
public uint RowVersion { get; set; }
- /*************************************************************************
- * Navigation properties
- *************************************************************************/
-
/// <summary>
/// Gets or sets the list of access schedules this user has.
/// </summary>
@@ -395,18 +370,6 @@ namespace Jellyfin.Data.Entities
[ForeignKey("Preference_Preferences_Guid")]
public virtual ICollection<Preference> Preferences { get; protected set; }
- /// <summary>
- /// Static create function (for use in LINQ queries, etc.)
- /// </summary>
- /// <param name="username">The username for the created user.</param>
- /// <param name="authenticationProviderId">The Id of the user's authentication provider.</param>
- /// <param name="passwordResetProviderId">The Id of the user's password reset provider.</param>
- /// <returns>The created instance.</returns>
- public static User Create(string username, string authenticationProviderId, string passwordResetProviderId)
- {
- return new User(username, authenticationProviderId, passwordResetProviderId);
- }
-
/// <inheritdoc/>
public void OnSavingChanges()
{
@@ -519,7 +482,5 @@ namespace Jellyfin.Data.Entities
Preferences.Add(new Preference(val, string.Empty));
}
}
-
- partial void Init();
}
}
diff --git a/Jellyfin.Data/Enums/ArtKind.cs b/Jellyfin.Data/Enums/ArtKind.cs
index 71b4db6f2..f7a73848c 100644
--- a/Jellyfin.Data/Enums/ArtKind.cs
+++ b/Jellyfin.Data/Enums/ArtKind.cs
@@ -1,13 +1,33 @@
-#pragma warning disable CS1591
-
namespace Jellyfin.Data.Enums
{
+ /// <summary>
+ /// An enum representing types of art.
+ /// </summary>
public enum ArtKind
{
- Other,
- Poster,
- Banner,
- Thumbnail,
- Logo
+ /// <summary>
+ /// Another type of art, not covered by the other members.
+ /// </summary>
+ Other = 0,
+
+ /// <summary>
+ /// A poster.
+ /// </summary>
+ Poster = 1,
+
+ /// <summary>
+ /// A banner.
+ /// </summary>
+ Banner = 2,
+
+ /// <summary>
+ /// A thumbnail.
+ /// </summary>
+ Thumbnail = 3,
+
+ /// <summary>
+ /// A logo.
+ /// </summary>
+ Logo = 4
}
}
diff --git a/Jellyfin.Data/Enums/DynamicDayOfWeek.cs b/Jellyfin.Data/Enums/DynamicDayOfWeek.cs
index a33cd9d1c..d3d8dd822 100644
--- a/Jellyfin.Data/Enums/DynamicDayOfWeek.cs
+++ b/Jellyfin.Data/Enums/DynamicDayOfWeek.cs
@@ -1,18 +1,58 @@
-#pragma warning disable CS1591
-
namespace Jellyfin.Data.Enums
{
+ /// <summary>
+ /// An enum that represents a day of the week, weekdays, weekends, or all days.
+ /// </summary>
public enum DynamicDayOfWeek
{
+ /// <summary>
+ /// Sunday.
+ /// </summary>
Sunday = 0,
+
+ /// <summary>
+ /// Monday.
+ /// </summary>
Monday = 1,
+
+ /// <summary>
+ /// Tuesday.
+ /// </summary>
Tuesday = 2,
+
+ /// <summary>
+ /// Wednesday.
+ /// </summary>
Wednesday = 3,
+
+ /// <summary>
+ /// Thursday.
+ /// </summary>
Thursday = 4,
+
+ /// <summary>
+ /// Friday.
+ /// </summary>
Friday = 5,
+
+ /// <summary>
+ /// Saturday.
+ /// </summary>
Saturday = 6,
+
+ /// <summary>
+ /// All days of the week.
+ /// </summary>
Everyday = 7,
+
+ /// <summary>
+ /// A week day, or Monday-Friday.
+ /// </summary>
Weekday = 8,
+
+ /// <summary>
+ /// Saturday and Sunday.
+ /// </summary>
Weekend = 9
}
}
diff --git a/Jellyfin.Data/Enums/IndexingKind.cs b/Jellyfin.Data/Enums/IndexingKind.cs
index fafe47e0c..c0df07714 100644
--- a/Jellyfin.Data/Enums/IndexingKind.cs
+++ b/Jellyfin.Data/Enums/IndexingKind.cs
@@ -1,7 +1,8 @@
-#pragma warning disable CS1591
-
-namespace Jellyfin.Data.Enums
+namespace Jellyfin.Data.Enums
{
+ /// <summary>
+ /// An enum representing a type of indexing in a user's display preferences.
+ /// </summary>
public enum IndexingKind
{
/// <summary>
diff --git a/Jellyfin.Data/Enums/MediaFileKind.cs b/Jellyfin.Data/Enums/MediaFileKind.cs
index b03591fb8..797c26ec2 100644
--- a/Jellyfin.Data/Enums/MediaFileKind.cs
+++ b/Jellyfin.Data/Enums/MediaFileKind.cs
@@ -1,13 +1,33 @@
-#pragma warning disable CS1591
-
namespace Jellyfin.Data.Enums
{
+ /// <summary>
+ /// An enum representing the type of media file.
+ /// </summary>
public enum MediaFileKind
{
- Main,
- Sidecar,
- AdditionalPart,
- AlternativeFormat,
- AdditionalStream
+ /// <summary>
+ /// The main file.
+ /// </summary>
+ Main = 0,
+
+ /// <summary>
+ /// A sidecar file.
+ /// </summary>
+ Sidecar = 1,
+
+ /// <summary>
+ /// An additional part to the main file.
+ /// </summary>
+ AdditionalPart = 2,
+
+ /// <summary>
+ /// An alternative format to the main file.
+ /// </summary>
+ AlternativeFormat = 3,
+
+ /// <summary>
+ /// An additional stream for the main file.
+ /// </summary>
+ AdditionalStream = 4
}
}
diff --git a/Jellyfin.Data/Enums/PersonRoleType.cs b/Jellyfin.Data/Enums/PersonRoleType.cs
index 2d80eaa4c..1e619f5ee 100644
--- a/Jellyfin.Data/Enums/PersonRoleType.cs
+++ b/Jellyfin.Data/Enums/PersonRoleType.cs
@@ -1,20 +1,68 @@
-#pragma warning disable CS1591
-
namespace Jellyfin.Data.Enums
{
+ /// <summary>
+ /// An enum representing a person's role in a specific media item.
+ /// </summary>
public enum PersonRoleType
{
- Other,
- Director,
- Artist,
- OriginalArtist,
- Actor,
- VoiceActor,
- Producer,
- Remixer,
- Conductor,
- Composer,
- Author,
- Editor
+ /// <summary>
+ /// Another role, not covered by the other types.
+ /// </summary>
+ Other = 0,
+
+ /// <summary>
+ /// The director of the media.
+ /// </summary>
+ Director = 1,
+
+ /// <summary>
+ /// An artist.
+ /// </summary>
+ Artist = 2,
+
+ /// <summary>
+ /// The original artist.
+ /// </summary>
+ OriginalArtist = 3,
+
+ /// <summary>
+ /// An actor.
+ /// </summary>
+ Actor = 4,
+
+ /// <summary>
+ /// A voice actor.
+ /// </summary>
+ VoiceActor = 5,
+
+ /// <summary>
+ /// A producer.
+ /// </summary>
+ Producer = 6,
+
+ /// <summary>
+ /// A remixer.
+ /// </summary>
+ Remixer = 7,
+
+ /// <summary>
+ /// A conductor.
+ /// </summary>
+ Conductor = 8,
+
+ /// <summary>
+ /// A composer.
+ /// </summary>
+ Composer = 9,
+
+ /// <summary>
+ /// An author.
+ /// </summary>
+ Author = 10,
+
+ /// <summary>
+ /// An editor.
+ /// </summary>
+ Editor = 11
}
}
diff --git a/Jellyfin.Data/Enums/SubtitlePlaybackMode.cs b/Jellyfin.Data/Enums/SubtitlePlaybackMode.cs
index c8fc21159..ca41300ed 100644
--- a/Jellyfin.Data/Enums/SubtitlePlaybackMode.cs
+++ b/Jellyfin.Data/Enums/SubtitlePlaybackMode.cs
@@ -1,13 +1,33 @@
-#pragma warning disable CS1591
-
-namespace Jellyfin.Data.Enums
+namespace Jellyfin.Data.Enums
{
+ /// <summary>
+ /// An enum representing a subtitle playback mode.
+ /// </summary>
public enum SubtitlePlaybackMode
{
+ /// <summary>
+ /// The default subtitle playback mode.
+ /// </summary>
Default = 0,
+
+ /// <summary>
+ /// Always show subtitles.
+ /// </summary>
Always = 1,
+
+ /// <summary>
+ /// Only show forced subtitles.
+ /// </summary>
OnlyForced = 2,
+
+ /// <summary>
+ /// Don't show subtitles.
+ /// </summary>
None = 3,
+
+ /// <summary>
+ /// Only show subtitles when the current audio stream is in a different language.
+ /// </summary>
Smart = 4
}
}
diff --git a/Jellyfin.Data/Enums/UnratedItem.cs b/Jellyfin.Data/Enums/UnratedItem.cs
index 5259e7739..871794086 100644
--- a/Jellyfin.Data/Enums/UnratedItem.cs
+++ b/Jellyfin.Data/Enums/UnratedItem.cs
@@ -1,17 +1,53 @@
-#pragma warning disable CS1591
-
namespace Jellyfin.Data.Enums
{
+ /// <summary>
+ /// An enum representing an unrated item.
+ /// </summary>
public enum UnratedItem
{
- Movie,
- Trailer,
- Series,
- Music,
- Book,
- LiveTvChannel,
- LiveTvProgram,
- ChannelContent,
- Other
+ /// <summary>
+ /// A movie.
+ /// </summary>
+ Movie = 0,
+
+ /// <summary>
+ /// A trailer.
+ /// </summary>
+ Trailer = 1,
+
+ /// <summary>
+ /// A series.
+ /// </summary>
+ Series = 2,
+
+ /// <summary>
+ /// Music.
+ /// </summary>
+ Music = 3,
+
+ /// <summary>
+ /// A book.
+ /// </summary>
+ Book = 4,
+
+ /// <summary>
+ /// A live TV channel
+ /// </summary>
+ LiveTvChannel = 5,
+
+ /// <summary>
+ /// A live TV program.
+ /// </summary>
+ LiveTvProgram = 6,
+
+ /// <summary>
+ /// Channel content.
+ /// </summary>
+ ChannelContent = 7,
+
+ /// <summary>
+ /// Another type, not covered by the other fields.
+ /// </summary>
+ Other = 8
}
}
diff --git a/Jellyfin.Data/Jellyfin.Data.csproj b/Jellyfin.Data/Jellyfin.Data.csproj
index 203eeaf3b..95343f91b 100644
--- a/Jellyfin.Data/Jellyfin.Data.csproj
+++ b/Jellyfin.Data/Jellyfin.Data.csproj
@@ -4,7 +4,7 @@
<TargetFrameworks>netstandard2.0;netstandard2.1</TargetFrameworks>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
- <TreatWarningsAsErrors Condition=" '$(Configuration)' == 'Release' ">true</TreatWarningsAsErrors>
+ <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<EmbedUntrackedSources>true</EmbedUntrackedSources>
<IncludeSymbols>true</IncludeSymbols>
@@ -45,4 +45,8 @@
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="3.1.7" />
</ItemGroup>
+ <ItemGroup>
+ <Compile Include="..\SharedVersion.cs" />
+ </ItemGroup>
+
</Project>
diff --git a/MediaBrowser.Common/Net/CacheMode.cs b/MediaBrowser.Common/Net/CacheMode.cs
deleted file mode 100644
index 78fa3bf9b..000000000
--- a/MediaBrowser.Common/Net/CacheMode.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-#pragma warning disable CS1591
-#pragma warning disable SA1602
-
-namespace MediaBrowser.Common.Net
-{
- public enum CacheMode
- {
- None = 0,
- Unconditional = 1
- }
-}
diff --git a/MediaBrowser.Common/Net/CompressionMethods.cs b/MediaBrowser.Common/Net/CompressionMethods.cs
deleted file mode 100644
index 39b72609f..000000000
--- a/MediaBrowser.Common/Net/CompressionMethods.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-#pragma warning disable CS1591
-#pragma warning disable SA1602
-
-using System;
-
-namespace MediaBrowser.Common.Net
-{
- [Flags]
- public enum CompressionMethods
- {
- None = 0b00000001,
- Deflate = 0b00000010,
- Gzip = 0b00000100
- }
-}
diff --git a/MediaBrowser.Common/Net/HttpRequestOptions.cs b/MediaBrowser.Common/Net/HttpRequestOptions.cs
deleted file mode 100644
index 347fc9833..000000000
--- a/MediaBrowser.Common/Net/HttpRequestOptions.cs
+++ /dev/null
@@ -1,105 +0,0 @@
-#pragma warning disable CS1591
-
-using System;
-using System.Collections.Generic;
-using System.Threading;
-using Microsoft.Net.Http.Headers;
-
-namespace MediaBrowser.Common.Net
-{
- /// <summary>
- /// Class HttpRequestOptions.
- /// </summary>
- public class HttpRequestOptions
- {
- /// <summary>
- /// Initializes a new instance of the <see cref="HttpRequestOptions"/> class.
- /// </summary>
- public HttpRequestOptions()
- {
- RequestHeaders = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
-
- CacheMode = CacheMode.None;
- DecompressionMethod = CompressionMethods.Deflate;
- }
-
- /// <summary>
- /// Gets or sets the URL.
- /// </summary>
- /// <value>The URL.</value>
- public string Url { get; set; }
-
- public CompressionMethods DecompressionMethod { get; set; }
-
- /// <summary>
- /// Gets or sets the accept header.
- /// </summary>
- /// <value>The accept header.</value>
- public string AcceptHeader
- {
- get => GetHeaderValue(HeaderNames.Accept);
- set => RequestHeaders[HeaderNames.Accept] = value;
- }
-
- /// <summary>
- /// Gets or sets the cancellation token.
- /// </summary>
- /// <value>The cancellation token.</value>
- public CancellationToken CancellationToken { get; set; }
-
- /// <summary>
- /// Gets or sets the user agent.
- /// </summary>
- /// <value>The user agent.</value>
- public string UserAgent
- {
- get => GetHeaderValue(HeaderNames.UserAgent);
- set => RequestHeaders[HeaderNames.UserAgent] = value;
- }
-
- /// <summary>
- /// Gets or sets the referrer.
- /// </summary>
- /// <value>The referrer.</value>
- public string Referer
- {
- get => GetHeaderValue(HeaderNames.Referer);
- set => RequestHeaders[HeaderNames.Referer] = value;
- }
-
- /// <summary>
- /// Gets or sets the host.
- /// </summary>
- /// <value>The host.</value>
- public string Host
- {
- get => GetHeaderValue(HeaderNames.Host);
- set => RequestHeaders[HeaderNames.Host] = value;
- }
-
- public Dictionary<string, string> RequestHeaders { get; private set; }
-
- public string RequestContentType { get; set; }
-
- public string RequestContent { get; set; }
-
- public bool BufferContent { get; set; }
-
- public bool LogErrorResponseBody { get; set; }
-
- public bool EnableKeepAlive { get; set; }
-
- public CacheMode CacheMode { get; set; }
-
- public TimeSpan CacheLength { get; set; }
-
- public bool EnableDefaultUserAgent { get; set; }
-
- private string GetHeaderValue(string name)
- {
- RequestHeaders.TryGetValue(name, out var value);
-
- return value;
- }
- }
-}
diff --git a/MediaBrowser.Common/Net/HttpResponseInfo.cs b/MediaBrowser.Common/Net/HttpResponseInfo.cs
deleted file mode 100644
index d4fee6c78..000000000
--- a/MediaBrowser.Common/Net/HttpResponseInfo.cs
+++ /dev/null
@@ -1,80 +0,0 @@
-using System;
-using System.IO;
-using System.Net;
-using System.Net.Http.Headers;
-
-namespace MediaBrowser.Common.Net
-{
- /// <summary>
- /// Class HttpResponseInfo.
- /// </summary>
- public sealed class HttpResponseInfo : IDisposable
- {
-#pragma warning disable CS1591
- public HttpResponseInfo()
- {
- }
-
- public HttpResponseInfo(HttpResponseHeaders headers, HttpContentHeaders contentHeader)
- {
- Headers = headers;
- ContentHeaders = contentHeader;
- }
-
-#pragma warning restore CS1591
-
- /// <summary>
- /// Gets or sets the type of the content.
- /// </summary>
- /// <value>The type of the content.</value>
- public string ContentType { get; set; }
-
- /// <summary>
- /// Gets or sets the response URL.
- /// </summary>
- /// <value>The response URL.</value>
- public string ResponseUrl { get; set; }
-
- /// <summary>
- /// Gets or sets the content.
- /// </summary>
- /// <value>The content.</value>
- public Stream Content { get; set; }
-
- /// <summary>
- /// Gets or sets the status code.
- /// </summary>
- /// <value>The status code.</value>
- public HttpStatusCode StatusCode { get; set; }
-
- /// <summary>
- /// Gets or sets the temp file path.
- /// </summary>
- /// <value>The temp file path.</value>
- public string TempFilePath { get; set; }
-
- /// <summary>
- /// Gets or sets the length of the content.
- /// </summary>
- /// <value>The length of the content.</value>
- public long? ContentLength { get; set; }
-
- /// <summary>
- /// Gets or sets the headers.
- /// </summary>
- /// <value>The headers.</value>
- public HttpResponseHeaders Headers { get; set; }
-
- /// <summary>
- /// Gets or sets the content headers.
- /// </summary>
- /// <value>The content headers.</value>
- public HttpContentHeaders ContentHeaders { get; set; }
-
- /// <inheritdoc />
- public void Dispose()
- {
- // backwards compatibility
- }
- }
-}
diff --git a/MediaBrowser.Common/Net/IHttpClient.cs b/MediaBrowser.Common/Net/IHttpClient.cs
deleted file mode 100644
index 534e22edd..000000000
--- a/MediaBrowser.Common/Net/IHttpClient.cs
+++ /dev/null
@@ -1,53 +0,0 @@
-using System;
-using System.IO;
-using System.Net.Http;
-using System.Threading.Tasks;
-
-namespace MediaBrowser.Common.Net
-{
- /// <summary>
- /// Interface IHttpClient.
- /// </summary>
- public interface IHttpClient
- {
- /// <summary>
- /// Gets the response.
- /// </summary>
- /// <param name="options">The options.</param>
- /// <returns>Task{HttpResponseInfo}.</returns>
- Task<HttpResponseInfo> GetResponse(HttpRequestOptions options);
-
- /// <summary>
- /// Gets the specified options.
- /// </summary>
- /// <param name="options">The options.</param>
- /// <returns>Task{Stream}.</returns>
- Task<Stream> Get(HttpRequestOptions options);
-
- /// <summary>
- /// Warning: Deprecated function,
- /// use 'Task{HttpResponseInfo} SendAsync(HttpRequestOptions options, HttpMethod httpMethod);' instead
- /// Sends the asynchronous.
- /// </summary>
- /// <param name="options">The options.</param>
- /// <param name="httpMethod">The HTTP method.</param>
- /// <returns>Task{HttpResponseInfo}.</returns>
- [Obsolete("Use 'Task{HttpResponseInfo} SendAsync(HttpRequestOptions options, HttpMethod httpMethod);' instead")]
- Task<HttpResponseInfo> SendAsync(HttpRequestOptions options, string httpMethod);
-
- /// <summary>
- /// Sends the asynchronous.
- /// </summary>
- /// <param name="options">The options.</param>
- /// <param name="httpMethod">The HTTP method.</param>
- /// <returns>Task{HttpResponseInfo}.</returns>
- Task<HttpResponseInfo> SendAsync(HttpRequestOptions options, HttpMethod httpMethod);
-
- /// <summary>
- /// Posts the specified options.
- /// </summary>
- /// <param name="options">The options.</param>
- /// <returns>Task{HttpResponseInfo}.</returns>
- Task<HttpResponseInfo> Post(HttpRequestOptions options);
- }
-}
diff --git a/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj b/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj
index 814edd732..6ead93e09 100644
--- a/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj
+++ b/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj
@@ -24,6 +24,7 @@
<ItemGroup>
<PackageReference Include="BDInfo" Version="0.7.6.1" />
+ <PackageReference Include="Microsoft.Extensions.Http" Version="3.1.6" />
<PackageReference Include="System.Text.Encoding.CodePages" Version="4.7.1" />
<PackageReference Include="UTF.Unknown" Version="2.3.0" />
</ItemGroup>
diff --git a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs
index 6ac5ac2ff..0a9958b9e 100644
--- a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs
+++ b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs
@@ -6,6 +6,7 @@ using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
+using System.Net.Http;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
@@ -31,7 +32,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
private readonly IApplicationPaths _appPaths;
private readonly IFileSystem _fileSystem;
private readonly IMediaEncoder _mediaEncoder;
- private readonly IHttpClient _httpClient;
+ private readonly IHttpClientFactory _httpClientFactory;
private readonly IMediaSourceManager _mediaSourceManager;
/// <summary>
@@ -46,7 +47,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
IApplicationPaths appPaths,
IFileSystem fileSystem,
IMediaEncoder mediaEncoder,
- IHttpClient httpClient,
+ IHttpClientFactory httpClientFactory,
IMediaSourceManager mediaSourceManager)
{
_libraryManager = libraryManager;
@@ -54,7 +55,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
_appPaths = appPaths;
_fileSystem = fileSystem;
_mediaEncoder = mediaEncoder;
- _httpClient = httpClient;
+ _httpClientFactory = httpClientFactory;
_mediaSourceManager = mediaSourceManager;
}
@@ -750,24 +751,20 @@ namespace MediaBrowser.MediaEncoding.Subtitles
}
}
- private Task<Stream> GetStream(string path, MediaProtocol protocol, CancellationToken cancellationToken)
+ private async Task<Stream> GetStream(string path, MediaProtocol protocol, CancellationToken cancellationToken)
{
switch (protocol)
{
case MediaProtocol.Http:
- var opts = new HttpRequestOptions()
- {
- Url = path,
- CancellationToken = cancellationToken,
-
- // Needed for seeking
- BufferContent = true
- };
-
- return _httpClient.Get(opts);
+ {
+ using var response = await _httpClientFactory.CreateClient(NamedClient.Default)
+ .GetAsync(path, cancellationToken)
+ .ConfigureAwait(false);
+ return await response.Content.ReadAsStreamAsync().ConfigureAwait(false);
+ }
case MediaProtocol.File:
- return Task.FromResult<Stream>(File.OpenRead(path));
+ return File.OpenRead(path);
default:
throw new ArgumentOutOfRangeException(nameof(protocol));
}
diff --git a/MediaBrowser.Model/Net/MimeTypes.cs b/MediaBrowser.Model/Net/MimeTypes.cs
index 771ca84f7..afe7351d3 100644
--- a/MediaBrowser.Model/Net/MimeTypes.cs
+++ b/MediaBrowser.Model/Net/MimeTypes.cs
@@ -125,7 +125,7 @@ namespace MediaBrowser.Model.Net
{ ".wmv", "video/x-ms-wmv" },
// Type audio
- { ".aac", "audio/mp4" },
+ { ".aac", "audio/aac" },
{ ".ac3", "audio/ac3" },
{ ".ape", "audio/x-ape" },
{ ".dsf", "audio/dsf" },
diff --git a/MediaBrowser.Providers/Manager/ProviderManager.cs b/MediaBrowser.Providers/Manager/ProviderManager.cs
index 155e8cb8a..171b824ca 100644
--- a/MediaBrowser.Providers/Manager/ProviderManager.cs
+++ b/MediaBrowser.Providers/Manager/ProviderManager.cs
@@ -156,7 +156,7 @@ namespace MediaBrowser.Providers.Manager
/// <inheritdoc/>
public async Task SaveImage(BaseItem item, string url, ImageType type, int? imageIndex, CancellationToken cancellationToken)
{
- var httpClient = _httpClientFactory.CreateClient();
+ var httpClient = _httpClientFactory.CreateClient(NamedClient.Default);
using var response = await httpClient.GetAsync(url, cancellationToken).ConfigureAwait(false);
var contentType = response.Content.Headers.ContentType.MediaType;
diff --git a/MediaBrowser.Providers/Plugins/AudioDb/AlbumImageProvider.cs b/MediaBrowser.Providers/Plugins/AudioDb/AlbumImageProvider.cs
index c9dac9ecd..e3a1decb8 100644
--- a/MediaBrowser.Providers/Plugins/AudioDb/AlbumImageProvider.cs
+++ b/MediaBrowser.Providers/Plugins/AudioDb/AlbumImageProvider.cs
@@ -4,6 +4,7 @@ using System.Collections.Generic;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
+using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
@@ -96,7 +97,7 @@ namespace MediaBrowser.Providers.Plugins.AudioDb
/// <inheritdoc />
public Task<HttpResponseMessage> GetImageResponse(string url, CancellationToken cancellationToken)
{
- var httpClient = _httpClientFactory.CreateClient();
+ var httpClient = _httpClientFactory.CreateClient(NamedClient.Default);
return httpClient.GetAsync(url, cancellationToken);
}
diff --git a/MediaBrowser.Providers/Plugins/AudioDb/AlbumProvider.cs b/MediaBrowser.Providers/Plugins/AudioDb/AlbumProvider.cs
index 321144edf..e6d89e688 100644
--- a/MediaBrowser.Providers/Plugins/AudioDb/AlbumProvider.cs
+++ b/MediaBrowser.Providers/Plugins/AudioDb/AlbumProvider.cs
@@ -10,6 +10,7 @@ using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Extensions;
+using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Providers;
@@ -173,7 +174,7 @@ namespace MediaBrowser.Providers.Plugins.AudioDb
Directory.CreateDirectory(Path.GetDirectoryName(path));
- using var response = await _httpClientFactory.CreateClient().GetAsync(url, cancellationToken);
+ using var response = await _httpClientFactory.CreateClient(NamedClient.Default).GetAsync(url, cancellationToken).ConfigureAwait(false);
await using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false);
await using var xmlFileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read, IODefaults.FileStreamBufferSize, true);
await stream.CopyToAsync(xmlFileStream, cancellationToken).ConfigureAwait(false);
diff --git a/MediaBrowser.Providers/Plugins/AudioDb/ArtistImageProvider.cs b/MediaBrowser.Providers/Plugins/AudioDb/ArtistImageProvider.cs
index 651266868..54851c4d0 100644
--- a/MediaBrowser.Providers/Plugins/AudioDb/ArtistImageProvider.cs
+++ b/MediaBrowser.Providers/Plugins/AudioDb/ArtistImageProvider.cs
@@ -4,6 +4,7 @@ using System.Collections.Generic;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
+using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
@@ -137,7 +138,7 @@ namespace MediaBrowser.Providers.Plugins.AudioDb
public Task<HttpResponseMessage> GetImageResponse(string url, CancellationToken cancellationToken)
{
- var httpClient = _httpClientFactory.CreateClient();
+ var httpClient = _httpClientFactory.CreateClient(NamedClient.Default);
return httpClient.GetAsync(url, cancellationToken);
}
diff --git a/MediaBrowser.Providers/Plugins/AudioDb/ArtistProvider.cs b/MediaBrowser.Providers/Plugins/AudioDb/ArtistProvider.cs
index 708426500..670c0cd05 100644
--- a/MediaBrowser.Providers/Plugins/AudioDb/ArtistProvider.cs
+++ b/MediaBrowser.Providers/Plugins/AudioDb/ArtistProvider.cs
@@ -9,6 +9,7 @@ using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Extensions;
+using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Providers;
@@ -154,7 +155,7 @@ namespace MediaBrowser.Providers.Plugins.AudioDb
var path = GetArtistInfoPath(_config.ApplicationPaths, musicBrainzId);
- using var response = await _httpClientFactory.CreateClient().GetAsync(url, cancellationToken);
+ using var response = await _httpClientFactory.CreateClient(NamedClient.Default).GetAsync(url, cancellationToken).ConfigureAwait(false);
await using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false);
Directory.CreateDirectory(Path.GetDirectoryName(path));
diff --git a/MediaBrowser.Providers/Plugins/MusicBrainz/AlbumProvider.cs b/MediaBrowser.Providers/Plugins/MusicBrainz/AlbumProvider.cs
index 7f10e6922..8414c9328 100644
--- a/MediaBrowser.Providers/Plugins/MusicBrainz/AlbumProvider.cs
+++ b/MediaBrowser.Providers/Plugins/MusicBrainz/AlbumProvider.cs
@@ -14,6 +14,7 @@ using System.Threading;
using System.Threading.Tasks;
using System.Xml;
using MediaBrowser.Common;
+using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities;
@@ -765,7 +766,7 @@ namespace MediaBrowser.Providers.Music
_logger.LogDebug("GetMusicBrainzResponse: Time since previous request: {0} ms", _stopWatchMusicBrainz.ElapsedMilliseconds);
_stopWatchMusicBrainz.Restart();
- response = await _httpClientFactory.CreateClient().SendAsync(options).ConfigureAwait(false);
+ response = await _httpClientFactory.CreateClient(NamedClient.Default).SendAsync(options).ConfigureAwait(false);
// We retry a finite number of times, and only whilst MB is indicating 503 (throttling)
}
diff --git a/MediaBrowser.Providers/Plugins/Omdb/OmdbImageProvider.cs b/MediaBrowser.Providers/Plugins/Omdb/OmdbImageProvider.cs
index c18725e0a..8b8fea09e 100644
--- a/MediaBrowser.Providers/Plugins/Omdb/OmdbImageProvider.cs
+++ b/MediaBrowser.Providers/Plugins/Omdb/OmdbImageProvider.cs
@@ -6,6 +6,7 @@ using System.Globalization;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Common;
+using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Movies;
@@ -82,7 +83,7 @@ namespace MediaBrowser.Providers.Plugins.Omdb
public Task<HttpResponseMessage> GetImageResponse(string url, CancellationToken cancellationToken)
{
- return _httpClientFactory.CreateClient().GetAsync(url, cancellationToken);
+ return _httpClientFactory.CreateClient(NamedClient.Default).GetAsync(url, cancellationToken);
}
public string Name => "The Open Movie Database";
diff --git a/MediaBrowser.Providers/Plugins/Omdb/OmdbItemProvider.cs b/MediaBrowser.Providers/Plugins/Omdb/OmdbItemProvider.cs
index 102ad82e1..d53eba7e9 100644
--- a/MediaBrowser.Providers/Plugins/Omdb/OmdbItemProvider.cs
+++ b/MediaBrowser.Providers/Plugins/Omdb/OmdbItemProvider.cs
@@ -9,6 +9,7 @@ using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Common;
+using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Movies;
@@ -129,7 +130,7 @@ namespace MediaBrowser.Providers.Plugins.Omdb
var url = OmdbProvider.GetOmdbUrl(urlQuery);
- using var response = await OmdbProvider.GetOmdbResponse(_httpClientFactory.CreateClient(), url, cancellationToken).ConfigureAwait(false);
+ using var response = await OmdbProvider.GetOmdbResponse(_httpClientFactory.CreateClient(NamedClient.Default), url, cancellationToken).ConfigureAwait(false);
await using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false);
var resultList = new List<SearchResult>();
@@ -274,7 +275,7 @@ namespace MediaBrowser.Providers.Plugins.Omdb
public Task<HttpResponseMessage> GetImageResponse(string url, CancellationToken cancellationToken)
{
- return _httpClientFactory.CreateClient().GetAsync(url, cancellationToken);
+ return _httpClientFactory.CreateClient(NamedClient.Default).GetAsync(url, cancellationToken);
}
class SearchResult
diff --git a/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs b/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs
index c45149c3a..32dab60a6 100644
--- a/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs
+++ b/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs
@@ -10,6 +10,7 @@ using System.Text;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Common;
+using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Providers;
@@ -296,7 +297,7 @@ namespace MediaBrowser.Providers.Plugins.Omdb
"i={0}&plot=short&tomatoes=true&r=json",
imdbParam));
- using var response = await GetOmdbResponse(_httpClientFactory.CreateClient(), url, cancellationToken).ConfigureAwait(false);
+ using var response = await GetOmdbResponse(_httpClientFactory.CreateClient(NamedClient.Default), url, cancellationToken).ConfigureAwait(false);
await using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false);
var rootObject = await _jsonSerializer.DeserializeFromStreamAsync<RootObject>(stream).ConfigureAwait(false);
Directory.CreateDirectory(Path.GetDirectoryName(path));
@@ -334,7 +335,7 @@ namespace MediaBrowser.Providers.Plugins.Omdb
imdbParam,
seasonId));
- using var response = await GetOmdbResponse(_httpClientFactory.CreateClient(), url, cancellationToken).ConfigureAwait(false);
+ using var response = await GetOmdbResponse(_httpClientFactory.CreateClient(NamedClient.Default), url, cancellationToken).ConfigureAwait(false);
await using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false);
var rootObject = await _jsonSerializer.DeserializeFromStreamAsync<SeasonRootObject>(stream).ConfigureAwait(false);
Directory.CreateDirectory(Path.GetDirectoryName(path));
diff --git a/MediaBrowser.Providers/Plugins/TheTvdb/TvdbEpisodeImageProvider.cs b/MediaBrowser.Providers/Plugins/TheTvdb/TvdbEpisodeImageProvider.cs
index 4e7c0e5a6..de2f6875f 100644
--- a/MediaBrowser.Providers/Plugins/TheTvdb/TvdbEpisodeImageProvider.cs
+++ b/MediaBrowser.Providers/Plugins/TheTvdb/TvdbEpisodeImageProvider.cs
@@ -6,6 +6,7 @@ using System.Net.Http;
using System.Globalization;
using System.Threading;
using System.Threading.Tasks;
+using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Providers;
@@ -116,7 +117,7 @@ namespace MediaBrowser.Providers.Plugins.TheTvdb
public Task<HttpResponseMessage> GetImageResponse(string url, CancellationToken cancellationToken)
{
- return _httpClientFactory.CreateClient().GetAsync(url, cancellationToken);
+ return _httpClientFactory.CreateClient(NamedClient.Default).GetAsync(url, cancellationToken);
}
}
}
diff --git a/MediaBrowser.Providers/Plugins/TheTvdb/TvdbEpisodeProvider.cs b/MediaBrowser.Providers/Plugins/TheTvdb/TvdbEpisodeProvider.cs
index 90436c7c9..c088d8cec 100644
--- a/MediaBrowser.Providers/Plugins/TheTvdb/TvdbEpisodeProvider.cs
+++ b/MediaBrowser.Providers/Plugins/TheTvdb/TvdbEpisodeProvider.cs
@@ -5,6 +5,7 @@ using System.Collections.Generic;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
+using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Providers;
@@ -153,6 +154,13 @@ namespace MediaBrowser.Providers.Plugins.TheTvdb
item.IndexNumber = Convert.ToInt32(episode.DvdEpisodeNumber ?? episode.AiredEpisodeNumber);
item.ParentIndexNumber = episode.DvdSeason ?? episode.AiredSeason;
}
+ else if (string.Equals(id.SeriesDisplayOrder, "absolute", StringComparison.OrdinalIgnoreCase))
+ {
+ if (episode.AbsoluteNumber.GetValueOrDefault() != 0)
+ {
+ item.IndexNumber = episode.AbsoluteNumber;
+ }
+ }
else if (episode.AiredEpisodeNumber.HasValue)
{
item.IndexNumber = episode.AiredEpisodeNumber;
@@ -244,7 +252,7 @@ namespace MediaBrowser.Providers.Plugins.TheTvdb
public Task<HttpResponseMessage> GetImageResponse(string url, CancellationToken cancellationToken)
{
- return _httpClientFactory.CreateClient().GetAsync(url, cancellationToken);
+ return _httpClientFactory.CreateClient(NamedClient.Default).GetAsync(url, cancellationToken);
}
public int Order => 0;
diff --git a/MediaBrowser.Providers/Plugins/TheTvdb/TvdbPersonImageProvider.cs b/MediaBrowser.Providers/Plugins/TheTvdb/TvdbPersonImageProvider.cs
index 388a4e3e7..dc3c60dee 100644
--- a/MediaBrowser.Providers/Plugins/TheTvdb/TvdbPersonImageProvider.cs
+++ b/MediaBrowser.Providers/Plugins/TheTvdb/TvdbPersonImageProvider.cs
@@ -6,6 +6,7 @@ using System.Linq;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
+using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.TV;
@@ -106,7 +107,7 @@ namespace MediaBrowser.Providers.Plugins.TheTvdb
/// <inheritdoc />
public Task<HttpResponseMessage> GetImageResponse(string url, CancellationToken cancellationToken)
{
- return _httpClientFactory.CreateClient().GetAsync(url, cancellationToken);
+ return _httpClientFactory.CreateClient(NamedClient.Default).GetAsync(url, cancellationToken);
}
}
}
diff --git a/MediaBrowser.Providers/Plugins/TheTvdb/TvdbSeasonImageProvider.cs b/MediaBrowser.Providers/Plugins/TheTvdb/TvdbSeasonImageProvider.cs
index ff8c3455f..49576d488 100644
--- a/MediaBrowser.Providers/Plugins/TheTvdb/TvdbSeasonImageProvider.cs
+++ b/MediaBrowser.Providers/Plugins/TheTvdb/TvdbSeasonImageProvider.cs
@@ -6,6 +6,7 @@ using System.Linq;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
+using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Providers;
@@ -148,7 +149,7 @@ namespace MediaBrowser.Providers.Plugins.TheTvdb
public Task<HttpResponseMessage> GetImageResponse(string url, CancellationToken cancellationToken)
{
- return _httpClientFactory.CreateClient().GetAsync(url, cancellationToken);
+ return _httpClientFactory.CreateClient(NamedClient.Default).GetAsync(url, cancellationToken);
}
}
}
diff --git a/MediaBrowser.Providers/Plugins/TheTvdb/TvdbSeriesImageProvider.cs b/MediaBrowser.Providers/Plugins/TheTvdb/TvdbSeriesImageProvider.cs
index d287828eb..d96840e51 100644
--- a/MediaBrowser.Providers/Plugins/TheTvdb/TvdbSeriesImageProvider.cs
+++ b/MediaBrowser.Providers/Plugins/TheTvdb/TvdbSeriesImageProvider.cs
@@ -6,6 +6,7 @@ using System.Linq;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
+using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities;
@@ -146,7 +147,7 @@ namespace MediaBrowser.Providers.Plugins.TheTvdb
public Task<HttpResponseMessage> GetImageResponse(string url, CancellationToken cancellationToken)
{
- return _httpClientFactory.CreateClient().GetAsync(url, cancellationToken);
+ return _httpClientFactory.CreateClient(NamedClient.Default).GetAsync(url, cancellationToken);
}
}
}
diff --git a/MediaBrowser.Providers/Plugins/TheTvdb/TvdbSeriesProvider.cs b/MediaBrowser.Providers/Plugins/TheTvdb/TvdbSeriesProvider.cs
index c6dd8a5f3..ca9b1d738 100644
--- a/MediaBrowser.Providers/Plugins/TheTvdb/TvdbSeriesProvider.cs
+++ b/MediaBrowser.Providers/Plugins/TheTvdb/TvdbSeriesProvider.cs
@@ -8,6 +8,7 @@ using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
+using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Providers;
@@ -410,7 +411,7 @@ namespace MediaBrowser.Providers.Plugins.TheTvdb
public Task<HttpResponseMessage> GetImageResponse(string url, CancellationToken cancellationToken)
{
- return _httpClientFactory.CreateClient().GetAsync(url, cancellationToken);
+ return _httpClientFactory.CreateClient(NamedClient.Default).GetAsync(url, cancellationToken);
}
}
}
diff --git a/MediaBrowser.Providers/Plugins/Tmdb/BoxSets/TmdbBoxSetImageProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/BoxSets/TmdbBoxSetImageProvider.cs
index f43444028..f6592afe4 100644
--- a/MediaBrowser.Providers/Plugins/Tmdb/BoxSets/TmdbBoxSetImageProvider.cs
+++ b/MediaBrowser.Providers/Plugins/Tmdb/BoxSets/TmdbBoxSetImageProvider.cs
@@ -6,6 +6,7 @@ using System.Linq;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
+using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Movies;
using MediaBrowser.Controller.Providers;
@@ -155,7 +156,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.BoxSets
public Task<HttpResponseMessage> GetImageResponse(string url, CancellationToken cancellationToken)
{
- return _httpClientFactory.CreateClient().GetAsync(url, cancellationToken);
+ return _httpClientFactory.CreateClient(NamedClient.Default).GetAsync(url, cancellationToken);
}
}
}
diff --git a/MediaBrowser.Providers/Plugins/Tmdb/BoxSets/TmdbBoxSetProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/BoxSets/TmdbBoxSetProvider.cs
index 4da2c042f..e627550f1 100644
--- a/MediaBrowser.Providers/Plugins/Tmdb/BoxSets/TmdbBoxSetProvider.cs
+++ b/MediaBrowser.Providers/Plugins/Tmdb/BoxSets/TmdbBoxSetProvider.cs
@@ -10,6 +10,7 @@ using System.Net.Http.Headers;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Common.Configuration;
+using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities.Movies;
using MediaBrowser.Controller.Library;
@@ -271,7 +272,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.BoxSets
public Task<HttpResponseMessage> GetImageResponse(string url, CancellationToken cancellationToken)
{
- return _httpClientFactory.CreateClient().GetAsync(url, cancellationToken);
+ return _httpClientFactory.CreateClient(NamedClient.Default).GetAsync(url, cancellationToken);
}
}
}
diff --git a/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbImageProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbImageProvider.cs
index 60d7a599e..a975fb8f6 100644
--- a/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbImageProvider.cs
+++ b/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbImageProvider.cs
@@ -7,6 +7,7 @@ using System.Linq;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
+using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Movies;
using MediaBrowser.Controller.Providers;
@@ -204,7 +205,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Movies
public Task<HttpResponseMessage> GetImageResponse(string url, CancellationToken cancellationToken)
{
- return _httpClientFactory.CreateClient().GetAsync(url, cancellationToken);
+ return _httpClientFactory.CreateClient(NamedClient.Default).GetAsync(url, cancellationToken);
}
}
}
diff --git a/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieProvider.cs
index d8918bb6b..f8bc19395 100644
--- a/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieProvider.cs
+++ b/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieProvider.cs
@@ -11,6 +11,7 @@ using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Common;
using MediaBrowser.Common.Configuration;
+using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Movies;
@@ -383,7 +384,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Movies
internal Task<HttpResponseMessage> GetMovieDbResponse(HttpRequestMessage message)
{
message.Headers.UserAgent.ParseAdd(_appHost.ApplicationUserAgent);
- return _httpClientFactory.CreateClient().SendAsync(message);
+ return _httpClientFactory.CreateClient(NamedClient.Default).SendAsync(message);
}
/// <inheritdoc />
@@ -392,7 +393,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Movies
/// <inheritdoc />
public Task<HttpResponseMessage> GetImageResponse(string url, CancellationToken cancellationToken)
{
- return _httpClientFactory.CreateClient().GetAsync(url, cancellationToken);
+ return _httpClientFactory.CreateClient(NamedClient.Default).GetAsync(url, cancellationToken);
}
}
}
diff --git a/MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonImageProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonImageProvider.cs
index 291b36027..f2d2c8120 100644
--- a/MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonImageProvider.cs
+++ b/MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonImageProvider.cs
@@ -6,6 +6,7 @@ using System.Linq;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
+using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Providers;
@@ -131,7 +132,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.People
public Task<HttpResponseMessage> GetImageResponse(string url, CancellationToken cancellationToken)
{
- return _httpClientFactory.CreateClient().GetAsync(url, cancellationToken);
+ return _httpClientFactory.CreateClient(NamedClient.Default).GetAsync(url, cancellationToken);
}
}
}
diff --git a/MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonProvider.cs
index a4b1387d3..6bf04b81a 100644
--- a/MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonProvider.cs
+++ b/MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonProvider.cs
@@ -12,6 +12,7 @@ using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Extensions;
+using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Providers;
@@ -267,7 +268,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.People
public Task<HttpResponseMessage> GetImageResponse(string url, CancellationToken cancellationToken)
{
- return _httpClientFactory.CreateClient().GetAsync(url, cancellationToken);
+ return _httpClientFactory.CreateClient(NamedClient.Default).GetAsync(url, cancellationToken);
}
}
}
diff --git a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeProviderBase.cs b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeProviderBase.cs
index 5705885b4..30b7674e3 100644
--- a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeProviderBase.cs
+++ b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeProviderBase.cs
@@ -7,6 +7,7 @@ using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading;
using System.Threading.Tasks;
+using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Model.Globalization;
using MediaBrowser.Model.IO;
@@ -138,7 +139,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV
protected Task<HttpResponseMessage> GetResponse(string url, CancellationToken cancellationToken)
{
- return _httpClientFactory.CreateClient().GetAsync(url, cancellationToken);
+ return _httpClientFactory.CreateClient(NamedClient.Default).GetAsync(url, cancellationToken);
}
}
}
diff --git a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeasonImageProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeasonImageProvider.cs
index 787514d05..e7e2fd05b 100644
--- a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeasonImageProvider.cs
+++ b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeasonImageProvider.cs
@@ -7,6 +7,7 @@ using System.Linq;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
+using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Providers;
@@ -38,7 +39,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV
public Task<HttpResponseMessage> GetImageResponse(string url, CancellationToken cancellationToken)
{
- return _httpClientFactory.CreateClient().GetAsync(url, cancellationToken);
+ return _httpClientFactory.CreateClient(NamedClient.Default).GetAsync(url, cancellationToken);
}
public async Task<IEnumerable<RemoteImageInfo>> GetImages(BaseItem item, CancellationToken cancellationToken)
diff --git a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeasonProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeasonProvider.cs
index e59504cc6..73ed13267 100644
--- a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeasonProvider.cs
+++ b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeasonProvider.cs
@@ -9,6 +9,7 @@ using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading;
using System.Threading.Tasks;
+using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities;
@@ -124,7 +125,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV
public Task<HttpResponseMessage> GetImageResponse(string url, CancellationToken cancellationToken)
{
- return _httpClientFactory.CreateClient().GetAsync(url, cancellationToken);
+ return _httpClientFactory.CreateClient(NamedClient.Default).GetAsync(url, cancellationToken);
}
private async Task<SeasonResult> GetSeasonInfo(string seriesTmdbId, int season, string preferredMetadataLanguage,
diff --git a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeriesImageProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeriesImageProvider.cs
index f11eeb15b..125560175 100644
--- a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeriesImageProvider.cs
+++ b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeriesImageProvider.cs
@@ -6,6 +6,7 @@ using System.Linq;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
+using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Providers;
@@ -182,7 +183,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV
public Task<HttpResponseMessage> GetImageResponse(string url, CancellationToken cancellationToken)
{
- return _httpClientFactory.CreateClient().GetAsync(url, cancellationToken);
+ return _httpClientFactory.CreateClient(NamedClient.Default).GetAsync(url, cancellationToken);
}
}
}
diff --git a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeriesProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeriesProvider.cs
index 0eded3233..aaba6ffc0 100644
--- a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeriesProvider.cs
+++ b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeriesProvider.cs
@@ -10,6 +10,7 @@ using System.Net.Http.Headers;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Common.Configuration;
+using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.TV;
@@ -551,7 +552,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV
public Task<HttpResponseMessage> GetImageResponse(string url, CancellationToken cancellationToken)
{
- return _httpClientFactory.CreateClient().GetAsync(url, cancellationToken);
+ return _httpClientFactory.CreateClient(NamedClient.Default).GetAsync(url, cancellationToken);
}
}
}
diff --git a/MediaBrowser.Providers/Plugins/Tmdb/Trailers/TmdbTrailerProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/Trailers/TmdbTrailerProvider.cs
index 10374bde9..25296387b 100644
--- a/MediaBrowser.Providers/Plugins/Tmdb/Trailers/TmdbTrailerProvider.cs
+++ b/MediaBrowser.Providers/Plugins/Tmdb/Trailers/TmdbTrailerProvider.cs
@@ -4,6 +4,7 @@ using System.Collections.Generic;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
+using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Providers;
@@ -36,7 +37,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Trailers
public Task<HttpResponseMessage> GetImageResponse(string url, CancellationToken cancellationToken)
{
- return _httpClientFactory.CreateClient().GetAsync(url, cancellationToken);
+ return _httpClientFactory.CreateClient(NamedClient.Default).GetAsync(url, cancellationToken);
}
}
}
diff --git a/MediaBrowser.Providers/Studios/StudiosImageProvider.cs b/MediaBrowser.Providers/Studios/StudiosImageProvider.cs
index 321153c6b..76dc7df7f 100644
--- a/MediaBrowser.Providers/Studios/StudiosImageProvider.cs
+++ b/MediaBrowser.Providers/Studios/StudiosImageProvider.cs
@@ -8,6 +8,7 @@ using System.Linq;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
+using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Providers;
@@ -122,7 +123,7 @@ namespace MediaBrowser.Providers.Studios
public Task<HttpResponseMessage> GetImageResponse(string url, CancellationToken cancellationToken)
{
- var httpClient = _httpClientFactory.CreateClient();
+ var httpClient = _httpClientFactory.CreateClient(NamedClient.Default);
return httpClient.GetAsync(url, cancellationToken);
}
@@ -140,7 +141,7 @@ namespace MediaBrowser.Providers.Studios
if (!fileInfo.Exists || (DateTime.UtcNow - fileSystem.GetLastWriteTimeUtc(fileInfo)).TotalDays > 1)
{
- var httpClient = _httpClientFactory.CreateClient();
+ var httpClient = _httpClientFactory.CreateClient(NamedClient.Default);
Directory.CreateDirectory(Path.GetDirectoryName(file));
await using var response = await httpClient.GetStreamAsync(url).ConfigureAwait(false);
diff --git a/MediaBrowser.sln b/MediaBrowser.sln
index 75587da1f..fd45dca2a 100644
--- a/MediaBrowser.sln
+++ b/MediaBrowser.sln
@@ -66,8 +66,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Jellyfin.Data", "Jellyfin.D
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Jellyfin.Server.Implementations", "Jellyfin.Server.Implementations\Jellyfin.Server.Implementations.csproj", "{DAE48069-6D86-4BA6-B148-D1D49B6DDA52}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MediaBrowser.Api.Tests", "tests\MediaBrowser.Api.Tests\MediaBrowser.Api.Tests.csproj", "{7C93C84F-105C-48E5-A878-406FA0A5B296}"
-EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -178,10 +176,6 @@ Global
{DAE48069-6D86-4BA6-B148-D1D49B6DDA52}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DAE48069-6D86-4BA6-B148-D1D49B6DDA52}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DAE48069-6D86-4BA6-B148-D1D49B6DDA52}.Release|Any CPU.Build.0 = Release|Any CPU
- {7C93C84F-105C-48E5-A878-406FA0A5B296}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {7C93C84F-105C-48E5-A878-406FA0A5B296}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {7C93C84F-105C-48E5-A878-406FA0A5B296}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {7C93C84F-105C-48E5-A878-406FA0A5B296}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/tests/MediaBrowser.Api.Tests/BrandingServiceTests.cs b/tests/Jellyfin.Api.Tests/BrandingServiceTests.cs
index 5d7f7765c..6fc287420 100644
--- a/tests/MediaBrowser.Api.Tests/BrandingServiceTests.cs
+++ b/tests/Jellyfin.Api.Tests/BrandingServiceTests.cs
@@ -3,7 +3,7 @@ using System.Threading.Tasks;
using MediaBrowser.Model.Branding;
using Xunit;
-namespace MediaBrowser.Api.Tests
+namespace Jellyfin.Api.Tests
{
public sealed class BrandingServiceTests : IClassFixture<JellyfinApplicationFactory>
{
diff --git a/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj b/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj
index 368b6bf0b..bcba3a203 100644
--- a/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj
+++ b/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj
@@ -16,6 +16,7 @@
<PackageReference Include="AutoFixture" Version="4.13.0" />
<PackageReference Include="AutoFixture.AutoMoq" Version="4.13.0" />
<PackageReference Include="AutoFixture.Xunit2" Version="4.13.0" />
+ <PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="3.1.7" />
<PackageReference Include="Microsoft.Extensions.Options" Version="3.1.7" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" />
<PackageReference Include="xunit" Version="2.4.1" />
diff --git a/tests/MediaBrowser.Api.Tests/JellyfinApplicationFactory.cs b/tests/Jellyfin.Api.Tests/JellyfinApplicationFactory.cs
index 2029f88e9..77f1640fa 100644
--- a/tests/MediaBrowser.Api.Tests/JellyfinApplicationFactory.cs
+++ b/tests/Jellyfin.Api.Tests/JellyfinApplicationFactory.cs
@@ -15,7 +15,7 @@ using Microsoft.Extensions.Logging;
using Serilog;
using Serilog.Extensions.Logging;
-namespace MediaBrowser.Api.Tests
+namespace Jellyfin.Api.Tests
{
/// <summary>
/// Factory for bootstrapping the Jellyfin application in memory for functional end to end tests.
diff --git a/tests/Jellyfin.Api.Tests/OpenApiSpecTests.cs b/tests/Jellyfin.Api.Tests/OpenApiSpecTests.cs
new file mode 100644
index 000000000..3a85b5514
--- /dev/null
+++ b/tests/Jellyfin.Api.Tests/OpenApiSpecTests.cs
@@ -0,0 +1,42 @@
+using System.IO;
+using System.Reflection;
+using System.Text.Json;
+using System.Threading.Tasks;
+using MediaBrowser.Model.Branding;
+using Xunit;
+using Xunit.Abstractions;
+
+namespace Jellyfin.Api.Tests
+{
+ public sealed class OpenApiSpecTests : IClassFixture<JellyfinApplicationFactory>
+ {
+ private readonly JellyfinApplicationFactory _factory;
+ private readonly ITestOutputHelper _outputHelper;
+
+ public OpenApiSpecTests(JellyfinApplicationFactory factory, ITestOutputHelper outputHelper)
+ {
+ _factory = factory;
+ _outputHelper = outputHelper;
+ }
+
+ [Fact]
+ public async Task GetSpec_ReturnsCorrectResponse()
+ {
+ // Arrange
+ var client = _factory.CreateClient();
+
+ // Act
+ var response = await client.GetAsync("/api-docs/openapi.json");
+
+ // Assert
+ response.EnsureSuccessStatusCode();
+ Assert.Equal("application/json; charset=utf-8", response.Content.Headers.ContentType.ToString());
+
+ // Write out for publishing
+ var responseBody = await response.Content.ReadAsStringAsync();
+ string outputPath = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) ?? ".", "openapi.json"));
+ _outputHelper.WriteLine("Writing OpenAPI Spec JSON to '{0}'.", outputPath);
+ File.WriteAllText(outputPath, responseBody);
+ }
+ }
+}
diff --git a/tests/MediaBrowser.Api.Tests/MediaBrowser.Api.Tests.csproj b/tests/MediaBrowser.Api.Tests/MediaBrowser.Api.Tests.csproj
deleted file mode 100644
index b3fd853e2..000000000
--- a/tests/MediaBrowser.Api.Tests/MediaBrowser.Api.Tests.csproj
+++ /dev/null
@@ -1,34 +0,0 @@
-<Project Sdk="Microsoft.NET.Sdk">
-
- <PropertyGroup>
- <TargetFramework>netcoreapp3.1</TargetFramework>
- <IsPackable>false</IsPackable>
- <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
- <Nullable>enable</Nullable>
- </PropertyGroup>
-
- <ItemGroup>
- <PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="3.1.7" />
- <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" />
- <PackageReference Include="xunit" Version="2.4.1" />
- <PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" />
- <PackageReference Include="coverlet.collector" Version="1.3.0" />
- </ItemGroup>
-
- <ItemGroup>
- <ProjectReference Include="..\..\Jellyfin.Server\Jellyfin.Server.csproj" />
- </ItemGroup>
-
- <!-- Code Analyzers -->
- <ItemGroup Condition=" '$(Configuration)' == 'Debug' ">
- <PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.9.8" PrivateAssets="All" />
- <PackageReference Include="SerilogAnalyzer" Version="0.15.0" PrivateAssets="All" />
- <PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="All" />
- <PackageReference Include="SmartAnalyzers.MultithreadingAnalyzer" Version="1.1.31" PrivateAssets="All" />
- </ItemGroup>
-
- <PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
- <CodeAnalysisRuleSet>../jellyfin-tests.ruleset</CodeAnalysisRuleSet>
- </PropertyGroup>
-
-</Project>
diff --git a/tests/jellyfin-tests.ruleset b/tests/jellyfin-tests.ruleset
index 5a113e955..e2abaf5bb 100644
--- a/tests/jellyfin-tests.ruleset
+++ b/tests/jellyfin-tests.ruleset
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<RuleSet Name="Rules for MediaBrowser.Api.Tests" Description="Code analysis rules for MediaBrowser.Api.Tests.csproj" ToolsVersion="14.0">
+<RuleSet Name="Rules for Jellyfin.Api.Tests" Description="Code analysis rules for Jellyfin.Api.Tests.csproj" ToolsVersion="14.0">
<!-- Include the solution default RuleSet. The rules in this file will override the defaults. -->
<Include Path="../jellyfin.ruleset" Action="Default" />
@@ -17,6 +17,6 @@
<!-- CA2007: Consider calling ConfigureAwait on the awaited task -->
<Rule Id="CA2007" Action="None" />
<!-- CA2234: Pass system uri objects instead of strings -->
- <Rule Id="CA2234" Action="Info" />
+ <Rule Id="CA2234" Action="Info" />
</Rules>
</RuleSet>