mirror of
				https://github.com/jellyfin/jellyfin.git
				synced 2025-11-03 19:17:24 -05:00 
			
		
		
		
	Merge pull request #10390 from Bond-009/streams
This commit is contained in:
		
						commit
						4fc27fa63e
					
				@ -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;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
				
			|||||||
@ -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;
 | 
				
			||||||
@ -76,13 +77,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();
 | 
				
			||||||
@ -129,9 +127,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))
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
@ -175,34 +171,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,10 +520,9 @@ 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 = Convert.ToHexString(md5.ComputeHash(stream));
 | 
					            var hash = Convert.ToHexString(await MD5.HashDataAsync(stream, cancellationToken).ConfigureAwait(false));
 | 
				
			||||||
            if (!string.Equals(package.Checksum, hash, StringComparison.OrdinalIgnoreCase))
 | 
					            if (!string.Equals(package.Checksum, hash, StringComparison.OrdinalIgnoreCase))
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                _logger.LogError(
 | 
					                _logger.LogError(
 | 
				
			||||||
@ -556,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);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
				
			|||||||
@ -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>
 | 
				
			||||||
 | 
				
			|||||||
@ -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);
 | 
				
			||||||
            File.WriteAllText(outputPath, responseBody);
 | 
					            await using var fs = File.Create(outputPath);
 | 
				
			||||||
 | 
					            await response.Content.CopyToAsync(fs);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user