mirror of
https://github.com/jellyfin/jellyfin.git
synced 2025-07-09 03:04:24 -04:00
Merge branch 'master' into fix-resharper-warnings
# Conflicts: # Emby.Server.Implementations/Updates/InstallationManager.cs # tests/Jellyfin.Server.Integration.Tests/OpenApiSpecTests.cs
This commit is contained in:
commit
38d962242a
@ -86,8 +86,8 @@
|
|||||||
<PackageVersion Include="TMDbLib" Version="2.0.0" />
|
<PackageVersion Include="TMDbLib" Version="2.0.0" />
|
||||||
<PackageVersion Include="UTF.Unknown" Version="2.5.1" />
|
<PackageVersion Include="UTF.Unknown" Version="2.5.1" />
|
||||||
<PackageVersion Include="Xunit.Priority" Version="1.1.6" />
|
<PackageVersion Include="Xunit.Priority" Version="1.1.6" />
|
||||||
<PackageVersion Include="xunit.runner.visualstudio" Version="2.5.1" />
|
<PackageVersion Include="xunit.runner.visualstudio" Version="2.5.3" />
|
||||||
<PackageVersion Include="Xunit.SkippableFact" Version="1.4.13" />
|
<PackageVersion Include="Xunit.SkippableFact" Version="1.4.13" />
|
||||||
<PackageVersion Include="xunit" Version="2.5.1" />
|
<PackageVersion Include="xunit" Version="2.5.2" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
69
Emby.Dlna/Extensions/DlnaServiceCollectionExtensions.cs
Normal file
69
Emby.Dlna/Extensions/DlnaServiceCollectionExtensions.cs
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
using System;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Net;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Text;
|
||||||
|
using Emby.Dlna.ConnectionManager;
|
||||||
|
using Emby.Dlna.ContentDirectory;
|
||||||
|
using Emby.Dlna.MediaReceiverRegistrar;
|
||||||
|
using Emby.Dlna.Ssdp;
|
||||||
|
using MediaBrowser.Common.Net;
|
||||||
|
using MediaBrowser.Controller;
|
||||||
|
using MediaBrowser.Controller.Dlna;
|
||||||
|
using MediaBrowser.Model.Dlna;
|
||||||
|
using MediaBrowser.Model.Net;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Rssdp.Infrastructure;
|
||||||
|
|
||||||
|
namespace Emby.Dlna.Extensions;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Extension methods for adding DLNA services.
|
||||||
|
/// </summary>
|
||||||
|
public static class DlnaServiceCollectionExtensions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Adds DLNA services to the provided <see cref="IServiceCollection"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="services">The <see cref="IServiceCollection"/>.</param>
|
||||||
|
/// <param name="applicationHost">The <see cref="IServerApplicationHost"/>.</param>
|
||||||
|
public static void AddDlnaServices(
|
||||||
|
this IServiceCollection services,
|
||||||
|
IServerApplicationHost applicationHost)
|
||||||
|
{
|
||||||
|
services.AddHttpClient(NamedClient.Dlna, c =>
|
||||||
|
{
|
||||||
|
c.DefaultRequestHeaders.UserAgent.ParseAdd(
|
||||||
|
string.Format(
|
||||||
|
CultureInfo.InvariantCulture,
|
||||||
|
"{0}/{1} UPnP/1.0 {2}/{3}",
|
||||||
|
Environment.OSVersion.Platform,
|
||||||
|
Environment.OSVersion,
|
||||||
|
applicationHost.Name,
|
||||||
|
applicationHost.ApplicationVersionString));
|
||||||
|
|
||||||
|
c.DefaultRequestHeaders.Add("CPFN.UPNP.ORG", applicationHost.FriendlyName); // Required for UPnP DeviceArchitecture v2.0
|
||||||
|
c.DefaultRequestHeaders.Add("FriendlyName.DLNA.ORG", applicationHost.FriendlyName); // REVIEW: where does this come from?
|
||||||
|
})
|
||||||
|
.ConfigurePrimaryHttpMessageHandler(_ => new SocketsHttpHandler
|
||||||
|
{
|
||||||
|
AutomaticDecompression = DecompressionMethods.All,
|
||||||
|
RequestHeaderEncodingSelector = (_, _) => Encoding.UTF8
|
||||||
|
});
|
||||||
|
|
||||||
|
services.AddSingleton<IDlnaManager, DlnaManager>();
|
||||||
|
services.AddSingleton<IDeviceDiscovery, DeviceDiscovery>();
|
||||||
|
services.AddSingleton<IContentDirectory, ContentDirectoryService>();
|
||||||
|
services.AddSingleton<IConnectionManager, ConnectionManagerService>();
|
||||||
|
services.AddSingleton<IMediaReceiverRegistrar, MediaReceiverRegistrarService>();
|
||||||
|
|
||||||
|
services.AddSingleton<ISsdpCommunicationsServer>(provider => new SsdpCommunicationsServer(
|
||||||
|
provider.GetRequiredService<ISocketFactory>(),
|
||||||
|
provider.GetRequiredService<INetworkManager>(),
|
||||||
|
provider.GetRequiredService<ILogger<SsdpCommunicationsServer>>())
|
||||||
|
{
|
||||||
|
IsShared = true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -23,10 +23,8 @@ using MediaBrowser.Controller.Library;
|
|||||||
using MediaBrowser.Controller.MediaEncoding;
|
using MediaBrowser.Controller.MediaEncoding;
|
||||||
using MediaBrowser.Controller.Plugins;
|
using MediaBrowser.Controller.Plugins;
|
||||||
using MediaBrowser.Controller.Session;
|
using MediaBrowser.Controller.Session;
|
||||||
using MediaBrowser.Controller.TV;
|
|
||||||
using MediaBrowser.Model.Dlna;
|
using MediaBrowser.Model.Dlna;
|
||||||
using MediaBrowser.Model.Globalization;
|
using MediaBrowser.Model.Globalization;
|
||||||
using MediaBrowser.Model.Net;
|
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Rssdp;
|
using Rssdp;
|
||||||
using Rssdp.Infrastructure;
|
using Rssdp.Infrastructure;
|
||||||
@ -49,14 +47,13 @@ namespace Emby.Dlna.Main
|
|||||||
private readonly IMediaSourceManager _mediaSourceManager;
|
private readonly IMediaSourceManager _mediaSourceManager;
|
||||||
private readonly IMediaEncoder _mediaEncoder;
|
private readonly IMediaEncoder _mediaEncoder;
|
||||||
private readonly IDeviceDiscovery _deviceDiscovery;
|
private readonly IDeviceDiscovery _deviceDiscovery;
|
||||||
private readonly ISocketFactory _socketFactory;
|
private readonly ISsdpCommunicationsServer _communicationsServer;
|
||||||
private readonly INetworkManager _networkManager;
|
private readonly INetworkManager _networkManager;
|
||||||
private readonly object _syncLock = new object();
|
private readonly object _syncLock = new();
|
||||||
private readonly bool _disabled;
|
private readonly bool _disabled;
|
||||||
|
|
||||||
private PlayToManager _manager;
|
private PlayToManager _manager;
|
||||||
private SsdpDevicePublisher _publisher;
|
private SsdpDevicePublisher _publisher;
|
||||||
private ISsdpCommunicationsServer _communicationsServer;
|
|
||||||
|
|
||||||
private bool _disposed;
|
private bool _disposed;
|
||||||
|
|
||||||
@ -75,10 +72,8 @@ namespace Emby.Dlna.Main
|
|||||||
IMediaSourceManager mediaSourceManager,
|
IMediaSourceManager mediaSourceManager,
|
||||||
IDeviceDiscovery deviceDiscovery,
|
IDeviceDiscovery deviceDiscovery,
|
||||||
IMediaEncoder mediaEncoder,
|
IMediaEncoder mediaEncoder,
|
||||||
ISocketFactory socketFactory,
|
ISsdpCommunicationsServer communicationsServer,
|
||||||
INetworkManager networkManager,
|
INetworkManager networkManager)
|
||||||
IUserViewManager userViewManager,
|
|
||||||
ITVSeriesManager tvSeriesManager)
|
|
||||||
{
|
{
|
||||||
_config = config;
|
_config = config;
|
||||||
_appHost = appHost;
|
_appHost = appHost;
|
||||||
@ -93,37 +88,10 @@ namespace Emby.Dlna.Main
|
|||||||
_mediaSourceManager = mediaSourceManager;
|
_mediaSourceManager = mediaSourceManager;
|
||||||
_deviceDiscovery = deviceDiscovery;
|
_deviceDiscovery = deviceDiscovery;
|
||||||
_mediaEncoder = mediaEncoder;
|
_mediaEncoder = mediaEncoder;
|
||||||
_socketFactory = socketFactory;
|
_communicationsServer = communicationsServer;
|
||||||
_networkManager = networkManager;
|
_networkManager = networkManager;
|
||||||
_logger = loggerFactory.CreateLogger<DlnaEntryPoint>();
|
_logger = loggerFactory.CreateLogger<DlnaEntryPoint>();
|
||||||
|
|
||||||
ContentDirectory = new ContentDirectory.ContentDirectoryService(
|
|
||||||
dlnaManager,
|
|
||||||
userDataManager,
|
|
||||||
imageProcessor,
|
|
||||||
libraryManager,
|
|
||||||
config,
|
|
||||||
userManager,
|
|
||||||
loggerFactory.CreateLogger<ContentDirectory.ContentDirectoryService>(),
|
|
||||||
httpClientFactory,
|
|
||||||
localizationManager,
|
|
||||||
mediaSourceManager,
|
|
||||||
userViewManager,
|
|
||||||
mediaEncoder,
|
|
||||||
tvSeriesManager);
|
|
||||||
|
|
||||||
ConnectionManager = new ConnectionManager.ConnectionManagerService(
|
|
||||||
dlnaManager,
|
|
||||||
config,
|
|
||||||
loggerFactory.CreateLogger<ConnectionManager.ConnectionManagerService>(),
|
|
||||||
httpClientFactory);
|
|
||||||
|
|
||||||
MediaReceiverRegistrar = new MediaReceiverRegistrar.MediaReceiverRegistrarService(
|
|
||||||
loggerFactory.CreateLogger<MediaReceiverRegistrar.MediaReceiverRegistrarService>(),
|
|
||||||
httpClientFactory,
|
|
||||||
config);
|
|
||||||
Current = this;
|
|
||||||
|
|
||||||
var netConfig = config.GetConfiguration<NetworkConfiguration>(NetworkConfigurationStore.StoreKey);
|
var netConfig = config.GetConfiguration<NetworkConfiguration>(NetworkConfigurationStore.StoreKey);
|
||||||
_disabled = appHost.ListenWithHttps && netConfig.RequireHttps;
|
_disabled = appHost.ListenWithHttps && netConfig.RequireHttps;
|
||||||
|
|
||||||
@ -133,19 +101,6 @@ namespace Emby.Dlna.Main
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static DlnaEntryPoint Current { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a value indicating whether the dlna server is enabled.
|
|
||||||
/// </summary>
|
|
||||||
public static bool Enabled { get; private set; }
|
|
||||||
|
|
||||||
public IContentDirectory ContentDirectory { get; private set; }
|
|
||||||
|
|
||||||
public IConnectionManager ConnectionManager { get; private set; }
|
|
||||||
|
|
||||||
public IMediaReceiverRegistrar MediaReceiverRegistrar { get; private set; }
|
|
||||||
|
|
||||||
public async Task RunAsync()
|
public async Task RunAsync()
|
||||||
{
|
{
|
||||||
await ((DlnaManager)_dlnaManager).InitProfilesAsync().ConfigureAwait(false);
|
await ((DlnaManager)_dlnaManager).InitProfilesAsync().ConfigureAwait(false);
|
||||||
@ -172,9 +127,7 @@ namespace Emby.Dlna.Main
|
|||||||
private void ReloadComponents()
|
private void ReloadComponents()
|
||||||
{
|
{
|
||||||
var options = _config.GetDlnaConfiguration();
|
var options = _config.GetDlnaConfiguration();
|
||||||
Enabled = options.EnableServer;
|
StartDeviceDiscovery();
|
||||||
|
|
||||||
StartSsdpHandler();
|
|
||||||
|
|
||||||
if (options.EnableServer)
|
if (options.EnableServer)
|
||||||
{
|
{
|
||||||
@ -195,37 +148,11 @@ namespace Emby.Dlna.Main
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void StartSsdpHandler()
|
private void StartDeviceDiscovery()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (_communicationsServer is null)
|
((DeviceDiscovery)_deviceDiscovery).Start(_communicationsServer);
|
||||||
{
|
|
||||||
_communicationsServer = new SsdpCommunicationsServer(
|
|
||||||
_socketFactory,
|
|
||||||
_networkManager,
|
|
||||||
_logger)
|
|
||||||
{
|
|
||||||
IsShared = true
|
|
||||||
};
|
|
||||||
|
|
||||||
StartDeviceDiscovery(_communicationsServer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_logger.LogError(ex, "Error starting SSDP handlers");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void StartDeviceDiscovery(ISsdpCommunicationsServer communicationsServer)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (communicationsServer is not null)
|
|
||||||
{
|
|
||||||
((DeviceDiscovery)_deviceDiscovery).Start(communicationsServer);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@ -233,19 +160,6 @@ namespace Emby.Dlna.Main
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DisposeDeviceDiscovery()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
_logger.LogInformation("Disposing DeviceDiscovery");
|
|
||||||
((DeviceDiscovery)_deviceDiscovery).Dispose();
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_logger.LogError(ex, "Error stopping device discovery");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void StartDevicePublisher(Configuration.DlnaOptions options)
|
public void StartDevicePublisher(Configuration.DlnaOptions options)
|
||||||
{
|
{
|
||||||
if (_publisher is not null)
|
if (_publisher is not null)
|
||||||
@ -318,7 +232,7 @@ namespace Emby.Dlna.Main
|
|||||||
// This must be a globally unique value that survives reboots etc. Get from storage or embedded hardware etc.
|
// This must be a globally unique value that survives reboots etc. Get from storage or embedded hardware etc.
|
||||||
};
|
};
|
||||||
|
|
||||||
SetProperies(device, fullService);
|
SetProperties(device, fullService);
|
||||||
_publisher.AddDevice(device);
|
_publisher.AddDevice(device);
|
||||||
|
|
||||||
var embeddedDevices = new[]
|
var embeddedDevices = new[]
|
||||||
@ -339,13 +253,13 @@ namespace Emby.Dlna.Main
|
|||||||
// This must be a globally unique value that survives reboots etc. Get from storage or embedded hardware etc.
|
// This must be a globally unique value that survives reboots etc. Get from storage or embedded hardware etc.
|
||||||
};
|
};
|
||||||
|
|
||||||
SetProperies(embeddedDevice, subDevice);
|
SetProperties(embeddedDevice, subDevice);
|
||||||
device.AddDevice(embeddedDevice);
|
device.AddDevice(embeddedDevice);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private string CreateUuid(string text)
|
private static string CreateUuid(string text)
|
||||||
{
|
{
|
||||||
if (!Guid.TryParse(text, out var guid))
|
if (!Guid.TryParse(text, out var guid))
|
||||||
{
|
{
|
||||||
@ -355,15 +269,14 @@ namespace Emby.Dlna.Main
|
|||||||
return guid.ToString("D", CultureInfo.InvariantCulture);
|
return guid.ToString("D", CultureInfo.InvariantCulture);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetProperies(SsdpDevice device, string fullDeviceType)
|
private static void SetProperties(SsdpDevice device, string fullDeviceType)
|
||||||
{
|
{
|
||||||
var service = fullDeviceType.Replace("urn:", string.Empty, StringComparison.OrdinalIgnoreCase).Replace(":1", string.Empty, StringComparison.OrdinalIgnoreCase);
|
var serviceParts = fullDeviceType
|
||||||
|
.Replace("urn:", string.Empty, StringComparison.OrdinalIgnoreCase)
|
||||||
|
.Replace(":1", string.Empty, StringComparison.OrdinalIgnoreCase)
|
||||||
|
.Split(':');
|
||||||
|
|
||||||
var serviceParts = service.Split(':');
|
device.DeviceTypeNamespace = serviceParts[0].Replace('.', '-');
|
||||||
|
|
||||||
var deviceTypeNamespace = serviceParts[0].Replace('.', '-');
|
|
||||||
|
|
||||||
device.DeviceTypeNamespace = deviceTypeNamespace;
|
|
||||||
device.DeviceClass = serviceParts[1];
|
device.DeviceClass = serviceParts[1];
|
||||||
device.DeviceType = serviceParts[2];
|
device.DeviceType = serviceParts[2];
|
||||||
}
|
}
|
||||||
@ -444,20 +357,6 @@ namespace Emby.Dlna.Main
|
|||||||
|
|
||||||
DisposeDevicePublisher();
|
DisposeDevicePublisher();
|
||||||
DisposePlayToManager();
|
DisposePlayToManager();
|
||||||
DisposeDeviceDiscovery();
|
|
||||||
|
|
||||||
if (_communicationsServer is not null)
|
|
||||||
{
|
|
||||||
_logger.LogInformation("Disposing SsdpCommunicationsServer");
|
|
||||||
_communicationsServer.Dispose();
|
|
||||||
_communicationsServer = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
ContentDirectory = null;
|
|
||||||
ConnectionManager = null;
|
|
||||||
MediaReceiverRegistrar = null;
|
|
||||||
Current = null;
|
|
||||||
|
|
||||||
_disposed = true;
|
_disposed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -55,41 +55,42 @@ namespace Emby.Dlna.PlayTo
|
|||||||
var client = _httpClientFactory.CreateClient(NamedClient.Dlna);
|
var client = _httpClientFactory.CreateClient(NamedClient.Dlna);
|
||||||
using var response = await client.SendAsync(request, cancellationToken).ConfigureAwait(false);
|
using var response = await client.SendAsync(request, cancellationToken).ConfigureAwait(false);
|
||||||
response.EnsureSuccessStatusCode();
|
response.EnsureSuccessStatusCode();
|
||||||
await using MemoryStream ms = new MemoryStream();
|
Stream stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false);
|
||||||
await response.Content.CopyToAsync(ms, cancellationToken).ConfigureAwait(false);
|
await using (stream.ConfigureAwait(false))
|
||||||
ms.Position = 0;
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
return await XDocument.LoadAsync(
|
|
||||||
ms,
|
|
||||||
LoadOptions.None,
|
|
||||||
cancellationToken).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
catch (XmlException)
|
|
||||||
{
|
|
||||||
// try correcting the Xml response with common errors
|
|
||||||
ms.Position = 0;
|
|
||||||
using StreamReader sr = new StreamReader(ms);
|
|
||||||
var xmlString = await sr.ReadToEndAsync(cancellationToken).ConfigureAwait(false);
|
|
||||||
|
|
||||||
// find and replace unescaped ampersands (&)
|
|
||||||
xmlString = EscapeAmpersandRegex().Replace(xmlString, "&");
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// retry reading Xml
|
|
||||||
using var xmlReader = new StringReader(xmlString);
|
|
||||||
return await XDocument.LoadAsync(
|
return await XDocument.LoadAsync(
|
||||||
xmlReader,
|
stream,
|
||||||
LoadOptions.None,
|
LoadOptions.None,
|
||||||
cancellationToken).ConfigureAwait(false);
|
cancellationToken).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch (XmlException ex)
|
catch (XmlException)
|
||||||
{
|
{
|
||||||
_logger.LogError(ex, "Failed to parse response");
|
// try correcting the Xml response with common errors
|
||||||
_logger.LogDebug("Malformed response: {Content}\n", xmlString);
|
stream.Position = 0;
|
||||||
|
using StreamReader sr = new StreamReader(stream);
|
||||||
|
var xmlString = await sr.ReadToEndAsync(cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
return null;
|
// find and replace unescaped ampersands (&)
|
||||||
|
xmlString = EscapeAmpersandRegex().Replace(xmlString, "&");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// retry reading Xml
|
||||||
|
using var xmlReader = new StringReader(xmlString);
|
||||||
|
return await XDocument.LoadAsync(
|
||||||
|
xmlReader,
|
||||||
|
LoadOptions.None,
|
||||||
|
cancellationToken).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
catch (XmlException ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "Failed to parse response");
|
||||||
|
_logger.LogDebug("Malformed response: {Content}\n", xmlString);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,9 +13,7 @@ using System.Net;
|
|||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Security.Cryptography.X509Certificates;
|
using System.Security.Cryptography.X509Certificates;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Emby.Dlna;
|
|
||||||
using Emby.Dlna.Main;
|
using Emby.Dlna.Main;
|
||||||
using Emby.Dlna.Ssdp;
|
|
||||||
using Emby.Naming.Common;
|
using Emby.Naming.Common;
|
||||||
using Emby.Photos;
|
using Emby.Photos;
|
||||||
using Emby.Server.Implementations.Channels;
|
using Emby.Server.Implementations.Channels;
|
||||||
@ -58,7 +56,6 @@ using MediaBrowser.Controller.Chapters;
|
|||||||
using MediaBrowser.Controller.ClientEvent;
|
using MediaBrowser.Controller.ClientEvent;
|
||||||
using MediaBrowser.Controller.Collections;
|
using MediaBrowser.Controller.Collections;
|
||||||
using MediaBrowser.Controller.Configuration;
|
using MediaBrowser.Controller.Configuration;
|
||||||
using MediaBrowser.Controller.Dlna;
|
|
||||||
using MediaBrowser.Controller.Drawing;
|
using MediaBrowser.Controller.Drawing;
|
||||||
using MediaBrowser.Controller.Dto;
|
using MediaBrowser.Controller.Dto;
|
||||||
using MediaBrowser.Controller.Entities;
|
using MediaBrowser.Controller.Entities;
|
||||||
@ -82,7 +79,6 @@ using MediaBrowser.LocalMetadata.Savers;
|
|||||||
using MediaBrowser.MediaEncoding.BdInfo;
|
using MediaBrowser.MediaEncoding.BdInfo;
|
||||||
using MediaBrowser.MediaEncoding.Subtitles;
|
using MediaBrowser.MediaEncoding.Subtitles;
|
||||||
using MediaBrowser.Model.Cryptography;
|
using MediaBrowser.Model.Cryptography;
|
||||||
using MediaBrowser.Model.Dlna;
|
|
||||||
using MediaBrowser.Model.Globalization;
|
using MediaBrowser.Model.Globalization;
|
||||||
using MediaBrowser.Model.IO;
|
using MediaBrowser.Model.IO;
|
||||||
using MediaBrowser.Model.MediaInfo;
|
using MediaBrowser.Model.MediaInfo;
|
||||||
@ -563,8 +559,6 @@ namespace Emby.Server.Implementations
|
|||||||
|
|
||||||
serviceCollection.AddSingleton<ISessionManager, SessionManager>();
|
serviceCollection.AddSingleton<ISessionManager, SessionManager>();
|
||||||
|
|
||||||
serviceCollection.AddSingleton<IDlnaManager, DlnaManager>();
|
|
||||||
|
|
||||||
serviceCollection.AddSingleton<ICollectionManager, CollectionManager>();
|
serviceCollection.AddSingleton<ICollectionManager, CollectionManager>();
|
||||||
|
|
||||||
serviceCollection.AddSingleton<IPlaylistManager, PlaylistManager>();
|
serviceCollection.AddSingleton<IPlaylistManager, PlaylistManager>();
|
||||||
@ -576,8 +570,6 @@ namespace Emby.Server.Implementations
|
|||||||
|
|
||||||
serviceCollection.AddSingleton<IUserViewManager, UserViewManager>();
|
serviceCollection.AddSingleton<IUserViewManager, UserViewManager>();
|
||||||
|
|
||||||
serviceCollection.AddSingleton<IDeviceDiscovery, DeviceDiscovery>();
|
|
||||||
|
|
||||||
serviceCollection.AddSingleton<IChapterManager, ChapterManager>();
|
serviceCollection.AddSingleton<IChapterManager, ChapterManager>();
|
||||||
|
|
||||||
serviceCollection.AddSingleton<IEncodingManager, MediaEncoder.EncodingManager>();
|
serviceCollection.AddSingleton<IEncodingManager, MediaEncoder.EncodingManager>();
|
||||||
|
@ -371,8 +371,11 @@ namespace Emby.Server.Implementations.Channels
|
|||||||
|
|
||||||
Directory.CreateDirectory(Path.GetDirectoryName(path));
|
Directory.CreateDirectory(Path.GetDirectoryName(path));
|
||||||
|
|
||||||
await using FileStream createStream = File.Create(path);
|
FileStream createStream = File.Create(path);
|
||||||
await JsonSerializer.SerializeAsync(createStream, mediaSources, _jsonOptions).ConfigureAwait(false);
|
await using (createStream.ConfigureAwait(false))
|
||||||
|
{
|
||||||
|
await JsonSerializer.SerializeAsync(createStream, mediaSources, _jsonOptions).ConfigureAwait(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
@ -43,8 +43,6 @@
|
|||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net7.0</TargetFramework>
|
||||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
<!-- https://github.com/microsoft/ApplicationInsights-dotnet/issues/2047 -->
|
|
||||||
<NoWarn>AD0001</NoWarn>
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
|
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
|
||||||
|
@ -48,15 +48,20 @@ namespace Emby.Server.Implementations.Library
|
|||||||
|
|
||||||
if (!string.IsNullOrEmpty(cacheKey))
|
if (!string.IsNullOrEmpty(cacheKey))
|
||||||
{
|
{
|
||||||
|
FileStream jsonStream = AsyncFile.OpenRead(cacheFilePath);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await using FileStream jsonStream = AsyncFile.OpenRead(cacheFilePath);
|
|
||||||
mediaInfo = await JsonSerializer.DeserializeAsync<MediaInfo>(jsonStream, _jsonOptions, cancellationToken).ConfigureAwait(false);
|
mediaInfo = await JsonSerializer.DeserializeAsync<MediaInfo>(jsonStream, _jsonOptions, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
// _logger.LogDebug("Found cached media info");
|
// _logger.LogDebug("Found cached media info");
|
||||||
}
|
}
|
||||||
catch
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
_logger.LogError(ex, "Error deserializing mediainfo cache");
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
await jsonStream.DisposeAsync().ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,10 +89,13 @@ namespace Emby.Server.Implementations.Library
|
|||||||
if (cacheFilePath is not null)
|
if (cacheFilePath is not null)
|
||||||
{
|
{
|
||||||
Directory.CreateDirectory(Path.GetDirectoryName(cacheFilePath));
|
Directory.CreateDirectory(Path.GetDirectoryName(cacheFilePath));
|
||||||
await using FileStream createStream = AsyncFile.OpenWrite(cacheFilePath);
|
FileStream createStream = AsyncFile.OpenWrite(cacheFilePath);
|
||||||
await JsonSerializer.SerializeAsync(createStream, mediaInfo, _jsonOptions, cancellationToken).ConfigureAwait(false);
|
await using (createStream.ConfigureAwait(false))
|
||||||
|
{
|
||||||
|
await JsonSerializer.SerializeAsync(createStream, mediaInfo, _jsonOptions, cancellationToken).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
// _logger.LogDebug("Saved media info to {0}", cacheFilePath);
|
_logger.LogDebug("Saved media info to {0}", cacheFilePath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -625,17 +625,19 @@ namespace Emby.Server.Implementations.Library
|
|||||||
|
|
||||||
if (!string.IsNullOrEmpty(cacheKey))
|
if (!string.IsNullOrEmpty(cacheKey))
|
||||||
{
|
{
|
||||||
|
FileStream jsonStream = AsyncFile.OpenRead(cacheFilePath);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await using FileStream jsonStream = AsyncFile.OpenRead(cacheFilePath);
|
|
||||||
mediaInfo = await JsonSerializer.DeserializeAsync<MediaInfo>(jsonStream, _jsonOptions, cancellationToken).ConfigureAwait(false);
|
mediaInfo = await JsonSerializer.DeserializeAsync<MediaInfo>(jsonStream, _jsonOptions, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
// _logger.LogDebug("Found cached media info");
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
_logger.LogDebug(ex, "_jsonSerializer.DeserializeFromFile threw an exception.");
|
_logger.LogDebug(ex, "_jsonSerializer.DeserializeFromFile threw an exception.");
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
await jsonStream.DisposeAsync().ConfigureAwait(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mediaInfo is null)
|
if (mediaInfo is null)
|
||||||
@ -664,8 +666,11 @@ namespace Emby.Server.Implementations.Library
|
|||||||
if (cacheFilePath is not null)
|
if (cacheFilePath is not null)
|
||||||
{
|
{
|
||||||
Directory.CreateDirectory(Path.GetDirectoryName(cacheFilePath));
|
Directory.CreateDirectory(Path.GetDirectoryName(cacheFilePath));
|
||||||
await using FileStream createStream = File.Create(cacheFilePath);
|
FileStream createStream = File.Create(cacheFilePath);
|
||||||
await JsonSerializer.SerializeAsync(createStream, mediaInfo, _jsonOptions, cancellationToken).ConfigureAwait(false);
|
await using (createStream.ConfigureAwait(false))
|
||||||
|
{
|
||||||
|
await JsonSerializer.SerializeAsync(createStream, mediaInfo, _jsonOptions, cancellationToken).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
// _logger.LogDebug("Saved media info to {0}", cacheFilePath);
|
// _logger.LogDebug("Saved media info to {0}", cacheFilePath);
|
||||||
}
|
}
|
||||||
|
@ -1851,7 +1851,8 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await using (var stream = new FileStream(nfoPath, FileMode.CreateNew, FileAccess.Write, FileShare.None))
|
var stream = new FileStream(nfoPath, FileMode.CreateNew, FileAccess.Write, FileShare.None);
|
||||||
|
await using (stream.ConfigureAwait(false))
|
||||||
{
|
{
|
||||||
var settings = new XmlWriterSettings
|
var settings = new XmlWriterSettings
|
||||||
{
|
{
|
||||||
@ -1860,7 +1861,8 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
|
|||||||
Async = true
|
Async = true
|
||||||
};
|
};
|
||||||
|
|
||||||
await using (var writer = XmlWriter.Create(stream, settings))
|
var writer = XmlWriter.Create(stream, settings);
|
||||||
|
await using (writer.ConfigureAwait(false))
|
||||||
{
|
{
|
||||||
await writer.WriteStartDocumentAsync(true).ConfigureAwait(false);
|
await writer.WriteStartDocumentAsync(true).ConfigureAwait(false);
|
||||||
await writer.WriteStartElementAsync(null, "tvshow", null).ConfigureAwait(false);
|
await writer.WriteStartElementAsync(null, "tvshow", null).ConfigureAwait(false);
|
||||||
@ -1914,7 +1916,8 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await using (var stream = new FileStream(nfoPath, FileMode.CreateNew, FileAccess.Write, FileShare.None))
|
var stream = new FileStream(nfoPath, FileMode.CreateNew, FileAccess.Write, FileShare.None);
|
||||||
|
await using (stream.ConfigureAwait(false))
|
||||||
{
|
{
|
||||||
var settings = new XmlWriterSettings
|
var settings = new XmlWriterSettings
|
||||||
{
|
{
|
||||||
@ -1927,7 +1930,8 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
|
|||||||
|
|
||||||
var isSeriesEpisode = timer.IsProgramSeries;
|
var isSeriesEpisode = timer.IsProgramSeries;
|
||||||
|
|
||||||
await using (var writer = XmlWriter.Create(stream, settings))
|
var writer = XmlWriter.Create(stream, settings);
|
||||||
|
await using (writer.ConfigureAwait(false))
|
||||||
{
|
{
|
||||||
await writer.WriteStartDocumentAsync(true).ConfigureAwait(false);
|
await writer.WriteStartDocumentAsync(true).ConfigureAwait(false);
|
||||||
|
|
||||||
@ -1965,7 +1969,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
await writer.WriteStartElementAsync(null, "movie", null);
|
await writer.WriteStartElementAsync(null, "movie", null).ConfigureAwait(false);
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(item.Name))
|
if (!string.IsNullOrWhiteSpace(item.Name))
|
||||||
{
|
{
|
||||||
|
@ -106,8 +106,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
|
|||||||
options.Content = JsonContent.Create(requestList, options: _jsonOptions);
|
options.Content = JsonContent.Create(requestList, options: _jsonOptions);
|
||||||
options.Headers.TryAddWithoutValidation("token", token);
|
options.Headers.TryAddWithoutValidation("token", token);
|
||||||
using var response = await Send(options, true, info, cancellationToken).ConfigureAwait(false);
|
using var response = await Send(options, true, info, cancellationToken).ConfigureAwait(false);
|
||||||
await using var responseStream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false);
|
var dailySchedules = await response.Content.ReadFromJsonAsync<IReadOnlyList<DayDto>>(_jsonOptions, cancellationToken).ConfigureAwait(false);
|
||||||
var dailySchedules = await JsonSerializer.DeserializeAsync<IReadOnlyList<DayDto>>(responseStream, _jsonOptions, cancellationToken).ConfigureAwait(false);
|
|
||||||
if (dailySchedules is null)
|
if (dailySchedules is null)
|
||||||
{
|
{
|
||||||
return Array.Empty<ProgramInfo>();
|
return Array.Empty<ProgramInfo>();
|
||||||
@ -122,8 +121,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
|
|||||||
programRequestOptions.Content = JsonContent.Create(programIds, options: _jsonOptions);
|
programRequestOptions.Content = JsonContent.Create(programIds, options: _jsonOptions);
|
||||||
|
|
||||||
using var innerResponse = await Send(programRequestOptions, true, info, cancellationToken).ConfigureAwait(false);
|
using var innerResponse = await Send(programRequestOptions, true, info, cancellationToken).ConfigureAwait(false);
|
||||||
await using var innerResponseStream = await innerResponse.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false);
|
var programDetails = await innerResponse.Content.ReadFromJsonAsync<IReadOnlyList<ProgramDetailsDto>>(_jsonOptions, cancellationToken).ConfigureAwait(false);
|
||||||
var programDetails = await JsonSerializer.DeserializeAsync<IReadOnlyList<ProgramDetailsDto>>(innerResponseStream, _jsonOptions, cancellationToken).ConfigureAwait(false);
|
|
||||||
if (programDetails is null)
|
if (programDetails is null)
|
||||||
{
|
{
|
||||||
return Array.Empty<ProgramInfo>();
|
return Array.Empty<ProgramInfo>();
|
||||||
@ -482,8 +480,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
using var innerResponse2 = await Send(message, true, info, cancellationToken).ConfigureAwait(false);
|
using var innerResponse2 = await Send(message, true, info, cancellationToken).ConfigureAwait(false);
|
||||||
await using var response = await innerResponse2.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false);
|
return await innerResponse2.Content.ReadFromJsonAsync<IReadOnlyList<ShowImagesDto>>(_jsonOptions, cancellationToken).ConfigureAwait(false);
|
||||||
return await JsonSerializer.DeserializeAsync<IReadOnlyList<ShowImagesDto>>(response, _jsonOptions, cancellationToken).ConfigureAwait(false);
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@ -510,10 +507,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
using var httpResponse = await Send(options, false, info, cancellationToken).ConfigureAwait(false);
|
using var httpResponse = await Send(options, false, info, cancellationToken).ConfigureAwait(false);
|
||||||
await using var response = await httpResponse.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false);
|
var root = await httpResponse.Content.ReadFromJsonAsync<IReadOnlyList<HeadendsDto>>(_jsonOptions, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
var root = await JsonSerializer.DeserializeAsync<IReadOnlyList<HeadendsDto>>(response, _jsonOptions, cancellationToken).ConfigureAwait(false);
|
|
||||||
|
|
||||||
if (root is not null)
|
if (root is not null)
|
||||||
{
|
{
|
||||||
foreach (HeadendsDto headend in root)
|
foreach (HeadendsDto headend in root)
|
||||||
@ -649,8 +643,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
|
|||||||
|
|
||||||
using var response = await Send(options, false, null, cancellationToken).ConfigureAwait(false);
|
using var response = await Send(options, false, null, cancellationToken).ConfigureAwait(false);
|
||||||
response.EnsureSuccessStatusCode();
|
response.EnsureSuccessStatusCode();
|
||||||
await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false);
|
var root = await response.Content.ReadFromJsonAsync<TokenDto>(_jsonOptions, cancellationToken).ConfigureAwait(false);
|
||||||
var root = await JsonSerializer.DeserializeAsync<TokenDto>(stream, _jsonOptions, cancellationToken).ConfigureAwait(false);
|
|
||||||
if (string.Equals(root?.Message, "OK", StringComparison.Ordinal))
|
if (string.Equals(root?.Message, "OK", StringComparison.Ordinal))
|
||||||
{
|
{
|
||||||
_logger.LogInformation("Authenticated with Schedules Direct token: {Token}", root.Token);
|
_logger.LogInformation("Authenticated with Schedules Direct token: {Token}", root.Token);
|
||||||
@ -691,10 +684,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
|
|||||||
{
|
{
|
||||||
using var httpResponse = await Send(options, false, null, cancellationToken).ConfigureAwait(false);
|
using var httpResponse = await Send(options, false, null, cancellationToken).ConfigureAwait(false);
|
||||||
httpResponse.EnsureSuccessStatusCode();
|
httpResponse.EnsureSuccessStatusCode();
|
||||||
await using var stream = await httpResponse.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false);
|
var root = await httpResponse.Content.ReadFromJsonAsync<LineupsDto>(_jsonOptions, cancellationToken).ConfigureAwait(false);
|
||||||
using var response = httpResponse.Content;
|
|
||||||
var root = await JsonSerializer.DeserializeAsync<LineupsDto>(stream, _jsonOptions, cancellationToken).ConfigureAwait(false);
|
|
||||||
|
|
||||||
return root?.Lineups.Any(i => string.Equals(info.ListingsId, i.Lineup, StringComparison.OrdinalIgnoreCase)) ?? false;
|
return root?.Lineups.Any(i => string.Equals(info.ListingsId, i.Lineup, StringComparison.OrdinalIgnoreCase)) ?? false;
|
||||||
}
|
}
|
||||||
catch (HttpRequestException ex)
|
catch (HttpRequestException ex)
|
||||||
@ -748,8 +738,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
|
|||||||
options.Headers.TryAddWithoutValidation("token", token);
|
options.Headers.TryAddWithoutValidation("token", token);
|
||||||
|
|
||||||
using var httpResponse = await Send(options, true, info, cancellationToken).ConfigureAwait(false);
|
using var httpResponse = await Send(options, true, info, cancellationToken).ConfigureAwait(false);
|
||||||
await using var stream = await httpResponse.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false);
|
var root = await httpResponse.Content.ReadFromJsonAsync<ChannelDto>(_jsonOptions, cancellationToken).ConfigureAwait(false);
|
||||||
var root = await JsonSerializer.DeserializeAsync<ChannelDto>(stream, _jsonOptions, cancellationToken).ConfigureAwait(false);
|
|
||||||
if (root is null)
|
if (root is null)
|
||||||
{
|
{
|
||||||
return new List<ChannelInfo>();
|
return new List<ChannelInfo>();
|
||||||
|
@ -9,6 +9,7 @@ using System.IO;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
|
using System.Net.Http.Json;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@ -75,13 +76,10 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
|
|||||||
var model = await GetModelInfo(info, false, cancellationToken).ConfigureAwait(false);
|
var model = await GetModelInfo(info, false, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
using var response = await _httpClientFactory.CreateClient(NamedClient.Default).GetAsync(model.LineupURL ?? model.BaseURL + "/lineup.json", HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false);
|
using var response = await _httpClientFactory.CreateClient(NamedClient.Default).GetAsync(model.LineupURL ?? model.BaseURL + "/lineup.json", HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false);
|
||||||
await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false);
|
var lineup = await response.Content.ReadFromJsonAsync<IEnumerable<Channels>>(_jsonOptions, cancellationToken).ConfigureAwait(false) ?? Enumerable.Empty<Channels>();
|
||||||
var lineup = await JsonSerializer.DeserializeAsync<List<Channels>>(stream, _jsonOptions, cancellationToken)
|
|
||||||
.ConfigureAwait(false) ?? new List<Channels>();
|
|
||||||
|
|
||||||
if (info.ImportFavoritesOnly)
|
if (info.ImportFavoritesOnly)
|
||||||
{
|
{
|
||||||
lineup = lineup.Where(i => i.Favorite).ToList();
|
lineup = lineup.Where(i => i.Favorite);
|
||||||
}
|
}
|
||||||
|
|
||||||
return lineup.Where(i => !i.DRM).ToList();
|
return lineup.Where(i => !i.DRM).ToList();
|
||||||
@ -128,9 +126,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
|
|||||||
.GetAsync(GetApiUrl(info) + "/discover.json", HttpCompletionOption.ResponseHeadersRead, cancellationToken)
|
.GetAsync(GetApiUrl(info) + "/discover.json", HttpCompletionOption.ResponseHeadersRead, cancellationToken)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
response.EnsureSuccessStatusCode();
|
response.EnsureSuccessStatusCode();
|
||||||
await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false);
|
var discoverResponse = await response.Content.ReadFromJsonAsync<DiscoverResponse>(_jsonOptions, cancellationToken).ConfigureAwait(false);
|
||||||
var discoverResponse = await JsonSerializer.DeserializeAsync<DiscoverResponse>(stream, _jsonOptions, cancellationToken)
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(cacheKey))
|
if (!string.IsNullOrEmpty(cacheKey))
|
||||||
{
|
{
|
||||||
@ -174,34 +170,37 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
|
|||||||
using var response = await _httpClientFactory.CreateClient(NamedClient.Default)
|
using var response = await _httpClientFactory.CreateClient(NamedClient.Default)
|
||||||
.GetAsync(string.Format(CultureInfo.InvariantCulture, "{0}/tuners.html", GetApiUrl(info)), HttpCompletionOption.ResponseHeadersRead, cancellationToken)
|
.GetAsync(string.Format(CultureInfo.InvariantCulture, "{0}/tuners.html", GetApiUrl(info)), HttpCompletionOption.ResponseHeadersRead, cancellationToken)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false);
|
|
||||||
using var sr = new StreamReader(stream, System.Text.Encoding.UTF8);
|
|
||||||
var tuners = new List<LiveTvTunerInfo>();
|
var tuners = new List<LiveTvTunerInfo>();
|
||||||
await foreach (var line in sr.ReadAllLinesAsync().ConfigureAwait(false))
|
var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false);
|
||||||
|
await using (stream.ConfigureAwait(false))
|
||||||
{
|
{
|
||||||
string stripedLine = StripXML(line);
|
using var sr = new StreamReader(stream, System.Text.Encoding.UTF8);
|
||||||
if (stripedLine.Contains("Channel", StringComparison.Ordinal))
|
await foreach (var line in sr.ReadAllLinesAsync().ConfigureAwait(false))
|
||||||
{
|
{
|
||||||
LiveTvTunerStatus status;
|
string stripedLine = StripXML(line);
|
||||||
var index = stripedLine.IndexOf("Channel", StringComparison.OrdinalIgnoreCase);
|
if (stripedLine.Contains("Channel", StringComparison.Ordinal))
|
||||||
var name = stripedLine.Substring(0, index - 1);
|
|
||||||
var currentChannel = stripedLine.Substring(index + 7);
|
|
||||||
if (string.Equals(currentChannel, "none", StringComparison.Ordinal))
|
|
||||||
{
|
{
|
||||||
status = LiveTvTunerStatus.LiveTv;
|
LiveTvTunerStatus status;
|
||||||
}
|
var index = stripedLine.IndexOf("Channel", StringComparison.OrdinalIgnoreCase);
|
||||||
else
|
var name = stripedLine.Substring(0, index - 1);
|
||||||
{
|
var currentChannel = stripedLine.Substring(index + 7);
|
||||||
status = LiveTvTunerStatus.Available;
|
if (string.Equals(currentChannel, "none", StringComparison.Ordinal))
|
||||||
}
|
{
|
||||||
|
status = LiveTvTunerStatus.LiveTv;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
status = LiveTvTunerStatus.Available;
|
||||||
|
}
|
||||||
|
|
||||||
tuners.Add(new LiveTvTunerInfo
|
tuners.Add(new LiveTvTunerInfo
|
||||||
{
|
{
|
||||||
Name = name,
|
Name = name,
|
||||||
SourceType = string.IsNullOrWhiteSpace(model.ModelNumber) ? Name : model.ModelNumber,
|
SourceType = string.IsNullOrWhiteSpace(model.ModelNumber) ? Name : model.ModelNumber,
|
||||||
ProgramName = currentChannel,
|
ProgramName = currentChannel,
|
||||||
Status = status
|
Status = status
|
||||||
});
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,25 +71,28 @@ namespace Emby.Server.Implementations.Localization
|
|||||||
string countryCode = resource.Substring(RatingsPath.Length, 2);
|
string countryCode = resource.Substring(RatingsPath.Length, 2);
|
||||||
var dict = new Dictionary<string, ParentalRating>(StringComparer.OrdinalIgnoreCase);
|
var dict = new Dictionary<string, ParentalRating>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
|
||||||
await using var stream = _assembly.GetManifestResourceStream(resource);
|
var stream = _assembly.GetManifestResourceStream(resource);
|
||||||
using var reader = new StreamReader(stream!); // shouldn't be null here, we just got the resource path from Assembly.GetManifestResourceNames()
|
await using (stream!.ConfigureAwait(false)) // shouldn't be null here, we just got the resource path from Assembly.GetManifestResourceNames()
|
||||||
await foreach (var line in reader.ReadAllLinesAsync().ConfigureAwait(false))
|
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(line))
|
using var reader = new StreamReader(stream!);
|
||||||
|
await foreach (var line in reader.ReadAllLinesAsync().ConfigureAwait(false))
|
||||||
{
|
{
|
||||||
continue;
|
if (string.IsNullOrWhiteSpace(line))
|
||||||
}
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
string[] parts = line.Split(',');
|
string[] parts = line.Split(',');
|
||||||
if (parts.Length == 2
|
if (parts.Length == 2
|
||||||
&& int.TryParse(parts[1], NumberStyles.Integer, CultureInfo.InvariantCulture, out var value))
|
&& int.TryParse(parts[1], NumberStyles.Integer, CultureInfo.InvariantCulture, out var value))
|
||||||
{
|
{
|
||||||
var name = parts[0];
|
var name = parts[0];
|
||||||
dict.Add(name, new ParentalRating(name, value));
|
dict.Add(name, new ParentalRating(name, value));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_logger.LogWarning("Malformed line in ratings file for country {CountryCode}", countryCode);
|
_logger.LogWarning("Malformed line in ratings file for country {CountryCode}", countryCode);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -386,11 +386,11 @@ namespace Emby.Server.Implementations.Plugins
|
|||||||
var url = new Uri(packageInfo.ImageUrl);
|
var url = new Uri(packageInfo.ImageUrl);
|
||||||
imagePath = Path.Join(path, url.Segments[^1]);
|
imagePath = Path.Join(path, url.Segments[^1]);
|
||||||
|
|
||||||
await using var fileStream = AsyncFile.OpenWrite(imagePath);
|
var fileStream = AsyncFile.OpenWrite(imagePath);
|
||||||
|
Stream? downloadStream = null;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await using var downloadStream = await HttpClientFactory
|
downloadStream = await HttpClientFactory
|
||||||
.CreateClient(NamedClient.Default)
|
.CreateClient(NamedClient.Default)
|
||||||
.GetStreamAsync(url)
|
.GetStreamAsync(url)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
@ -402,6 +402,14 @@ namespace Emby.Server.Implementations.Plugins
|
|||||||
_logger.LogError(ex, "Failed to download image to path {Path} on disk.", imagePath);
|
_logger.LogError(ex, "Failed to download image to path {Path} on disk.", imagePath);
|
||||||
imagePath = string.Empty;
|
imagePath = string.Empty;
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
await fileStream.DisposeAsync().ConfigureAwait(false);
|
||||||
|
if (downloadStream is not null)
|
||||||
|
{
|
||||||
|
await downloadStream.DisposeAsync().ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var manifest = new PluginManifest
|
var manifest = new PluginManifest
|
||||||
@ -421,7 +429,7 @@ namespace Emby.Server.Implementations.Plugins
|
|||||||
ImagePath = imagePath
|
ImagePath = imagePath
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!await ReconcileManifest(manifest, path))
|
if (!await ReconcileManifest(manifest, path).ConfigureAwait(false))
|
||||||
{
|
{
|
||||||
// An error occurred during reconciliation and saving could be undesirable.
|
// An error occurred during reconciliation and saving could be undesirable.
|
||||||
return false;
|
return false;
|
||||||
@ -458,7 +466,7 @@ namespace Emby.Server.Implementations.Plugins
|
|||||||
}
|
}
|
||||||
|
|
||||||
using var metaStream = File.OpenRead(metafile);
|
using var metaStream = File.OpenRead(metafile);
|
||||||
var localManifest = await JsonSerializer.DeserializeAsync<PluginManifest>(metaStream, _jsonOptions);
|
var localManifest = await JsonSerializer.DeserializeAsync<PluginManifest>(metaStream, _jsonOptions).ConfigureAwait(false);
|
||||||
localManifest ??= new PluginManifest();
|
localManifest ??= new PluginManifest();
|
||||||
|
|
||||||
if (!Equals(localManifest.Id, manifest.Id))
|
if (!Equals(localManifest.Id, manifest.Id))
|
||||||
|
@ -520,18 +520,16 @@ namespace Emby.Server.Implementations.Updates
|
|||||||
|
|
||||||
// CA5351: Do Not Use Broken Cryptographic Algorithms
|
// CA5351: Do Not Use Broken Cryptographic Algorithms
|
||||||
#pragma warning disable CA5351
|
#pragma warning disable CA5351
|
||||||
using var md5 = MD5.Create();
|
|
||||||
cancellationToken.ThrowIfCancellationRequested();
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
var hash = await md5.ComputeHashAsync(stream, cancellationToken).ConfigureAwait(false);
|
var hash = Convert.ToHexString(await MD5.HashDataAsync(stream, cancellationToken).ConfigureAwait(false));
|
||||||
var hashHex = Convert.ToHexString(hash);
|
if (!string.Equals(package.Checksum, hash, StringComparison.OrdinalIgnoreCase))
|
||||||
if (!string.Equals(package.Checksum, hashHex, StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
{
|
||||||
_logger.LogError(
|
_logger.LogError(
|
||||||
"The checksums didn't match while installing {Package}, expected: {Expected}, got: {Received}",
|
"The checksums didn't match while installing {Package}, expected: {Expected}, got: {Received}",
|
||||||
package.Name,
|
package.Name,
|
||||||
package.Checksum,
|
package.Checksum,
|
||||||
hashHex);
|
hash);
|
||||||
throw new InvalidDataException("The checksum of the received data doesn't match.");
|
throw new InvalidDataException("The checksum of the received data doesn't match.");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -557,7 +555,7 @@ namespace Emby.Server.Implementations.Updates
|
|||||||
reader.ExtractToDirectory(targetDir, true);
|
reader.ExtractToDirectory(targetDir, true);
|
||||||
|
|
||||||
// Ensure we create one or populate existing ones with missing data.
|
// Ensure we create one or populate existing ones with missing data.
|
||||||
await _pluginManager.PopulateManifest(package.PackageInfo, package.Version, targetDir, status);
|
await _pluginManager.PopulateManifest(package.PackageInfo, package.Version, targetDir, status).ConfigureAwait(false);
|
||||||
|
|
||||||
_pluginManager.ImportPluginFrom(targetDir);
|
_pluginManager.ImportPluginFrom(targetDir);
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,6 @@ using System.IO;
|
|||||||
using System.Net.Mime;
|
using System.Net.Mime;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Emby.Dlna;
|
using Emby.Dlna;
|
||||||
using Emby.Dlna.Main;
|
|
||||||
using Jellyfin.Api.Attributes;
|
using Jellyfin.Api.Attributes;
|
||||||
using Jellyfin.Api.Constants;
|
using Jellyfin.Api.Constants;
|
||||||
using MediaBrowser.Controller.Dlna;
|
using MediaBrowser.Controller.Dlna;
|
||||||
@ -33,12 +32,19 @@ public class DlnaServerController : BaseJellyfinApiController
|
|||||||
/// Initializes a new instance of the <see cref="DlnaServerController"/> class.
|
/// Initializes a new instance of the <see cref="DlnaServerController"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="dlnaManager">Instance of the <see cref="IDlnaManager"/> interface.</param>
|
/// <param name="dlnaManager">Instance of the <see cref="IDlnaManager"/> interface.</param>
|
||||||
public DlnaServerController(IDlnaManager dlnaManager)
|
/// <param name="contentDirectory">Instance of the <see cref="IContentDirectory"/> interface.</param>
|
||||||
|
/// <param name="connectionManager">Instance of the <see cref="IConnectionManager"/> interface.</param>
|
||||||
|
/// <param name="mediaReceiverRegistrar">Instance of the <see cref="IMediaReceiverRegistrar"/> interface.</param>
|
||||||
|
public DlnaServerController(
|
||||||
|
IDlnaManager dlnaManager,
|
||||||
|
IContentDirectory contentDirectory,
|
||||||
|
IConnectionManager connectionManager,
|
||||||
|
IMediaReceiverRegistrar mediaReceiverRegistrar)
|
||||||
{
|
{
|
||||||
_dlnaManager = dlnaManager;
|
_dlnaManager = dlnaManager;
|
||||||
_contentDirectory = DlnaEntryPoint.Current.ContentDirectory;
|
_contentDirectory = contentDirectory;
|
||||||
_connectionManager = DlnaEntryPoint.Current.ConnectionManager;
|
_connectionManager = connectionManager;
|
||||||
_mediaReceiverRegistrar = DlnaEntryPoint.Current.MediaReceiverRegistrar;
|
_mediaReceiverRegistrar = mediaReceiverRegistrar;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -8,8 +8,6 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net7.0</TargetFramework>
|
||||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
<!-- https://github.com/microsoft/ApplicationInsights-dotnet/issues/2047 -->
|
|
||||||
<NoWarn>AD0001</NoWarn>
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Globalization;
|
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Net.Http.Headers;
|
using System.Net.Http.Headers;
|
||||||
using System.Net.Mime;
|
using System.Net.Mime;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using Emby.Dlna.Extensions;
|
||||||
using Jellyfin.Api.Middleware;
|
using Jellyfin.Api.Middleware;
|
||||||
using Jellyfin.MediaEncoding.Hls.Extensions;
|
using Jellyfin.MediaEncoding.Hls.Extensions;
|
||||||
using Jellyfin.Networking.Configuration;
|
using Jellyfin.Networking.Configuration;
|
||||||
@ -119,26 +119,11 @@ namespace Jellyfin.Server
|
|||||||
})
|
})
|
||||||
.ConfigurePrimaryHttpMessageHandler(defaultHttpClientHandlerDelegate);
|
.ConfigurePrimaryHttpMessageHandler(defaultHttpClientHandlerDelegate);
|
||||||
|
|
||||||
services.AddHttpClient(NamedClient.Dlna, c =>
|
|
||||||
{
|
|
||||||
c.DefaultRequestHeaders.UserAgent.ParseAdd(
|
|
||||||
string.Format(
|
|
||||||
CultureInfo.InvariantCulture,
|
|
||||||
"{0}/{1} UPnP/1.0 {2}/{3}",
|
|
||||||
Environment.OSVersion.Platform,
|
|
||||||
Environment.OSVersion,
|
|
||||||
_serverApplicationHost.Name,
|
|
||||||
_serverApplicationHost.ApplicationVersionString));
|
|
||||||
|
|
||||||
c.DefaultRequestHeaders.Add("CPFN.UPNP.ORG", _serverApplicationHost.FriendlyName); // Required for UPnP DeviceArchitecture v2.0
|
|
||||||
c.DefaultRequestHeaders.Add("FriendlyName.DLNA.ORG", _serverApplicationHost.FriendlyName); // REVIEW: where does this come from?
|
|
||||||
})
|
|
||||||
.ConfigurePrimaryHttpMessageHandler(defaultHttpClientHandlerDelegate);
|
|
||||||
|
|
||||||
services.AddHealthChecks()
|
services.AddHealthChecks()
|
||||||
.AddCheck<DbContextFactoryHealthCheck<JellyfinDbContext>>(nameof(JellyfinDbContext));
|
.AddCheck<DbContextFactoryHealthCheck<JellyfinDbContext>>(nameof(JellyfinDbContext));
|
||||||
|
|
||||||
services.AddHlsPlaylistGenerator();
|
services.AddHlsPlaylistGenerator();
|
||||||
|
services.AddDlnaServices(_serverApplicationHost);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -23,9 +23,12 @@ namespace MediaBrowser.Controller.ClientEvent
|
|||||||
{
|
{
|
||||||
var fileName = $"upload_{clientName}_{clientVersion}_{DateTime.UtcNow:yyyyMMddHHmmss}_{Guid.NewGuid():N}.log";
|
var fileName = $"upload_{clientName}_{clientVersion}_{DateTime.UtcNow:yyyyMMddHHmmss}_{Guid.NewGuid():N}.log";
|
||||||
var logFilePath = Path.Combine(_applicationPaths.LogDirectoryPath, fileName);
|
var logFilePath = Path.Combine(_applicationPaths.LogDirectoryPath, fileName);
|
||||||
await using var fileStream = new FileStream(logFilePath, FileMode.CreateNew, FileAccess.Write, FileShare.None);
|
var fileStream = new FileStream(logFilePath, FileMode.CreateNew, FileAccess.Write, FileShare.None);
|
||||||
await fileContents.CopyToAsync(fileStream).ConfigureAwait(false);
|
await using (fileStream.ConfigureAwait(false))
|
||||||
return fileName;
|
{
|
||||||
|
await fileContents.CopyToAsync(fileStream).ConfigureAwait(false);
|
||||||
|
return fileName;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -176,17 +176,12 @@ namespace MediaBrowser.Providers.Plugins.AudioDb
|
|||||||
Directory.CreateDirectory(Path.GetDirectoryName(path));
|
Directory.CreateDirectory(Path.GetDirectoryName(path));
|
||||||
|
|
||||||
using var response = await _httpClientFactory.CreateClient(NamedClient.Default).GetAsync(url, cancellationToken).ConfigureAwait(false);
|
using var response = await _httpClientFactory.CreateClient(NamedClient.Default).GetAsync(url, cancellationToken).ConfigureAwait(false);
|
||||||
var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false);
|
var fileStreamOptions = AsyncFile.WriteOptions;
|
||||||
await using (stream.ConfigureAwait(false))
|
fileStreamOptions.Mode = FileMode.Create;
|
||||||
|
var fs = new FileStream(path, fileStreamOptions);
|
||||||
|
await using (fs.ConfigureAwait(false))
|
||||||
{
|
{
|
||||||
var fileStreamOptions = AsyncFile.WriteOptions;
|
await response.Content.CopyToAsync(fs, cancellationToken).ConfigureAwait(false);
|
||||||
fileStreamOptions.Mode = FileMode.Create;
|
|
||||||
fileStreamOptions.PreallocationSize = stream.Length;
|
|
||||||
var xmlFileStream = new FileStream(path, fileStreamOptions);
|
|
||||||
await using (xmlFileStream.ConfigureAwait(false))
|
|
||||||
{
|
|
||||||
await stream.CopyToAsync(xmlFileStream, cancellationToken).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -154,20 +154,15 @@ namespace MediaBrowser.Providers.Plugins.AudioDb
|
|||||||
|
|
||||||
using var response = await _httpClientFactory.CreateClient(NamedClient.Default).GetAsync(url, cancellationToken).ConfigureAwait(false);
|
using var response = await _httpClientFactory.CreateClient(NamedClient.Default).GetAsync(url, cancellationToken).ConfigureAwait(false);
|
||||||
response.EnsureSuccessStatusCode();
|
response.EnsureSuccessStatusCode();
|
||||||
var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false);
|
var path = GetArtistInfoPath(_config.ApplicationPaths, musicBrainzId);
|
||||||
await using (stream.ConfigureAwait(false))
|
Directory.CreateDirectory(Path.GetDirectoryName(path));
|
||||||
{
|
|
||||||
var path = GetArtistInfoPath(_config.ApplicationPaths, musicBrainzId);
|
|
||||||
Directory.CreateDirectory(Path.GetDirectoryName(path));
|
|
||||||
|
|
||||||
var fileStreamOptions = AsyncFile.WriteOptions;
|
var fileStreamOptions = AsyncFile.WriteOptions;
|
||||||
fileStreamOptions.Mode = FileMode.Create;
|
fileStreamOptions.Mode = FileMode.Create;
|
||||||
fileStreamOptions.PreallocationSize = stream.Length;
|
var xmlFileStream = new FileStream(path, fileStreamOptions);
|
||||||
var xmlFileStream = new FileStream(path, fileStreamOptions);
|
await using (xmlFileStream.ConfigureAwait(false))
|
||||||
await using (xmlFileStream.ConfigureAwait(false))
|
{
|
||||||
{
|
await response.Content.CopyToAsync(xmlFileStream, cancellationToken).ConfigureAwait(false);
|
||||||
await stream.CopyToAsync(xmlFileStream, cancellationToken).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@ using System.Globalization;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
|
using System.Net.Http.Json;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
@ -137,31 +138,27 @@ namespace MediaBrowser.Providers.Plugins.Omdb
|
|||||||
var url = OmdbProvider.GetOmdbUrl(urlQuery.ToString());
|
var url = OmdbProvider.GetOmdbUrl(urlQuery.ToString());
|
||||||
|
|
||||||
using var response = await _httpClientFactory.CreateClient(NamedClient.Default).GetAsync(url, cancellationToken).ConfigureAwait(false);
|
using var response = await _httpClientFactory.CreateClient(NamedClient.Default).GetAsync(url, cancellationToken).ConfigureAwait(false);
|
||||||
var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false);
|
if (isSearch)
|
||||||
await using (stream.ConfigureAwait(false))
|
|
||||||
{
|
{
|
||||||
if (isSearch)
|
var searchResultList = await response.Content.ReadFromJsonAsync<SearchResultList>(_jsonOptions, cancellationToken).ConfigureAwait(false);
|
||||||
|
if (searchResultList?.Search is not null)
|
||||||
{
|
{
|
||||||
var searchResultList = await JsonSerializer.DeserializeAsync<SearchResultList>(stream, _jsonOptions, cancellationToken).ConfigureAwait(false);
|
var resultCount = searchResultList.Search.Count;
|
||||||
if (searchResultList?.Search is not null)
|
var result = new RemoteSearchResult[resultCount];
|
||||||
|
for (var i = 0; i < resultCount; i++)
|
||||||
{
|
{
|
||||||
var resultCount = searchResultList.Search.Count;
|
result[i] = ResultToMetadataResult(searchResultList.Search[i], searchInfo, indexNumberEnd);
|
||||||
var result = new RemoteSearchResult[resultCount];
|
}
|
||||||
for (var i = 0; i < resultCount; i++)
|
|
||||||
{
|
|
||||||
result[i] = ResultToMetadataResult(searchResultList.Search[i], searchInfo, indexNumberEnd);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var result = await response.Content.ReadFromJsonAsync<SearchResult>(_jsonOptions, cancellationToken).ConfigureAwait(false);
|
||||||
|
if (string.Equals(result?.Response, "true", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
var result = await JsonSerializer.DeserializeAsync<SearchResult>(stream, _jsonOptions, cancellationToken).ConfigureAwait(false);
|
return new[] { ResultToMetadataResult(result, searchInfo, indexNumberEnd) };
|
||||||
if (string.Equals(result?.Response, "true", StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
return new[] { ResultToMetadataResult(result, searchInfo, indexNumberEnd) };
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,9 +40,7 @@ namespace Jellyfin.Server.Integration.Tests
|
|||||||
using var authResponse = await client.SendAsync(httpRequest);
|
using var authResponse = await client.SendAsync(httpRequest);
|
||||||
authResponse.EnsureSuccessStatusCode();
|
authResponse.EnsureSuccessStatusCode();
|
||||||
|
|
||||||
var auth = await JsonSerializer.DeserializeAsync<AuthenticationResultDto>(
|
var auth = await authResponse.Content.ReadFromJsonAsync<AuthenticationResultDto>(jsonOptions);
|
||||||
await authResponse.Content.ReadAsStreamAsync(),
|
|
||||||
jsonOptions);
|
|
||||||
|
|
||||||
return auth!.AccessToken;
|
return auth!.AccessToken;
|
||||||
}
|
}
|
||||||
@ -51,8 +49,7 @@ namespace Jellyfin.Server.Integration.Tests
|
|||||||
{
|
{
|
||||||
using var response = await client.GetAsync("Users/Me");
|
using var response = await client.GetAsync("Users/Me");
|
||||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||||
var userDto = await JsonSerializer.DeserializeAsync<UserDto>(
|
var userDto = await response.Content.ReadFromJsonAsync<UserDto>(JsonDefaults.Options);
|
||||||
await response.Content.ReadAsStreamAsync(), JsonDefaults.Options);
|
|
||||||
Assert.NotNull(userDto);
|
Assert.NotNull(userDto);
|
||||||
return userDto;
|
return userDto;
|
||||||
}
|
}
|
||||||
@ -67,9 +64,7 @@ namespace Jellyfin.Server.Integration.Tests
|
|||||||
|
|
||||||
var response = await client.GetAsync($"Users/{userId}/Items/Root");
|
var response = await client.GetAsync($"Users/{userId}/Items/Root");
|
||||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||||
var rootDto = await JsonSerializer.DeserializeAsync<BaseItemDto>(
|
var rootDto = await response.Content.ReadFromJsonAsync<BaseItemDto>(JsonDefaults.Options);
|
||||||
await response.Content.ReadAsStreamAsync(),
|
|
||||||
JsonDefaults.Options);
|
|
||||||
Assert.NotNull(rootDto);
|
Assert.NotNull(rootDto);
|
||||||
return rootDto;
|
return rootDto;
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using System.Net;
|
using System.Net;
|
||||||
|
using System.Net.Http.Json;
|
||||||
using System.Net.Mime;
|
using System.Net.Mime;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
@ -30,8 +31,7 @@ namespace Jellyfin.Server.Integration.Tests
|
|||||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||||
Assert.Equal(MediaTypeNames.Application.Json, response.Content.Headers.ContentType?.MediaType);
|
Assert.Equal(MediaTypeNames.Application.Json, response.Content.Headers.ContentType?.MediaType);
|
||||||
Assert.Equal(Encoding.UTF8.BodyName, response.Content.Headers.ContentType?.CharSet);
|
Assert.Equal(Encoding.UTF8.BodyName, response.Content.Headers.ContentType?.CharSet);
|
||||||
var responseBody = await response.Content.ReadAsStreamAsync();
|
await response.Content.ReadFromJsonAsync<BrandingOptions>();
|
||||||
_ = await JsonSerializer.DeserializeAsync<BrandingOptions>(responseBody);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
using System.Net.Http.Json;
|
||||||
using System.Net.Mime;
|
using System.Net.Mime;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
@ -64,8 +65,7 @@ namespace Jellyfin.Server.Integration.Tests.Controllers
|
|||||||
|
|
||||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||||
|
|
||||||
var res = await response.Content.ReadAsStreamAsync();
|
_ = await response.Content.ReadFromJsonAsync<ConfigurationPageInfo[]>(_jsonOpions);
|
||||||
_ = await JsonSerializer.DeserializeAsync<ConfigurationPageInfo[]>(res, _jsonOpions);
|
|
||||||
// TODO: check content
|
// TODO: check content
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -81,8 +81,7 @@ namespace Jellyfin.Server.Integration.Tests.Controllers
|
|||||||
Assert.Equal(MediaTypeNames.Application.Json, response.Content.Headers.ContentType?.MediaType);
|
Assert.Equal(MediaTypeNames.Application.Json, response.Content.Headers.ContentType?.MediaType);
|
||||||
Assert.Equal(Encoding.UTF8.BodyName, response.Content.Headers.ContentType?.CharSet);
|
Assert.Equal(Encoding.UTF8.BodyName, response.Content.Headers.ContentType?.CharSet);
|
||||||
|
|
||||||
var res = await response.Content.ReadAsStreamAsync();
|
var data = await response.Content.ReadFromJsonAsync<ConfigurationPageInfo[]>(_jsonOpions);
|
||||||
var data = await JsonSerializer.DeserializeAsync<ConfigurationPageInfo[]>(res, _jsonOpions);
|
|
||||||
Assert.NotNull(data);
|
Assert.NotNull(data);
|
||||||
Assert.Empty(data);
|
Assert.Empty(data);
|
||||||
}
|
}
|
||||||
|
@ -93,9 +93,7 @@ namespace Jellyfin.Server.Integration.Tests.Controllers
|
|||||||
Assert.Equal(MediaTypeNames.Application.Json, response.Content.Headers.ContentType?.MediaType);
|
Assert.Equal(MediaTypeNames.Application.Json, response.Content.Headers.ContentType?.MediaType);
|
||||||
Assert.Equal(Encoding.UTF8.BodyName, response.Content.Headers.ContentType?.CharSet);
|
Assert.Equal(Encoding.UTF8.BodyName, response.Content.Headers.ContentType?.CharSet);
|
||||||
|
|
||||||
var profiles = await JsonSerializer.DeserializeAsync<DeviceProfileInfo[]>(
|
var profiles = await response.Content.ReadFromJsonAsync<DeviceProfileInfo[]>(_jsonOptions);
|
||||||
await response.Content.ReadAsStreamAsync(),
|
|
||||||
_jsonOptions);
|
|
||||||
|
|
||||||
var newProfile = profiles?.FirstOrDefault(x => string.Equals(x.Name, "ThisProfileIsNew", StringComparison.Ordinal));
|
var newProfile = profiles?.FirstOrDefault(x => string.Equals(x.Name, "ThisProfileIsNew", StringComparison.Ordinal));
|
||||||
Assert.NotNull(newProfile);
|
Assert.NotNull(newProfile);
|
||||||
@ -124,9 +122,7 @@ namespace Jellyfin.Server.Integration.Tests.Controllers
|
|||||||
Assert.Equal(MediaTypeNames.Application.Json, response.Content.Headers.ContentType?.MediaType);
|
Assert.Equal(MediaTypeNames.Application.Json, response.Content.Headers.ContentType?.MediaType);
|
||||||
Assert.Equal(Encoding.UTF8.BodyName, response.Content.Headers.ContentType?.CharSet);
|
Assert.Equal(Encoding.UTF8.BodyName, response.Content.Headers.ContentType?.CharSet);
|
||||||
|
|
||||||
var profiles = await JsonSerializer.DeserializeAsync<DeviceProfileInfo[]>(
|
var profiles = await response.Content.ReadFromJsonAsync<DeviceProfileInfo[]>(_jsonOptions);
|
||||||
await response.Content.ReadAsStreamAsync(),
|
|
||||||
_jsonOptions);
|
|
||||||
|
|
||||||
Assert.Null(profiles?.FirstOrDefault(x => string.Equals(x.Name, "ThisProfileIsNew", StringComparison.Ordinal)));
|
Assert.Null(profiles?.FirstOrDefault(x => string.Equals(x.Name, "ThisProfileIsNew", StringComparison.Ordinal)));
|
||||||
var newProfile = profiles?.FirstOrDefault(x => string.Equals(x.Name, "ThisProfileIsUpdated", StringComparison.Ordinal));
|
var newProfile = profiles?.FirstOrDefault(x => string.Equals(x.Name, "ThisProfileIsUpdated", StringComparison.Ordinal));
|
||||||
@ -150,9 +146,7 @@ namespace Jellyfin.Server.Integration.Tests.Controllers
|
|||||||
Assert.Equal(MediaTypeNames.Application.Json, response.Content.Headers.ContentType?.MediaType);
|
Assert.Equal(MediaTypeNames.Application.Json, response.Content.Headers.ContentType?.MediaType);
|
||||||
Assert.Equal(Encoding.UTF8.BodyName, response.Content.Headers.ContentType?.CharSet);
|
Assert.Equal(Encoding.UTF8.BodyName, response.Content.Headers.ContentType?.CharSet);
|
||||||
|
|
||||||
var profiles = await JsonSerializer.DeserializeAsync<DeviceProfileInfo[]>(
|
var profiles = await response.Content.ReadFromJsonAsync<DeviceProfileInfo[]>(_jsonOptions);
|
||||||
await response.Content.ReadAsStreamAsync(),
|
|
||||||
_jsonOptions);
|
|
||||||
|
|
||||||
Assert.Null(profiles?.FirstOrDefault(x => string.Equals(x.Name, "ThisProfileIsUpdated", StringComparison.Ordinal)));
|
Assert.Null(profiles?.FirstOrDefault(x => string.Equals(x.Name, "ThisProfileIsUpdated", StringComparison.Ordinal)));
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
using System.Net.Http.Json;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Jellyfin.Extensions.Json;
|
using Jellyfin.Extensions.Json;
|
||||||
@ -56,9 +57,7 @@ public sealed class ItemsControllerTests : IClassFixture<JellyfinApplicationFact
|
|||||||
|
|
||||||
var response = await client.GetAsync(string.Format(CultureInfo.InvariantCulture, format, userDto.Id));
|
var response = await client.GetAsync(string.Format(CultureInfo.InvariantCulture, format, userDto.Id));
|
||||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||||
var items = await JsonSerializer.DeserializeAsync<QueryResult<BaseItemDto>>(
|
var items = await response.Content.ReadFromJsonAsync<QueryResult<BaseItemDto>>(_jsonOptions);
|
||||||
await response.Content.ReadAsStreamAsync(),
|
|
||||||
_jsonOptions);
|
|
||||||
Assert.NotNull(items);
|
Assert.NotNull(items);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -43,8 +43,7 @@ namespace Jellyfin.Server.Integration.Tests.Controllers
|
|||||||
Assert.Equal(HttpStatusCode.OK, getResponse.StatusCode);
|
Assert.Equal(HttpStatusCode.OK, getResponse.StatusCode);
|
||||||
Assert.Equal(MediaTypeNames.Application.Json, getResponse.Content.Headers.ContentType?.MediaType);
|
Assert.Equal(MediaTypeNames.Application.Json, getResponse.Content.Headers.ContentType?.MediaType);
|
||||||
|
|
||||||
using var responseStream = await getResponse.Content.ReadAsStreamAsync();
|
var newConfig = await getResponse.Content.ReadFromJsonAsync<StartupConfigurationDto>(_jsonOptions);
|
||||||
var newConfig = await JsonSerializer.DeserializeAsync<StartupConfigurationDto>(responseStream, _jsonOptions);
|
|
||||||
Assert.Equal(config.UICulture, newConfig!.UICulture);
|
Assert.Equal(config.UICulture, newConfig!.UICulture);
|
||||||
Assert.Equal(config.MetadataCountryCode, newConfig.MetadataCountryCode);
|
Assert.Equal(config.MetadataCountryCode, newConfig.MetadataCountryCode);
|
||||||
Assert.Equal(config.PreferredMetadataLanguage, newConfig.PreferredMetadataLanguage);
|
Assert.Equal(config.PreferredMetadataLanguage, newConfig.PreferredMetadataLanguage);
|
||||||
@ -60,8 +59,7 @@ namespace Jellyfin.Server.Integration.Tests.Controllers
|
|||||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||||
Assert.Equal(MediaTypeNames.Application.Json, response.Content.Headers.ContentType?.MediaType);
|
Assert.Equal(MediaTypeNames.Application.Json, response.Content.Headers.ContentType?.MediaType);
|
||||||
|
|
||||||
using var contentStream = await response.Content.ReadAsStreamAsync();
|
var user = await response.Content.ReadFromJsonAsync<StartupUserDto>(_jsonOptions);
|
||||||
var user = await JsonSerializer.DeserializeAsync<StartupUserDto>(contentStream, _jsonOptions);
|
|
||||||
Assert.NotNull(user);
|
Assert.NotNull(user);
|
||||||
Assert.NotNull(user.Name);
|
Assert.NotNull(user.Name);
|
||||||
Assert.NotEmpty(user.Name);
|
Assert.NotEmpty(user.Name);
|
||||||
@ -87,8 +85,7 @@ namespace Jellyfin.Server.Integration.Tests.Controllers
|
|||||||
Assert.Equal(HttpStatusCode.OK, getResponse.StatusCode);
|
Assert.Equal(HttpStatusCode.OK, getResponse.StatusCode);
|
||||||
Assert.Equal(MediaTypeNames.Application.Json, getResponse.Content.Headers.ContentType?.MediaType);
|
Assert.Equal(MediaTypeNames.Application.Json, getResponse.Content.Headers.ContentType?.MediaType);
|
||||||
|
|
||||||
var contentStream = await getResponse.Content.ReadAsStreamAsync();
|
var newUser = await getResponse.Content.ReadFromJsonAsync<StartupUserDto>(_jsonOptions);
|
||||||
var newUser = await JsonSerializer.DeserializeAsync<StartupUserDto>(contentStream, _jsonOptions);
|
|
||||||
Assert.NotNull(newUser);
|
Assert.NotNull(newUser);
|
||||||
Assert.Equal(user.Name, newUser.Name);
|
Assert.Equal(user.Name, newUser.Name);
|
||||||
Assert.NotNull(newUser.Password);
|
Assert.NotNull(newUser.Password);
|
||||||
|
@ -43,8 +43,7 @@ namespace Jellyfin.Server.Integration.Tests.Controllers
|
|||||||
|
|
||||||
using var response = await client.GetAsync("Users/Public");
|
using var response = await client.GetAsync("Users/Public");
|
||||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||||
var users = await JsonSerializer.DeserializeAsync<UserDto[]>(
|
var users = await response.Content.ReadFromJsonAsync<UserDto[]>(_jsonOpions);
|
||||||
await response.Content.ReadAsStreamAsync(), _jsonOpions);
|
|
||||||
// User are hidden by default
|
// User are hidden by default
|
||||||
Assert.NotNull(users);
|
Assert.NotNull(users);
|
||||||
Assert.Empty(users);
|
Assert.Empty(users);
|
||||||
@ -59,8 +58,7 @@ namespace Jellyfin.Server.Integration.Tests.Controllers
|
|||||||
|
|
||||||
using var response = await client.GetAsync("Users");
|
using var response = await client.GetAsync("Users");
|
||||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||||
var users = await JsonSerializer.DeserializeAsync<UserDto[]>(
|
var users = await response.Content.ReadFromJsonAsync<UserDto[]>(_jsonOpions);
|
||||||
await response.Content.ReadAsStreamAsync(), _jsonOpions);
|
|
||||||
Assert.NotNull(users);
|
Assert.NotNull(users);
|
||||||
Assert.Single(users);
|
Assert.Single(users);
|
||||||
Assert.False(users![0].HasConfiguredPassword);
|
Assert.False(users![0].HasConfiguredPassword);
|
||||||
@ -92,8 +90,7 @@ namespace Jellyfin.Server.Integration.Tests.Controllers
|
|||||||
|
|
||||||
using var response = await CreateUserByName(client, createRequest);
|
using var response = await CreateUserByName(client, createRequest);
|
||||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||||
var user = await JsonSerializer.DeserializeAsync<UserDto>(
|
var user = await response.Content.ReadFromJsonAsync<UserDto>(_jsonOpions);
|
||||||
await response.Content.ReadAsStreamAsync(), _jsonOpions);
|
|
||||||
Assert.Equal(TestUsername, user!.Name);
|
Assert.Equal(TestUsername, user!.Name);
|
||||||
Assert.False(user.HasPassword);
|
Assert.False(user.HasPassword);
|
||||||
Assert.False(user.HasConfiguredPassword);
|
Assert.False(user.HasConfiguredPassword);
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
using System.Net.Http.Json;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Jellyfin.Extensions.Json;
|
using Jellyfin.Extensions.Json;
|
||||||
@ -85,9 +86,7 @@ public sealed class UserLibraryControllerTests : IClassFixture<JellyfinApplicati
|
|||||||
|
|
||||||
var response = await client.GetAsync($"Users/{userDto.Id}/Items/{rootFolderDto.Id}");
|
var response = await client.GetAsync($"Users/{userDto.Id}/Items/{rootFolderDto.Id}");
|
||||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||||
var rootDto = await JsonSerializer.DeserializeAsync<BaseItemDto>(
|
var rootDto = await response.Content.ReadFromJsonAsync<BaseItemDto>(_jsonOptions);
|
||||||
await response.Content.ReadAsStreamAsync(),
|
|
||||||
_jsonOptions);
|
|
||||||
Assert.NotNull(rootDto);
|
Assert.NotNull(rootDto);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,9 +101,7 @@ public sealed class UserLibraryControllerTests : IClassFixture<JellyfinApplicati
|
|||||||
|
|
||||||
var response = await client.GetAsync($"Users/{userDto.Id}/Items/{rootFolderDto.Id}/Intros");
|
var response = await client.GetAsync($"Users/{userDto.Id}/Items/{rootFolderDto.Id}/Intros");
|
||||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||||
var rootDto = await JsonSerializer.DeserializeAsync<QueryResult<BaseItemDto>>(
|
var rootDto = await response.Content.ReadFromJsonAsync<QueryResult<BaseItemDto>>(_jsonOptions);
|
||||||
await response.Content.ReadAsStreamAsync(),
|
|
||||||
_jsonOptions);
|
|
||||||
Assert.NotNull(rootDto);
|
Assert.NotNull(rootDto);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -121,9 +118,7 @@ public sealed class UserLibraryControllerTests : IClassFixture<JellyfinApplicati
|
|||||||
|
|
||||||
var response = await client.GetAsync(string.Format(CultureInfo.InvariantCulture, format, userDto.Id, rootFolderDto.Id));
|
var response = await client.GetAsync(string.Format(CultureInfo.InvariantCulture, format, userDto.Id, rootFolderDto.Id));
|
||||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||||
var rootDto = await JsonSerializer.DeserializeAsync<BaseItemDto[]>(
|
var rootDto = await response.Content.ReadFromJsonAsync<BaseItemDto[]>(_jsonOptions);
|
||||||
await response.Content.ReadAsStreamAsync(),
|
|
||||||
_jsonOptions);
|
|
||||||
Assert.NotNull(rootDto);
|
Assert.NotNull(rootDto);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,10 +31,10 @@ namespace Jellyfin.Server.Integration.Tests
|
|||||||
Assert.Equal("application/json; charset=utf-8", response.Content.Headers.ContentType?.ToString());
|
Assert.Equal("application/json; charset=utf-8", response.Content.Headers.ContentType?.ToString());
|
||||||
|
|
||||||
// Write out for publishing
|
// Write out for publishing
|
||||||
var responseBody = await response.Content.ReadAsStringAsync();
|
|
||||||
string outputPath = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) ?? ".", "openapi.json"));
|
string outputPath = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) ?? ".", "openapi.json"));
|
||||||
_outputHelper.WriteLine("Writing OpenAPI Spec JSON to '{0}'.", outputPath);
|
_outputHelper.WriteLine("Writing OpenAPI Spec JSON to '{0}'.", outputPath);
|
||||||
await File.WriteAllTextAsync(outputPath, responseBody);
|
await using var fs = File.Create(outputPath);
|
||||||
|
await response.Content.CopyToAsync(fs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user