From e3dac4fda2033801085eb7086a3a534c473a00a0 Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Sat, 12 Jun 2021 22:20:35 +0200 Subject: Use async FileStreams where it makes sense --- .../LiveTv/EmbyTV/DirectRecorder.cs | 4 +- .../LiveTv/EmbyTV/EncodedRecorder.cs | 2 +- .../LiveTv/Listings/XmlTvListingsProvider.cs | 2 +- .../LiveTv/TunerHosts/BaseTunerHost.cs | 4 +- .../LiveTv/TunerHosts/LiveStream.cs | 4 +- .../LiveTv/TunerHosts/M3uParser.cs | 3 +- .../LiveTv/TunerHosts/SharedHttpStream.cs | 62 +++++++++++----------- 7 files changed, 41 insertions(+), 40 deletions(-) (limited to 'Emby.Server.Implementations/LiveTv') diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs index bb3d635d12..c5a9a92ec2 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs @@ -46,7 +46,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV Directory.CreateDirectory(Path.GetDirectoryName(targetFile) ?? throw new ArgumentException("Path can't be a root directory.", nameof(targetFile))); // use FileShare.None as this bypasses dotnet bug dotnet/runtime#42790 . - using (var output = new FileStream(targetFile, FileMode.Create, FileAccess.Write, FileShare.None)) + using (var output = new FileStream(targetFile, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, AsyncFile.UseAsyncIO)) { onStarted(); @@ -72,7 +72,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV Directory.CreateDirectory(Path.GetDirectoryName(targetFile) ?? throw new ArgumentException("Path can't be a root directory.", nameof(targetFile))); // use FileShare.None as this bypasses dotnet bug dotnet/runtime#42790 . - await using var output = new FileStream(targetFile, FileMode.Create, FileAccess.Write, FileShare.None); + await using var output = new FileStream(targetFile, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.CopyToBufferSize, AsyncFile.UseAsyncIO); onStarted(); diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs index e10bc76470..d806a02959 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs @@ -94,7 +94,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV Directory.CreateDirectory(Path.GetDirectoryName(logFilePath)); // FFMpeg writes debug/error info to stderr. This is useful when debugging so let's put it in the log directory. - _logFileStream = new FileStream(logFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, IODefaults.FileStreamBufferSize, true); + _logFileStream = new FileStream(logFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, IODefaults.FileStreamBufferSize, AsyncFile.UseAsyncIO); await JsonSerializer.SerializeAsync(_logFileStream, mediaSource, _jsonOptions, cancellationToken).ConfigureAwait(false); await _logFileStream.WriteAsync(Encoding.UTF8.GetBytes(Environment.NewLine + Environment.NewLine + commandLineLogMessage + Environment.NewLine + Environment.NewLine), cancellationToken).ConfigureAwait(false); diff --git a/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs b/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs index ebad4eddf1..8202fab861 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs @@ -81,7 +81,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings using var response = await _httpClientFactory.CreateClient(NamedClient.Default).GetAsync(path, cancellationToken).ConfigureAwait(false); await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); - await using (var fileStream = new FileStream(cacheFile, FileMode.CreateNew)) + await using (var fileStream = new FileStream(cacheFile, FileMode.CreateNew, FileAccess.Write, FileShare.None, IODefaults.CopyToBufferSize, AsyncFile.UseAsyncIO)) { await stream.CopyToAsync(fileStream, cancellationToken).ConfigureAwait(false); } diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs index 5941613cf9..f87212cf33 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs @@ -92,7 +92,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts try { Directory.CreateDirectory(Path.GetDirectoryName(channelCacheFile)); - await using var writeStream = File.OpenWrite(channelCacheFile); + await using var writeStream = AsyncFile.OpenWrite(channelCacheFile); await JsonSerializer.SerializeAsync(writeStream, channels, cancellationToken: cancellationToken).ConfigureAwait(false); } catch (IOException) @@ -108,7 +108,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts { try { - await using var readStream = File.OpenRead(channelCacheFile); + await using var readStream = AsyncFile.OpenRead(channelCacheFile); var channels = await JsonSerializer.DeserializeAsync>(readStream, cancellationToken: cancellationToken) .ConfigureAwait(false); list.AddRange(channels); diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs index 96a678c1d3..2c21a4a893 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs @@ -155,15 +155,13 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts using var linkedCancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, LiveStreamCancellationTokenSource.Token); cancellationToken = linkedCancellationTokenSource.Token; - // use non-async filestream on windows along with read due to https://github.com/dotnet/corefx/issues/6039 - var allowAsync = Environment.OSVersion.Platform != PlatformID.Win32NT; - bool seekFile = (DateTime.UtcNow - DateOpened).TotalSeconds > 10; var nextFileInfo = GetNextFile(null); var nextFile = nextFileInfo.file; var isLastFile = nextFileInfo.isLastFile; + var allowAsync = AsyncFile.UseAsyncIO; while (!string.IsNullOrEmpty(nextFile)) { var emptyReadLimit = isLastFile ? EmptyReadLimit : 1; diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs index d28c39e213..23071a4306 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs @@ -14,6 +14,7 @@ using Jellyfin.Extensions; using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Net; using MediaBrowser.Controller.LiveTv; +using MediaBrowser.Model.IO; using MediaBrowser.Model.LiveTv; using Microsoft.Extensions.Logging; @@ -50,7 +51,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts if (!info.Url.StartsWith("http", StringComparison.OrdinalIgnoreCase)) { - return File.OpenRead(info.Url); + return AsyncFile.OpenRead(info.Url); } using var requestMessage = new HttpRequestMessage(HttpMethod.Get, info.Url); diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs index f572151b8a..8629938777 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs @@ -129,37 +129,39 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts private Task StartStreaming(HttpResponseMessage response, TaskCompletionSource openTaskCompletionSource, CancellationToken cancellationToken) { - return Task.Run(async () => - { - try - { - Logger.LogInformation("Beginning {0} stream to {1}", GetType().Name, TempFilePath); - using var message = response; - await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); - await using var fileStream = new FileStream(TempFilePath, FileMode.Create, FileAccess.Write, FileShare.Read); - await StreamHelper.CopyToAsync( - stream, - fileStream, - IODefaults.CopyToBufferSize, - () => Resolve(openTaskCompletionSource), - cancellationToken).ConfigureAwait(false); - } - catch (OperationCanceledException ex) - { - Logger.LogInformation("Copying of {0} to {1} was canceled", GetType().Name, TempFilePath); - openTaskCompletionSource.TrySetException(ex); - } - catch (Exception ex) + return Task.Run( + async () => { - Logger.LogError(ex, "Error copying live stream {0} to {1}.", GetType().Name, TempFilePath); - openTaskCompletionSource.TrySetException(ex); - } - - openTaskCompletionSource.TrySetResult(false); - - EnableStreamSharing = false; - await DeleteTempFiles(new List { TempFilePath }).ConfigureAwait(false); - }, CancellationToken.None); + try + { + Logger.LogInformation("Beginning {0} stream to {1}", GetType().Name, TempFilePath); + using var message = response; + await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); + await using var fileStream = new FileStream(TempFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, IODefaults.FileStreamBufferSize, AsyncFile.UseAsyncIO); + await StreamHelper.CopyToAsync( + stream, + fileStream, + IODefaults.CopyToBufferSize, + () => Resolve(openTaskCompletionSource), + cancellationToken).ConfigureAwait(false); + } + catch (OperationCanceledException ex) + { + Logger.LogInformation("Copying of {0} to {1} was canceled", GetType().Name, TempFilePath); + openTaskCompletionSource.TrySetException(ex); + } + catch (Exception ex) + { + Logger.LogError(ex, "Error copying live stream {0} to {1}.", GetType().Name, TempFilePath); + openTaskCompletionSource.TrySetException(ex); + } + + openTaskCompletionSource.TrySetResult(false); + + EnableStreamSharing = false; + await DeleteTempFiles(new List { TempFilePath }).ConfigureAwait(false); + }, + CancellationToken.None); } private void Resolve(TaskCompletionSource openTaskCompletionSource) -- cgit v1.2.3 From 47be1bf69f62d72ecf81cc95347f3c8c5a6a5174 Mon Sep 17 00:00:00 2001 From: Cody Robibero Date: Fri, 3 Sep 2021 10:59:40 -0600 Subject: Enable nullable for SchedulesDirect --- .../LiveTv/Listings/SchedulesDirect.cs | 22 ++++------ .../Listings/SchedulesDirectDtos/BroadcasterDto.cs | 10 ++--- .../Listings/SchedulesDirectDtos/CaptionDto.cs | 6 +-- .../LiveTv/Listings/SchedulesDirectDtos/CastDto.cs | 14 +++---- .../Listings/SchedulesDirectDtos/ChannelDto.cs | 9 ++-- .../SchedulesDirectDtos/ContentRatingDto.cs | 6 +-- .../LiveTv/Listings/SchedulesDirectDtos/CrewDto.cs | 12 +++--- .../LiveTv/Listings/SchedulesDirectDtos/DayDto.cs | 17 ++------ .../SchedulesDirectDtos/Description1000Dto.cs | 6 +-- .../SchedulesDirectDtos/Description100Dto.cs | 6 +-- .../SchedulesDirectDtos/DescriptionsProgramDto.cs | 7 ++-- .../SchedulesDirectDtos/EventDetailsDto.cs | 4 +- .../Listings/SchedulesDirectDtos/GracenoteDto.cs | 2 - .../Listings/SchedulesDirectDtos/HeadendsDto.cs | 11 +++-- .../Listings/SchedulesDirectDtos/ImageDataDto.cs | 22 +++++----- .../Listings/SchedulesDirectDtos/LineupDto.cs | 12 +++--- .../Listings/SchedulesDirectDtos/LineupsDto.cs | 9 ++-- .../LiveTv/Listings/SchedulesDirectDtos/LogoDto.cs | 6 +-- .../LiveTv/Listings/SchedulesDirectDtos/MapDto.cs | 8 ++-- .../Listings/SchedulesDirectDtos/MetadataDto.cs | 8 ++-- .../SchedulesDirectDtos/MetadataProgramsDto.cs | 4 +- .../SchedulesDirectDtos/MetadataScheduleDto.cs | 10 ++--- .../Listings/SchedulesDirectDtos/MovieDto.cs | 7 ++-- .../Listings/SchedulesDirectDtos/MultipartDto.cs | 2 - .../SchedulesDirectDtos/ProgramDetailsDto.cs | 49 +++++++++++----------- .../Listings/SchedulesDirectDtos/ProgramDto.cs | 21 +++++----- .../SchedulesDirectDtos/QualityRatingDto.cs | 12 +++--- .../Listings/SchedulesDirectDtos/RatingDto.cs | 6 +-- .../SchedulesDirectDtos/RecommendationDto.cs | 6 +-- .../RequestScheduleForChannelDto.cs | 7 ++-- .../Listings/SchedulesDirectDtos/ShowImagesDto.cs | 7 ++-- .../Listings/SchedulesDirectDtos/StationDto.cs | 19 ++++----- .../Listings/SchedulesDirectDtos/TitleDto.cs | 4 +- .../Listings/SchedulesDirectDtos/TokenDto.cs | 15 ++++--- 34 files changed, 153 insertions(+), 213 deletions(-) (limited to 'Emby.Server.Implementations/LiveTv') diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs index 8125ed57df..41c3bafa06 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs @@ -16,7 +16,6 @@ using System.Threading; using System.Threading.Tasks; using Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos; using Jellyfin.Extensions.Json; -using MediaBrowser.Common; using MediaBrowser.Common.Net; using MediaBrowser.Controller.LiveTv; using MediaBrowser.Model.Cryptography; @@ -34,7 +33,6 @@ namespace Emby.Server.Implementations.LiveTv.Listings private readonly ILogger _logger; private readonly IHttpClientFactory _httpClientFactory; private readonly SemaphoreSlim _tokenSemaphore = new SemaphoreSlim(1, 1); - private readonly IApplicationHost _appHost; private readonly ICryptoProvider _cryptoProvider; private readonly ConcurrentDictionary _tokens = new ConcurrentDictionary(); @@ -44,12 +42,10 @@ namespace Emby.Server.Implementations.LiveTv.Listings public SchedulesDirect( ILogger logger, IHttpClientFactory httpClientFactory, - IApplicationHost appHost, ICryptoProvider cryptoProvider) { _logger = logger; _httpClientFactory = httpClientFactory; - _appHost = appHost; _cryptoProvider = cryptoProvider; } @@ -120,8 +116,8 @@ namespace Emby.Server.Implementations.LiveTv.Listings using var programRequestOptions = new HttpRequestMessage(HttpMethod.Post, ApiUrl + "/programs"); programRequestOptions.Headers.TryAddWithoutValidation("token", token); - var programsID = dailySchedules.SelectMany(d => d.Programs.Select(s => s.ProgramId)).Distinct(); - programRequestOptions.Content = new StringContent("[\"" + string.Join("\", \"", programsID) + "\"]", Encoding.UTF8, MediaTypeNames.Application.Json); + var programIds = dailySchedules.SelectMany(d => d.Programs.Select(s => s.ProgramId)).Distinct(); + programRequestOptions.Content = new StringContent("[\"" + string.Join("\", \"", programIds) + "\"]", Encoding.UTF8, MediaTypeNames.Application.Json); using var innerResponse = await Send(programRequestOptions, true, info, cancellationToken).ConfigureAwait(false); await using var innerResponseStream = await innerResponse.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); @@ -225,21 +221,21 @@ namespace Emby.Server.Implementations.LiveTv.Listings string newID = programId + "T" + startAt.Ticks + "C" + channelId; - if (programInfo.AudioProperties != null) + if (programInfo.AudioProperties.Count != 0) { - if (programInfo.AudioProperties.Exists(item => string.Equals(item, "atmos", StringComparison.OrdinalIgnoreCase))) + if (programInfo.AudioProperties.Contains("atmos", StringComparer.OrdinalIgnoreCase)) { audioType = ProgramAudio.Atmos; } - else if (programInfo.AudioProperties.Exists(item => string.Equals(item, "dd 5.1", StringComparison.OrdinalIgnoreCase))) + else if (programInfo.AudioProperties.Contains("dd 5.1", StringComparer.OrdinalIgnoreCase)) { audioType = ProgramAudio.DolbyDigital; } - else if (programInfo.AudioProperties.Exists(item => string.Equals(item, "dd", StringComparison.OrdinalIgnoreCase))) + else if (programInfo.AudioProperties.Contains("dd", StringComparer.OrdinalIgnoreCase)) { audioType = ProgramAudio.DolbyDigital; } - else if (programInfo.AudioProperties.Exists(item => string.Equals(item, "stereo", StringComparison.OrdinalIgnoreCase))) + else if (programInfo.AudioProperties.Contains("stereo", StringComparer.OrdinalIgnoreCase)) { audioType = ProgramAudio.Stereo; } @@ -520,7 +516,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings lineups.Add(new NameIdPair { Name = string.IsNullOrWhiteSpace(lineup.Name) ? lineup.Lineup : lineup.Name, - Id = lineup.Uri[18..] + Id = lineup.Uri?[18..] }); } } @@ -790,7 +786,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings { var channelNumber = GetChannelNumber(channel); - var station = allStations.Find(item => string.Equals(item.StationId, channel.StationId, StringComparison.OrdinalIgnoreCase)) + var station = allStations.FirstOrDefault(item => string.Equals(item.StationId, channel.StationId, StringComparison.OrdinalIgnoreCase)) ?? new StationDto { StationId = channel.StationId diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/BroadcasterDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/BroadcasterDto.cs index b881b307c3..95ac996e01 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/BroadcasterDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/BroadcasterDto.cs @@ -1,5 +1,3 @@ -#nullable disable - using System.Text.Json.Serialization; namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos @@ -13,24 +11,24 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the city. /// [JsonPropertyName("city")] - public string City { get; set; } + public string? City { get; set; } /// /// Gets or sets the state. /// [JsonPropertyName("state")] - public string State { get; set; } + public string? State { get; set; } /// /// Gets or sets the postal code. /// [JsonPropertyName("postalCode")] - public string Postalcode { get; set; } + public string? Postalcode { get; set; } /// /// Gets or sets the country. /// [JsonPropertyName("country")] - public string Country { get; set; } + public string? Country { get; set; } } } diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/CaptionDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/CaptionDto.cs index 96b67d1eb3..f6251b9ad8 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/CaptionDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/CaptionDto.cs @@ -1,5 +1,3 @@ -#nullable disable - using System.Text.Json.Serialization; namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos @@ -13,12 +11,12 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the content. /// [JsonPropertyName("content")] - public string Content { get; set; } + public string? Content { get; set; } /// /// Gets or sets the lang. /// [JsonPropertyName("lang")] - public string Lang { get; set; } + public string? Lang { get; set; } } } diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/CastDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/CastDto.cs index dac6f5f3e0..0b7a2c63ad 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/CastDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/CastDto.cs @@ -1,5 +1,3 @@ -#nullable disable - using System.Text.Json.Serialization; namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos @@ -13,36 +11,36 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the billing order. /// [JsonPropertyName("billingOrder")] - public string BillingOrder { get; set; } + public string? BillingOrder { get; set; } /// /// Gets or sets the role. /// [JsonPropertyName("role")] - public string Role { get; set; } + public string? Role { get; set; } /// /// Gets or sets the name id. /// [JsonPropertyName("nameId")] - public string NameId { get; set; } + public string? NameId { get; set; } /// /// Gets or sets the person id. /// [JsonPropertyName("personId")] - public string PersonId { get; set; } + public string? PersonId { get; set; } /// /// Gets or sets the name. /// [JsonPropertyName("name")] - public string Name { get; set; } + public string? Name { get; set; } /// /// Gets or sets the character name. /// [JsonPropertyName("characterName")] - public string CharacterName { get; set; } + public string? CharacterName { get; set; } } } diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ChannelDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ChannelDto.cs index 8c9c2c1fcc..87c327ed82 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ChannelDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ChannelDto.cs @@ -1,5 +1,4 @@ -#nullable disable - +using System; using System.Collections.Generic; using System.Text.Json.Serialization; @@ -14,18 +13,18 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the list of maps. /// [JsonPropertyName("map")] - public List Map { get; set; } + public IReadOnlyList Map { get; set; } = Array.Empty(); /// /// Gets or sets the list of stations. /// [JsonPropertyName("stations")] - public List Stations { get; set; } + public IReadOnlyList Stations { get; set; } = Array.Empty(); /// /// Gets or sets the metadata. /// [JsonPropertyName("metadata")] - public MetadataDto Metadata { get; set; } + public MetadataDto? Metadata { get; set; } } } diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ContentRatingDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ContentRatingDto.cs index 135b5bb08b..c19cd2e48d 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ContentRatingDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ContentRatingDto.cs @@ -1,5 +1,3 @@ -#nullable disable - using System.Text.Json.Serialization; namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos @@ -13,12 +11,12 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the body. /// [JsonPropertyName("body")] - public string Body { get; set; } + public string? Body { get; set; } /// /// Gets or sets the code. /// [JsonPropertyName("code")] - public string Code { get; set; } + public string? Code { get; set; } } } diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/CrewDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/CrewDto.cs index 82d1001c88..f00c9accdd 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/CrewDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/CrewDto.cs @@ -1,5 +1,3 @@ -#nullable disable - using System.Text.Json.Serialization; namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos @@ -13,30 +11,30 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the billing order. /// [JsonPropertyName("billingOrder")] - public string BillingOrder { get; set; } + public string? BillingOrder { get; set; } /// /// Gets or sets the role. /// [JsonPropertyName("role")] - public string Role { get; set; } + public string? Role { get; set; } /// /// Gets or sets the name id. /// [JsonPropertyName("nameId")] - public string NameId { get; set; } + public string? NameId { get; set; } /// /// Gets or sets the person id. /// [JsonPropertyName("personId")] - public string PersonId { get; set; } + public string? PersonId { get; set; } /// /// Gets or sets the name. /// [JsonPropertyName("name")] - public string Name { get; set; } + public string? Name { get; set; } } } diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/DayDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/DayDto.cs index 68876b0686..1a371965cf 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/DayDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/DayDto.cs @@ -1,5 +1,4 @@ -#nullable disable - +using System; using System.Collections.Generic; using System.Text.Json.Serialization; @@ -10,30 +9,22 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// public class DayDto { - /// - /// Initializes a new instance of the class. - /// - public DayDto() - { - Programs = new List(); - } - /// /// Gets or sets the station id. /// [JsonPropertyName("stationID")] - public string StationId { get; set; } + public string? StationId { get; set; } /// /// Gets or sets the list of programs. /// [JsonPropertyName("programs")] - public List Programs { get; set; } + public IReadOnlyList Programs { get; set; } = Array.Empty(); /// /// Gets or sets the metadata schedule. /// [JsonPropertyName("metadata")] - public MetadataScheduleDto Metadata { get; set; } + public MetadataScheduleDto? Metadata { get; set; } } } diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/Description1000Dto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/Description1000Dto.cs index d3e6ff3935..ca6ae7fb13 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/Description1000Dto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/Description1000Dto.cs @@ -1,5 +1,3 @@ -#nullable disable - using System.Text.Json.Serialization; namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos @@ -13,12 +11,12 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the description language. /// [JsonPropertyName("descriptionLanguage")] - public string DescriptionLanguage { get; set; } + public string? DescriptionLanguage { get; set; } /// /// Gets or sets the description. /// [JsonPropertyName("description")] - public string Description { get; set; } + public string? Description { get; set; } } } diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/Description100Dto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/Description100Dto.cs index 04360266c9..1577219ed2 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/Description100Dto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/Description100Dto.cs @@ -1,5 +1,3 @@ -#nullable disable - using System.Text.Json.Serialization; namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos @@ -13,12 +11,12 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the description language. /// [JsonPropertyName("descriptionLanguage")] - public string DescriptionLanguage { get; set; } + public string? DescriptionLanguage { get; set; } /// /// Gets or sets the description. /// [JsonPropertyName("description")] - public string Description { get; set; } + public string? Description { get; set; } } } diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/DescriptionsProgramDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/DescriptionsProgramDto.cs index 3af36ae965..eaf4a340bd 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/DescriptionsProgramDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/DescriptionsProgramDto.cs @@ -1,5 +1,4 @@ -#nullable disable - +using System; using System.Collections.Generic; using System.Text.Json.Serialization; @@ -14,12 +13,12 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the list of description 100. /// [JsonPropertyName("description100")] - public List Description100 { get; set; } + public IReadOnlyList Description100 { get; set; } = Array.Empty(); /// /// Gets or sets the list of description1000. /// [JsonPropertyName("description1000")] - public List Description1000 { get; set; } + public IReadOnlyList Description1000 { get; set; } = Array.Empty(); } } diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/EventDetailsDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/EventDetailsDto.cs index c3b2bd9c13..fbdfb1f716 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/EventDetailsDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/EventDetailsDto.cs @@ -1,5 +1,3 @@ -#nullable disable - using System.Text.Json.Serialization; namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos @@ -13,6 +11,6 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the sub type. /// [JsonPropertyName("subType")] - public string SubType { get; set; } + public string? SubType { get; set; } } } diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/GracenoteDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/GracenoteDto.cs index 3d8bea362a..6852d89d71 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/GracenoteDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/GracenoteDto.cs @@ -1,5 +1,3 @@ -#nullable disable - using System.Text.Json.Serialization; namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/HeadendsDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/HeadendsDto.cs index 1fb3decb23..b9844562f3 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/HeadendsDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/HeadendsDto.cs @@ -1,5 +1,4 @@ -#nullable disable - +using System; using System.Collections.Generic; using System.Text.Json.Serialization; @@ -14,24 +13,24 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the headend. /// [JsonPropertyName("headend")] - public string Headend { get; set; } + public string? Headend { get; set; } /// /// Gets or sets the transport. /// [JsonPropertyName("transport")] - public string Transport { get; set; } + public string? Transport { get; set; } /// /// Gets or sets the location. /// [JsonPropertyName("location")] - public string Location { get; set; } + public string? Location { get; set; } /// /// Gets or sets the list of lineups. /// [JsonPropertyName("lineups")] - public List Lineups { get; set; } + public IReadOnlyList Lineups { get; set; } = Array.Empty(); } } diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ImageDataDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ImageDataDto.cs index 912e680dd7..7e554ff1ce 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ImageDataDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ImageDataDto.cs @@ -1,5 +1,3 @@ -#nullable disable - using System.Text.Json.Serialization; namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos @@ -13,60 +11,60 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the width. /// [JsonPropertyName("width")] - public string Width { get; set; } + public string? Width { get; set; } /// /// Gets or sets the height. /// [JsonPropertyName("height")] - public string Height { get; set; } + public string? Height { get; set; } /// /// Gets or sets the uri. /// [JsonPropertyName("uri")] - public string Uri { get; set; } + public string? Uri { get; set; } /// /// Gets or sets the size. /// [JsonPropertyName("size")] - public string Size { get; set; } + public string? Size { get; set; } /// /// Gets or sets the aspect. /// [JsonPropertyName("aspect")] - public string aspect { get; set; } + public string? aspect { get; set; } /// /// Gets or sets the category. /// [JsonPropertyName("category")] - public string Category { get; set; } + public string? Category { get; set; } /// /// Gets or sets the text. /// [JsonPropertyName("text")] - public string Text { get; set; } + public string? Text { get; set; } /// /// Gets or sets the primary. /// [JsonPropertyName("primary")] - public string Primary { get; set; } + public string? Primary { get; set; } /// /// Gets or sets the tier. /// [JsonPropertyName("tier")] - public string Tier { get; set; } + public string? Tier { get; set; } /// /// Gets or sets the caption. /// [JsonPropertyName("caption")] - public CaptionDto Caption { get; set; } + public CaptionDto? Caption { get; set; } } } diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/LineupDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/LineupDto.cs index 52e920aa61..676e745258 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/LineupDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/LineupDto.cs @@ -1,5 +1,3 @@ -#nullable disable - using System.Text.Json.Serialization; namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos @@ -13,30 +11,30 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the linup. /// [JsonPropertyName("lineup")] - public string Lineup { get; set; } + public string? Lineup { get; set; } /// /// Gets or sets the lineup name. /// [JsonPropertyName("name")] - public string Name { get; set; } + public string? Name { get; set; } /// /// Gets or sets the transport. /// [JsonPropertyName("transport")] - public string Transport { get; set; } + public string? Transport { get; set; } /// /// Gets or sets the location. /// [JsonPropertyName("location")] - public string Location { get; set; } + public string? Location { get; set; } /// /// Gets or sets the uri. /// [JsonPropertyName("uri")] - public string Uri { get; set; } + public string? Uri { get; set; } } } diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/LineupsDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/LineupsDto.cs index 15139ba3b2..b0ee0ac8eb 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/LineupsDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/LineupsDto.cs @@ -1,5 +1,4 @@ -#nullable disable - +using System; using System.Collections.Generic; using System.Text.Json.Serialization; @@ -20,18 +19,18 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the server id. /// [JsonPropertyName("serverID")] - public string ServerId { get; set; } + public string? ServerId { get; set; } /// /// Gets or sets the datetime. /// [JsonPropertyName("datetime")] - public string Datetime { get; set; } + public string? Datetime { get; set; } /// /// Gets or sets the list of lineups. /// [JsonPropertyName("lineups")] - public List Lineups { get; set; } + public IReadOnlyList Lineups { get; set; } = Array.Empty(); } } diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/LogoDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/LogoDto.cs index 7b235ed7f6..fecc55e037 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/LogoDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/LogoDto.cs @@ -1,5 +1,3 @@ -#nullable disable - using System.Text.Json.Serialization; namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos @@ -13,7 +11,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the url. /// [JsonPropertyName("URL")] - public string Url { get; set; } + public string? Url { get; set; } /// /// Gets or sets the height. @@ -31,6 +29,6 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the md5. /// [JsonPropertyName("md5")] - public string Md5 { get; set; } + public string? Md5 { get; set; } } } diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MapDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MapDto.cs index 5140277b2c..cc1841c176 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MapDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MapDto.cs @@ -1,5 +1,3 @@ -#nullable disable - using System.Text.Json.Serialization; namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos @@ -13,19 +11,19 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the station id. /// [JsonPropertyName("stationID")] - public string StationId { get; set; } + public string? StationId { get; set; } /// /// Gets or sets the channel. /// [JsonPropertyName("channel")] - public string Channel { get; set; } + public string? Channel { get; set; } /// /// Gets or sets the logical channel number. /// [JsonPropertyName("logicalChannelNumber")] - public string LogicalChannelNumber { get; set; } + public string? LogicalChannelNumber { get; set; } /// /// Gets or sets the uhfvhf. diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MetadataDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MetadataDto.cs index 5a3893a35f..40faa493c5 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MetadataDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MetadataDto.cs @@ -1,5 +1,3 @@ -#nullable disable - using System.Text.Json.Serialization; namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos @@ -13,18 +11,18 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the linup. /// [JsonPropertyName("lineup")] - public string Lineup { get; set; } + public string? Lineup { get; set; } /// /// Gets or sets the modified timestamp. /// [JsonPropertyName("modified")] - public string Modified { get; set; } + public string? Modified { get; set; } /// /// Gets or sets the transport. /// [JsonPropertyName("transport")] - public string Transport { get; set; } + public string? Transport { get; set; } } } diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MetadataProgramsDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MetadataProgramsDto.cs index 4057e98024..843ef9091d 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MetadataProgramsDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MetadataProgramsDto.cs @@ -1,5 +1,3 @@ -#nullable disable - using System.Text.Json.Serialization; namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos @@ -13,6 +11,6 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the gracenote object. /// [JsonPropertyName("gracenote")] - public GracenoteDto Gracenote { get; set; } + public GracenoteDto? Gracenote { get; set; } } } diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MetadataScheduleDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MetadataScheduleDto.cs index 4979296da4..68fbeec46d 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MetadataScheduleDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MetadataScheduleDto.cs @@ -1,5 +1,3 @@ -#nullable disable - using System.Text.Json.Serialization; namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos @@ -13,25 +11,25 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the modified timestamp. /// [JsonPropertyName("modified")] - public string Modified { get; set; } + public string? Modified { get; set; } /// /// Gets or sets the md5. /// [JsonPropertyName("md5")] - public string Md5 { get; set; } + public string? Md5 { get; set; } /// /// Gets or sets the start date. /// [JsonPropertyName("startDate")] - public string StartDate { get; set; } + public string? StartDate { get; set; } /// /// Gets or sets the end date. /// [JsonPropertyName("endDate")] - public string EndDate { get; set; } + public string? EndDate { get; set; } /// /// Gets or sets the days count. diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MovieDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MovieDto.cs index 48d731d890..31bef423b2 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MovieDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MovieDto.cs @@ -1,5 +1,4 @@ -#nullable disable - +using System; using System.Collections.Generic; using System.Text.Json.Serialization; @@ -14,7 +13,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the year. /// [JsonPropertyName("year")] - public string Year { get; set; } + public string? Year { get; set; } /// /// Gets or sets the duration. @@ -26,6 +25,6 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the list of quality rating. /// [JsonPropertyName("qualityRating")] - public List QualityRating { get; set; } + public IReadOnlyList QualityRating { get; set; } = Array.Empty(); } } diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MultipartDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MultipartDto.cs index 42eddfff26..e8b15dc07c 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MultipartDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MultipartDto.cs @@ -1,5 +1,3 @@ -#nullable disable - using System.Text.Json.Serialization; namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ProgramDetailsDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ProgramDetailsDto.cs index a84c47c129..bfaed1e081 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ProgramDetailsDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ProgramDetailsDto.cs @@ -1,5 +1,4 @@ -#nullable disable - +using System; using System.Collections.Generic; using System.Text.Json.Serialization; @@ -14,85 +13,85 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the audience. /// [JsonPropertyName("audience")] - public string Audience { get; set; } + public string? Audience { get; set; } /// /// Gets or sets the program id. /// [JsonPropertyName("programID")] - public string ProgramId { get; set; } + public string? ProgramId { get; set; } /// /// Gets or sets the list of titles. /// [JsonPropertyName("titles")] - public List Titles { get; set; } + public IReadOnlyList Titles { get; set; } = Array.Empty(); /// /// Gets or sets the event details object. /// [JsonPropertyName("eventDetails")] - public EventDetailsDto EventDetails { get; set; } + public EventDetailsDto? EventDetails { get; set; } /// /// Gets or sets the descriptions. /// [JsonPropertyName("descriptions")] - public DescriptionsProgramDto Descriptions { get; set; } + public DescriptionsProgramDto? Descriptions { get; set; } /// /// Gets or sets the original air date. /// [JsonPropertyName("originalAirDate")] - public string OriginalAirDate { get; set; } + public string? OriginalAirDate { get; set; } /// /// Gets or sets the list of genres. /// [JsonPropertyName("genres")] - public List Genres { get; set; } + public IReadOnlyList Genres { get; set; } = Array.Empty(); /// /// Gets or sets the episode title. /// [JsonPropertyName("episodeTitle150")] - public string EpisodeTitle150 { get; set; } + public string? EpisodeTitle150 { get; set; } /// /// Gets or sets the list of metadata. /// [JsonPropertyName("metadata")] - public List Metadata { get; set; } + public IReadOnlyList Metadata { get; set; } = Array.Empty(); /// /// Gets or sets the list of content raitings. /// [JsonPropertyName("contentRating")] - public List ContentRating { get; set; } + public IReadOnlyList ContentRating { get; set; } = Array.Empty(); /// /// Gets or sets the list of cast. /// [JsonPropertyName("cast")] - public List Cast { get; set; } + public IReadOnlyList Cast { get; set; } = Array.Empty(); /// /// Gets or sets the list of crew. /// [JsonPropertyName("crew")] - public List Crew { get; set; } + public IReadOnlyList Crew { get; set; } = Array.Empty(); /// /// Gets or sets the entity type. /// [JsonPropertyName("entityType")] - public string EntityType { get; set; } + public string? EntityType { get; set; } /// /// Gets or sets the show type. /// [JsonPropertyName("showType")] - public string ShowType { get; set; } + public string? ShowType { get; set; } /// /// Gets or sets a value indicating whether there is image artwork. @@ -104,54 +103,54 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the primary image. /// [JsonPropertyName("primaryImage")] - public string PrimaryImage { get; set; } + public string? PrimaryImage { get; set; } /// /// Gets or sets the thumb image. /// [JsonPropertyName("thumbImage")] - public string ThumbImage { get; set; } + public string? ThumbImage { get; set; } /// /// Gets or sets the backdrop image. /// [JsonPropertyName("backdropImage")] - public string BackdropImage { get; set; } + public string? BackdropImage { get; set; } /// /// Gets or sets the banner image. /// [JsonPropertyName("bannerImage")] - public string BannerImage { get; set; } + public string? BannerImage { get; set; } /// /// Gets or sets the image id. /// [JsonPropertyName("imageID")] - public string ImageId { get; set; } + public string? ImageId { get; set; } /// /// Gets or sets the md5. /// [JsonPropertyName("md5")] - public string Md5 { get; set; } + public string? Md5 { get; set; } /// /// Gets or sets the list of content advisory. /// [JsonPropertyName("contentAdvisory")] - public List ContentAdvisory { get; set; } + public IReadOnlyList ContentAdvisory { get; set; } = Array.Empty(); /// /// Gets or sets the movie object. /// [JsonPropertyName("movie")] - public MovieDto Movie { get; set; } + public MovieDto? Movie { get; set; } /// /// Gets or sets the list of recommendations. /// [JsonPropertyName("recommendations")] - public List Recommendations { get; set; } + public IReadOnlyList Recommendations { get; set; } = Array.Empty(); } } diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ProgramDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ProgramDto.cs index ad5389100c..ff039c1cf1 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ProgramDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ProgramDto.cs @@ -1,5 +1,4 @@ -#nullable disable - +using System; using System.Collections.Generic; using System.Text.Json.Serialization; @@ -14,13 +13,13 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the program id. /// [JsonPropertyName("programID")] - public string ProgramId { get; set; } + public string? ProgramId { get; set; } /// /// Gets or sets the air date time. /// [JsonPropertyName("airDateTime")] - public string AirDateTime { get; set; } + public string? AirDateTime { get; set; } /// /// Gets or sets the duration. @@ -32,25 +31,25 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the md5. /// [JsonPropertyName("md5")] - public string Md5 { get; set; } + public string? Md5 { get; set; } /// /// Gets or sets the list of audio properties. /// [JsonPropertyName("audioProperties")] - public List AudioProperties { get; set; } + public IReadOnlyList AudioProperties { get; set; } = Array.Empty(); /// /// Gets or sets the list of video properties. /// [JsonPropertyName("videoProperties")] - public List VideoProperties { get; set; } + public IReadOnlyList VideoProperties { get; set; } = Array.Empty(); /// /// Gets or sets the list of ratings. /// [JsonPropertyName("ratings")] - public List Ratings { get; set; } + public IReadOnlyList Ratings { get; set; } = Array.Empty(); /// /// Gets or sets a value indicating whether this program is new. @@ -62,13 +61,13 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the multipart object. /// [JsonPropertyName("multipart")] - public MultipartDto Multipart { get; set; } + public MultipartDto? Multipart { get; set; } /// /// Gets or sets the live tape delay. /// [JsonPropertyName("liveTapeDelay")] - public string LiveTapeDelay { get; set; } + public string? LiveTapeDelay { get; set; } /// /// Gets or sets a value indicating whether this is the premiere. @@ -86,6 +85,6 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the premiere or finale. /// [JsonPropertyName("isPremiereOrFinale")] - public string IsPremiereOrFinale { get; set; } + public string? IsPremiereOrFinale { get; set; } } } diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/QualityRatingDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/QualityRatingDto.cs index 5cd0a74595..c5ddcf7c51 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/QualityRatingDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/QualityRatingDto.cs @@ -1,5 +1,3 @@ -#nullable disable - using System.Text.Json.Serialization; namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos @@ -13,30 +11,30 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the ratings body. /// [JsonPropertyName("ratingsBody")] - public string RatingsBody { get; set; } + public string? RatingsBody { get; set; } /// /// Gets or sets the rating. /// [JsonPropertyName("rating")] - public string Rating { get; set; } + public string? Rating { get; set; } /// /// Gets or sets the min rating. /// [JsonPropertyName("minRating")] - public string MinRating { get; set; } + public string? MinRating { get; set; } /// /// Gets or sets the max rating. /// [JsonPropertyName("maxRating")] - public string MaxRating { get; set; } + public string? MaxRating { get; set; } /// /// Gets or sets the increment. /// [JsonPropertyName("increment")] - public string Increment { get; set; } + public string? Increment { get; set; } } } diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/RatingDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/RatingDto.cs index 948b831446..e04b619a4d 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/RatingDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/RatingDto.cs @@ -1,5 +1,3 @@ -#nullable disable - using System.Text.Json.Serialization; namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos @@ -13,12 +11,12 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the body. /// [JsonPropertyName("body")] - public string Body { get; set; } + public string? Body { get; set; } /// /// Gets or sets the code. /// [JsonPropertyName("code")] - public string Code { get; set; } + public string? Code { get; set; } } } diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/RecommendationDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/RecommendationDto.cs index 1308f45ce7..c8f79fd1c2 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/RecommendationDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/RecommendationDto.cs @@ -1,5 +1,3 @@ -#nullable disable - using System.Text.Json.Serialization; namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos @@ -13,12 +11,12 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the program id. /// [JsonPropertyName("programID")] - public string ProgramId { get; set; } + public string? ProgramId { get; set; } /// /// Gets or sets the title. /// [JsonPropertyName("title120")] - public string Title120 { get; set; } + public string? Title120 { get; set; } } } diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/RequestScheduleForChannelDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/RequestScheduleForChannelDto.cs index fb7a31ac85..0cd05709b3 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/RequestScheduleForChannelDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/RequestScheduleForChannelDto.cs @@ -1,5 +1,4 @@ -#nullable disable - +using System; using System.Collections.Generic; using System.Text.Json.Serialization; @@ -14,12 +13,12 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the station id. /// [JsonPropertyName("stationID")] - public string StationId { get; set; } + public string? StationId { get; set; } /// /// Gets or sets the list of dates. /// [JsonPropertyName("date")] - public List Date { get; set; } + public IReadOnlyList Date { get; set; } = Array.Empty(); } } diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ShowImagesDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ShowImagesDto.cs index 34302370d6..84e224b71e 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ShowImagesDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ShowImagesDto.cs @@ -1,5 +1,4 @@ -#nullable disable - +using System; using System.Collections.Generic; using System.Text.Json.Serialization; @@ -14,12 +13,12 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the program id. /// [JsonPropertyName("programID")] - public string ProgramId { get; set; } + public string? ProgramId { get; set; } /// /// Gets or sets the list of data. /// [JsonPropertyName("data")] - public List Data { get; set; } + public IReadOnlyList Data { get; set; } = Array.Empty(); } } diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/StationDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/StationDto.cs index 12f3576c65..1b76b22e32 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/StationDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/StationDto.cs @@ -1,5 +1,4 @@ -#nullable disable - +using System; using System.Collections.Generic; using System.Text.Json.Serialization; @@ -14,49 +13,49 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the station id. /// [JsonPropertyName("stationID")] - public string StationId { get; set; } + public string? StationId { get; set; } /// /// Gets or sets the name. /// [JsonPropertyName("name")] - public string Name { get; set; } + public string? Name { get; set; } /// /// Gets or sets the callsign. /// [JsonPropertyName("callsign")] - public string Callsign { get; set; } + public string? Callsign { get; set; } /// /// Gets or sets the broadcast language. /// [JsonPropertyName("broadcastLanguage")] - public List BroadcastLanguage { get; set; } + public IReadOnlyList BroadcastLanguage { get; set; } = Array.Empty(); /// /// Gets or sets the description language. /// [JsonPropertyName("descriptionLanguage")] - public List DescriptionLanguage { get; set; } + public IReadOnlyList DescriptionLanguage { get; set; } = Array.Empty(); /// /// Gets or sets the broadcaster. /// [JsonPropertyName("broadcaster")] - public BroadcasterDto Broadcaster { get; set; } + public BroadcasterDto? Broadcaster { get; set; } /// /// Gets or sets the affiliate. /// [JsonPropertyName("affiliate")] - public string Affiliate { get; set; } + public string? Affiliate { get; set; } /// /// Gets or sets the logo. /// [JsonPropertyName("logo")] - public LogoDto Logo { get; set; } + public LogoDto? Logo { get; set; } /// /// Gets or set a value indicating whether it is commercial free. diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/TitleDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/TitleDto.cs index 06c95524b0..61cd4a9b00 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/TitleDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/TitleDto.cs @@ -1,5 +1,3 @@ -#nullable disable - using System.Text.Json.Serialization; namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos @@ -13,6 +11,6 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the title. /// [JsonPropertyName("title120")] - public string Title120 { get; set; } + public string? Title120 { get; set; } } } diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/TokenDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/TokenDto.cs index c3ec1c7d61..fb5ed95ac9 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/TokenDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/TokenDto.cs @@ -1,5 +1,4 @@ -#nullable disable - +using System; using System.Text.Json.Serialization; namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos @@ -19,18 +18,24 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the response message. /// [JsonPropertyName("message")] - public string Message { get; set; } + public string? Message { get; set; } /// /// Gets or sets the server id. /// [JsonPropertyName("serverID")] - public string ServerId { get; set; } + public string? ServerId { get; set; } /// /// Gets or sets the token. /// [JsonPropertyName("token")] - public string Token { get; set; } + public string? Token { get; set; } + + /// + /// Gets or sets the current datetime. + /// + [JsonPropertyName("datetime")] + public DateTime? DateTime { get; set; } } } -- cgit v1.2.3 From 47e24a2cf77e6c3fe50eb5398fa56950a047ed7b Mon Sep 17 00:00:00 2001 From: Cody Robibero Date: Fri, 3 Sep 2021 12:35:52 -0600 Subject: Add SchedulesDirect json tests --- .../LiveTv/Listings/SchedulesDirect.cs | 62 +++--- .../Listings/SchedulesDirectDtos/ImageDataDto.cs | 2 +- .../Listings/SchedulesDirectDtos/LineupDto.cs | 6 + .../Listings/SchedulesDirectDtos/LineupsDto.cs | 2 +- .../LiveTv/Listings/SchedulesDirectDtos/MapDto.cs | 12 + .../SchedulesDirectDtos/MetadataProgramsDto.cs | 2 +- .../SchedulesDirectDtos/ProgramDetailsDto.cs | 2 +- .../Listings/SchedulesDirectDtos/ProgramDto.cs | 2 +- .../Listings/SchedulesDirectDtos/TokenDto.cs | 6 + .../Jellyfin.Server.Implementations.Tests.csproj | 3 + .../SchedulesDirectDeserializeTests.cs | 245 +++++++++++++++++++++ .../TestData/headends_response.json | 113 ++++++++++ .../SchedulesDirect/TestData/lineup_response.json | 18 ++ .../SchedulesDirect/TestData/lineups_response.json | 40 ++++ .../TestData/metadata_programs_response.json | 51 +++++ .../TestData/programs_response.json | 245 +++++++++++++++++++++ .../TestData/schedules_request.json | 16 ++ .../TestData/schedules_response.json | 35 +++ .../TestData/token_live_response.json | 7 + .../TestData/token_offline_response.json | 8 + 20 files changed, 841 insertions(+), 36 deletions(-) create mode 100644 tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/SchedulesDirectDeserializeTests.cs create mode 100644 tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/headends_response.json create mode 100644 tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/lineup_response.json create mode 100644 tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/lineups_response.json create mode 100644 tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/metadata_programs_response.json create mode 100644 tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/programs_response.json create mode 100644 tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/schedules_request.json create mode 100644 tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/schedules_response.json create mode 100644 tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/token_live_response.json create mode 100644 tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/token_offline_response.json (limited to 'Emby.Server.Implementations/LiveTv') diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs index 41c3bafa06..e8562b8c57 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs @@ -9,12 +9,14 @@ using System.Globalization; using System.Linq; using System.Net; using System.Net.Http; +using System.Net.Http.Json; using System.Net.Mime; using System.Text; using System.Text.Json; using System.Threading; using System.Threading.Tasks; using Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos; +using Jellyfin.Extensions; using Jellyfin.Extensions.Json; using MediaBrowser.Common.Net; using MediaBrowser.Controller.LiveTv; @@ -110,19 +112,19 @@ namespace Emby.Server.Implementations.LiveTv.Listings options.Headers.TryAddWithoutValidation("token", token); 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 JsonSerializer.DeserializeAsync>(responseStream, _jsonOptions, cancellationToken).ConfigureAwait(false); - _logger.LogDebug("Found {ScheduleCount} programs on {ChannelID} ScheduleDirect", dailySchedules.Count, channelId); + var dailySchedules = await JsonSerializer.DeserializeAsync>(responseStream, _jsonOptions, cancellationToken).ConfigureAwait(false); + _logger.LogDebug("Found {ScheduleCount} programs on {ChannelID} ScheduleDirect", dailySchedules!.Count, channelId); using var programRequestOptions = new HttpRequestMessage(HttpMethod.Post, ApiUrl + "/programs"); programRequestOptions.Headers.TryAddWithoutValidation("token", token); var programIds = dailySchedules.SelectMany(d => d.Programs.Select(s => s.ProgramId)).Distinct(); - programRequestOptions.Content = new StringContent("[\"" + string.Join("\", \"", programIds) + "\"]", Encoding.UTF8, MediaTypeNames.Application.Json); + programRequestOptions.Content = new StringContent(JsonSerializer.Serialize(programIds), Encoding.UTF8, MediaTypeNames.Application.Json); 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 JsonSerializer.DeserializeAsync>(innerResponseStream, _jsonOptions, cancellationToken).ConfigureAwait(false); - var programDict = programDetails.ToDictionary(p => p.ProgramId, y => y); + var programDetails = await JsonSerializer.DeserializeAsync>(innerResponseStream, _jsonOptions, cancellationToken).ConfigureAwait(false); + var programDict = programDetails!.ToDictionary(p => p.ProgramId, y => y); var programIdsWithImages = programDetails .Where(p => p.HasImageArtwork).Select(p => p.ProgramId) @@ -138,6 +140,11 @@ namespace Emby.Server.Implementations.LiveTv.Listings // schedule.ProgramId + " which says it has images? " + // programDict[schedule.ProgramId].hasImageArtwork); + if (string.IsNullOrEmpty(schedule.ProgramId)) + { + continue; + } + if (images != null) { var imageIndex = images.FindIndex(i => i.ProgramId == schedule.ProgramId[..10]); @@ -145,7 +152,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings { var programEntry = programDict[schedule.ProgramId]; - var allImages = images[imageIndex].Data ?? new List(); + var allImages = images[imageIndex].Data; var imagesWithText = allImages.Where(i => string.Equals(i.Text, "yes", StringComparison.OrdinalIgnoreCase)); var imagesWithoutText = allImages.Where(i => string.Equals(i.Text, "no", StringComparison.OrdinalIgnoreCase)); @@ -213,7 +220,12 @@ namespace Emby.Server.Implementations.LiveTv.Listings private ProgramInfo GetProgram(string channelId, ProgramDto programInfo, ProgramDetailsDto details) { - var startAt = GetDate(programInfo.AirDateTime); + if (programInfo.AirDateTime == null) + { + return null; + } + + var startAt = programInfo.AirDateTime.Value; var endAt = startAt.AddSeconds(programInfo.Duration); var audioType = ProgramAudio.Stereo; @@ -351,9 +363,9 @@ namespace Emby.Server.Implementations.LiveTv.Listings } } - if (!string.IsNullOrWhiteSpace(details.OriginalAirDate)) + if (details.OriginalAirDate != null) { - info.OriginalAirDate = DateTime.Parse(details.OriginalAirDate, CultureInfo.InvariantCulture); + info.OriginalAirDate = details.OriginalAirDate; info.ProductionYear = info.OriginalAirDate.Value.Year; } @@ -380,18 +392,6 @@ namespace Emby.Server.Implementations.LiveTv.Listings return info; } - private static DateTime GetDate(string value) - { - var date = DateTime.ParseExact(value, "yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'", CultureInfo.InvariantCulture); - - if (date.Kind != DateTimeKind.Utc) - { - date = DateTime.SpecifyKind(date, DateTimeKind.Utc); - } - - return date; - } - private string GetProgramImage(string apiUrl, IEnumerable images, bool returnDefaultImage, double desiredAspect) { var match = images @@ -445,14 +445,14 @@ namespace Emby.Server.Implementations.LiveTv.Listings return result; } - private async Task> GetImageForPrograms( + private async Task> GetImageForPrograms( ListingsProviderInfo info, IReadOnlyList programIds, CancellationToken cancellationToken) { if (programIds.Count == 0) { - return new List(); + return Array.Empty(); } StringBuilder str = new StringBuilder("[", 1 + (programIds.Count * 13)); @@ -476,13 +476,13 @@ namespace Emby.Server.Implementations.LiveTv.Listings { using var innerResponse2 = await Send(message, true, info, cancellationToken).ConfigureAwait(false); await using var response = await innerResponse2.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); - return await JsonSerializer.DeserializeAsync>(response, _jsonOptions, cancellationToken).ConfigureAwait(false); + return await JsonSerializer.DeserializeAsync>(response, _jsonOptions, cancellationToken).ConfigureAwait(false); } catch (Exception ex) { _logger.LogError(ex, "Error getting image info from schedules direct"); - return new List(); + return Array.Empty(); } } @@ -505,7 +505,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings 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 JsonSerializer.DeserializeAsync>(response, _jsonOptions, cancellationToken).ConfigureAwait(false); + var root = await JsonSerializer.DeserializeAsync>(response, _jsonOptions, cancellationToken).ConfigureAwait(false); if (root != null) { @@ -647,7 +647,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings response.EnsureSuccessStatusCode(); await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); var root = await JsonSerializer.DeserializeAsync(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); return root.Token; @@ -704,12 +704,12 @@ namespace Emby.Server.Implementations.LiveTv.Listings using var response = httpResponse.Content; var root = await JsonSerializer.DeserializeAsync(stream, _jsonOptions, cancellationToken).ConfigureAwait(false); - return root.Lineups.Any(i => string.Equals(info.ListingsId, i.Lineup, StringComparison.OrdinalIgnoreCase)); + return root?.Lineups.Any(i => string.Equals(info.ListingsId, i.Lineup, StringComparison.OrdinalIgnoreCase)) ?? false; } catch (HttpRequestException ex) { // SchedulesDirect returns 400 if no lineups are configured. - if (ex.StatusCode.HasValue && ex.StatusCode.Value == HttpStatusCode.BadRequest) + if (ex.StatusCode is HttpStatusCode.BadRequest) { return false; } @@ -775,10 +775,10 @@ namespace Emby.Server.Implementations.LiveTv.Listings 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 JsonSerializer.DeserializeAsync(stream, _jsonOptions, cancellationToken).ConfigureAwait(false); - _logger.LogInformation("Found {ChannelCount} channels on the lineup on ScheduleDirect", root.Map.Count); + _logger.LogInformation("Found {ChannelCount} channels on the lineup on ScheduleDirect", root!.Map.Count); _logger.LogInformation("Mapping Stations to Channel"); - var allStations = root.Stations ?? new List(); + var allStations = root.Stations; var map = root.Map; var list = new List(map.Count); diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ImageDataDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ImageDataDto.cs index 7e554ff1ce..a1ae3ca6d4 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ImageDataDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ImageDataDto.cs @@ -35,7 +35,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the aspect. /// [JsonPropertyName("aspect")] - public string? aspect { get; set; } + public string? Aspect { get; set; } /// /// Gets or sets the category. diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/LineupDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/LineupDto.cs index 676e745258..3dc64e5d8a 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/LineupDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/LineupDto.cs @@ -36,5 +36,11 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// [JsonPropertyName("uri")] public string? Uri { get; set; } + + /// + /// Gets or sets a value indicating whether this lineup was deleted. + /// + [JsonPropertyName("isDeleted")] + public bool? IsDeleted { get; set; } } } diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/LineupsDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/LineupsDto.cs index b0ee0ac8eb..a635c59870 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/LineupsDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/LineupsDto.cs @@ -25,7 +25,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the datetime. /// [JsonPropertyName("datetime")] - public string? Datetime { get; set; } + public DateTime? Datetime { get; set; } /// /// Gets or sets the list of lineups. diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MapDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MapDto.cs index cc1841c176..2420307b4f 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MapDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MapDto.cs @@ -19,6 +19,12 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos [JsonPropertyName("channel")] public string? Channel { get; set; } + /// + /// Gets or sets the provider callsign. + /// + [JsonPropertyName("providerCallsign")] + public string? ProvderCallsign { get; set; } + /// /// Gets or sets the logical channel number. /// @@ -42,5 +48,11 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// [JsonPropertyName("atscMinor")] public int AtscMinor { get; set; } + + /// + /// Gets or sets the match type. + /// + [JsonPropertyName("matchType")] + public string? MatchType { get;set; } } } diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MetadataProgramsDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MetadataProgramsDto.cs index 843ef9091d..43f2901566 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MetadataProgramsDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MetadataProgramsDto.cs @@ -10,7 +10,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// /// Gets or sets the gracenote object. /// - [JsonPropertyName("gracenote")] + [JsonPropertyName("Gracenote")] public GracenoteDto? Gracenote { get; set; } } } diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ProgramDetailsDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ProgramDetailsDto.cs index bfaed1e081..84c48f67f3 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ProgramDetailsDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ProgramDetailsDto.cs @@ -43,7 +43,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the original air date. /// [JsonPropertyName("originalAirDate")] - public string? OriginalAirDate { get; set; } + public DateTime? OriginalAirDate { get; set; } /// /// Gets or sets the list of genres. diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ProgramDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ProgramDto.cs index ff039c1cf1..60389b45bf 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ProgramDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ProgramDto.cs @@ -19,7 +19,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the air date time. /// [JsonPropertyName("airDateTime")] - public string? AirDateTime { get; set; } + public DateTime? AirDateTime { get; set; } /// /// Gets or sets the duration. diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/TokenDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/TokenDto.cs index fb5ed95ac9..561f79c5af 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/TokenDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/TokenDto.cs @@ -37,5 +37,11 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// [JsonPropertyName("datetime")] public DateTime? DateTime { get; set; } + + /// + /// Gets or sets the response message. + /// + [JsonPropertyName("response")] + public string? Response { get; set; } } } diff --git a/tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj b/tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj index 9b6ab7bdf5..e02e357ca0 100644 --- a/tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj +++ b/tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj @@ -16,6 +16,9 @@ PreserveNewest + + PreserveNewest + diff --git a/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/SchedulesDirectDeserializeTests.cs b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/SchedulesDirectDeserializeTests.cs new file mode 100644 index 0000000000..84ac3ea477 --- /dev/null +++ b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/SchedulesDirectDeserializeTests.cs @@ -0,0 +1,245 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text.Json; +using Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos; +using Jellyfin.Extensions.Json; +using Xunit; + +namespace Jellyfin.Server.Implementations.Tests.LiveTv.SchedulesDirect +{ + public class SchedulesDirectDeserializeTests + { + private readonly JsonSerializerOptions _jsonOptions; + + public SchedulesDirectDeserializeTests() + { + _jsonOptions = JsonDefaults.Options; + } + + /// + /// /token reponse. + /// + [Fact] + public void Deserialize_Token_Response_Live_Success() + { + var bytes = File.ReadAllBytes("LiveTv/SchedulesDirect/TestData/token_live_response.json"); + var tokenDto = JsonSerializer.Deserialize(bytes); + + Assert.NotNull(tokenDto); + Assert.Equal(0, tokenDto!.Code); + Assert.Equal("OK", tokenDto.Message); + Assert.Equal("AWS-SD-web.1", tokenDto.ServerId); + Assert.Equal(new DateTime(2016, 08, 23, 13, 55, 25, DateTimeKind.Utc), tokenDto.DateTime); + Assert.Equal("f3fca79989cafe7dead71beefedc812b", tokenDto.Token); + } + + /// + /// /token response. + /// + [Fact] + public void Deserialize_Token_Response_Offline_Success() + { + var bytes = File.ReadAllBytes("LiveTv/SchedulesDirect/TestData/token_offline_response.json"); + var tokenDto = JsonSerializer.Deserialize(bytes); + + Assert.NotNull(tokenDto); + Assert.Equal(3_000, tokenDto!.Code); + Assert.Equal("Server offline for maintenance.", tokenDto.Message); + Assert.Equal("20141201.web.1", tokenDto.ServerId); + Assert.Equal(new DateTime(2015, 04, 23, 00, 03, 32, DateTimeKind.Utc), tokenDto.DateTime); + Assert.Equal("CAFEDEADBEEFCAFEDEADBEEFCAFEDEADBEEFCAFE", tokenDto.Token); + Assert.Equal("SERVICE_OFFLINE", tokenDto.Response); + } + + /// + /// /schedules request. + /// + [Fact] + public void Serialize_Schedule_Request_Success() + { + var expectedString = File.ReadAllText("LiveTv/SchedulesDirect/TestData/schedules_request.json").Trim(); + + var requestObject = new RequestScheduleForChannelDto[] + { + new RequestScheduleForChannelDto + { + StationId = "20454", + Date = new[] + { + "2015-03-13", + "2015-03-17" + } + }, + new RequestScheduleForChannelDto + { + StationId = "10021", + Date = new[] + { + "2015-03-12", + "2015-03-13" + } + } + }; + + var jsonOptions = new JsonSerializerOptions(_jsonOptions) + { + WriteIndented = true + }; + + var requestString = JsonSerializer.Serialize(requestObject, jsonOptions); + Assert.Equal(expectedString, requestString); + } + + /// + /// /schedules response. + /// + [Fact] + public void Deserialize_Schedule_Response_Success() + { + var bytes = File.ReadAllBytes("LiveTv/SchedulesDirect/TestData/schedules_response.json"); + var days = JsonSerializer.Deserialize>(bytes); + + Assert.NotNull(days); + Assert.Equal(1, days!.Count); + + var dayDto = days[0]; + Assert.Equal("20454", dayDto.StationId); + Assert.Equal(2, dayDto.Programs.Count); + + Assert.Equal("SH005371070000", dayDto.Programs[0].ProgramId); + Assert.Equal(new DateTime(2015, 03, 03, 00, 00, 00, DateTimeKind.Utc), dayDto.Programs[0].AirDateTime); + Assert.Equal(1_800, dayDto.Programs[0].Duration); + Assert.Equal("Sy8HEMBPcuiAx3FBukUhKQ", dayDto.Programs[0].Md5); + Assert.True(dayDto.Programs[0].New); + Assert.Equal(2, dayDto.Programs[0].AudioProperties.Count); + Assert.Equal("stereo", dayDto.Programs[0].AudioProperties[0]); + Assert.Equal("cc", dayDto.Programs[0].AudioProperties[1]); + Assert.Equal(1, dayDto.Programs[0].VideoProperties.Count); + Assert.Equal("hdtv", dayDto.Programs[0].VideoProperties[0]); + } + + /// + /// /programs response. + /// + [Fact] + public void Deserialize_Program_Response_Success() + { + var bytes = File.ReadAllBytes("LiveTv/SchedulesDirect/TestData/programs_response.json"); + var programDtos = JsonSerializer.Deserialize>(bytes); + + Assert.NotNull(programDtos); + Assert.Equal(2, programDtos!.Count); + Assert.Equal("EP000000060003", programDtos[0].ProgramId); + Assert.Equal(1, programDtos[0].Titles.Count); + Assert.Equal("'Allo 'Allo!", programDtos[0].Titles[0].Title120); + Assert.Equal("Series", programDtos[0].EventDetails?.SubType); + Assert.Equal("en", programDtos[0].Descriptions?.Description1000[0].DescriptionLanguage); + Assert.Equal("A disguised British Intelligence officer is sent to help the airmen.", programDtos[0].Descriptions?.Description1000[0].Description); + Assert.Equal(new DateTime(1985, 11, 04), programDtos[0].OriginalAirDate); + Assert.Equal(1, programDtos[0].Genres.Count); + Assert.Equal("Sitcom", programDtos[0].Genres[0]); + Assert.Equal("The Poloceman Cometh", programDtos[0].EpisodeTitle150); + Assert.Equal(2, programDtos[0].Metadata[0].Gracenote?.Season); + Assert.Equal(3, programDtos[0].Metadata[0].Gracenote?.Episode); + Assert.Equal(13, programDtos[0].Cast.Count); + Assert.Equal("383774", programDtos[0].Cast[0].PersonId); + Assert.Equal("392649", programDtos[0].Cast[0].NameId); + Assert.Equal("Gorden Kaye", programDtos[0].Cast[0].Name); + Assert.Equal("Actor", programDtos[0].Cast[0].Role); + Assert.Equal("01", programDtos[0].Cast[0].BillingOrder); + Assert.Equal(3, programDtos[0].Crew.Count); + Assert.Equal("354407", programDtos[0].Crew[0].PersonId); + Assert.Equal("363281", programDtos[0].Crew[0].NameId); + Assert.Equal("David Croft", programDtos[0].Crew[0].Name); + Assert.Equal("Director", programDtos[0].Crew[0].Role); + Assert.Equal("01", programDtos[0].Crew[0].BillingOrder); + } + + /// + /// /metadata/programs response. + /// + [Fact] + public void Deserialize_Metadata_Programs_Response_Success() + { + var bytes = File.ReadAllBytes("LiveTv/SchedulesDirect/TestData/metadata_programs_response.json"); + var showImagesDtos = JsonSerializer.Deserialize>(bytes); + + Assert.NotNull(showImagesDtos); + Assert.Equal(1, showImagesDtos!.Count); + Assert.Equal("SH00712240", showImagesDtos[0].ProgramId); + Assert.Equal(4, showImagesDtos[0].Data.Count); + Assert.Equal("135", showImagesDtos[0].Data[0].Width); + Assert.Equal("180", showImagesDtos[0].Data[0].Height); + Assert.Equal("assets/p282288_b_v2_aa.jpg", showImagesDtos[0].Data[0].Uri); + Assert.Equal("Sm", showImagesDtos[0].Data[0].Size); + Assert.Equal("3x4", showImagesDtos[0].Data[0].Aspect); + Assert.Equal("Banner-L3", showImagesDtos[0].Data[0].Category); + Assert.Equal("yes", showImagesDtos[0].Data[0].Text); + Assert.Equal("true", showImagesDtos[0].Data[0].Primary); + Assert.Equal("Series", showImagesDtos[0].Data[0].Tier); + } + + /// + /// /headends response. + /// + [Fact] + public void Deserialize_Headends_Response_Success() + { + var bytes = File.ReadAllBytes("LiveTv/SchedulesDirect/TestData/headends_response.json"); + var headendsDtos = JsonSerializer.Deserialize>(bytes); + + Assert.NotNull(headendsDtos); + Assert.Equal(8, headendsDtos!.Count); + Assert.Equal("CA00053", headendsDtos[0].Headend); + Assert.Equal("Cable", headendsDtos[0].Transport); + Assert.Equal("Beverly Hills", headendsDtos[0].Location); + Assert.Equal(2, headendsDtos[0].Lineups.Count); + Assert.Equal("Time Warner Cable - Cable", headendsDtos[0].Lineups[0].Name); + Assert.Equal("USA-CA00053-DEFAULT", headendsDtos[0].Lineups[0].Lineup); + Assert.Equal("/20141201/lineups/USA-CA00053-DEFAULT", headendsDtos[0].Lineups[0].Uri); + } + + /// + /// /lineups response. + /// + [Fact] + public void Deserialize_Lineups_Response_Success() + { + var bytes = File.ReadAllBytes("LiveTv/SchedulesDirect/TestData/lineups_response.json"); + var lineupsDto = JsonSerializer.Deserialize(bytes); + + Assert.NotNull(lineupsDto); + Assert.Equal(0, lineupsDto!.Code); + Assert.Equal("20141201.web.1", lineupsDto.ServerId); + Assert.Equal(new DateTime(2015, 04, 17, 14, 22, 17, DateTimeKind.Utc), lineupsDto.Datetime); + Assert.Equal(5, lineupsDto.Lineups.Count); + Assert.Equal("GBR-0001317-DEFAULT", lineupsDto.Lineups[0].Lineup); + Assert.Equal("Freeview - Carlton - LWT (Southeast)", lineupsDto.Lineups[0].Name); + Assert.Equal("DVB-T", lineupsDto.Lineups[0].Transport); + Assert.Equal("London", lineupsDto.Lineups[0].Location); + Assert.Equal("/20141201/lineups/GBR-0001317-DEFAULT", lineupsDto.Lineups[0].Uri); + + Assert.Equal("DELETED LINEUP", lineupsDto.Lineups[4].Name); + Assert.True(lineupsDto.Lineups[4].IsDeleted); + } + + /// + /// /lineup/:id response. + /// + [Fact] + public void Deserialize_Lineup_Response_Success() + { + var bytes = File.ReadAllBytes("LiveTv/SchedulesDirect/TestData/lineup_response.json"); + var channelDto = JsonSerializer.Deserialize(bytes); + + Assert.NotNull(channelDto); + Assert.Equal(2, channelDto!.Map.Count); + Assert.Equal("24326", channelDto.Map[0].StationId); + Assert.Equal("001", channelDto.Map[0].Channel); + Assert.Equal("BBC ONE South", channelDto.Map[0].ProvderCallsign); + Assert.Equal("1", channelDto.Map[0].LogicalChannelNumber); + Assert.Equal("providerCallsign", channelDto.Map[0].MatchType); + } + } +} diff --git a/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/headends_response.json b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/headends_response.json new file mode 100644 index 0000000000..a1a96cf87a --- /dev/null +++ b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/headends_response.json @@ -0,0 +1,113 @@ +[ + { + "headend": "CA00053", + "transport": "Cable", + "location": "Beverly Hills", + "lineups": [ + { + "name": "Time Warner Cable - Cable", + "lineup": "USA-CA00053-DEFAULT", + "uri": "/20141201/lineups/USA-CA00053-DEFAULT" + }, + { + "name": "Time Warner Cable - Digital", + "lineup": "USA-CA00053-X", + "uri": "/20141201/lineups/USA-CA00053-X" + } + ] + }, + { + "headend": "CA61222", + "transport": "Cable", + "location": "Beverly Hills", + "lineups": [ + { + "name": "Mulholland Estates - Cable", + "lineup": "USA-CA61222-DEFAULT", + "uri": "/20141201/lineups/USA-CA61222-DEFAULT" + } + ] + }, + { + "headend": "CA66511", + "transport": "Cable", + "location": "Los Angeles", + "lineups": [ + { + "name": "AT&T U-verse TV - Digital", + "lineup": "USA-CA66511-X", + "uri": "/20141201/lineups/USA-CA66511-X" + } + ] + }, + { + "headend": "CA67309", + "transport": "Cable", + "location": "Westchester", + "lineups": [ + { + "name": "Time Warner Cable Sherman Oaks - Cable", + "lineup": "USA-CA67309-DEFAULT", + "uri": "/20141201/lineups/USA-CA67309-DEFAULT" + }, + { + "name": "Time Warner Cable Sherman Oaks - Digital", + "lineup": "USA-CA67309-X", + "uri": "/20141201/lineups/USA-CA67309-X" + } + ] + }, + { + "headend": "CA67310", + "transport": "Cable", + "location": "Eagle Rock", + "lineups": [ + { + "name": "Time Warner Cable City of Los Angeles - Cable", + "lineup": "USA-CA67310-DEFAULT", + "uri": "/20141201/lineups/USA-CA67310-DEFAULT" + }, + { + "name": "Time Warner Cable City of Los Angeles - Digital", + "lineup": "USA-CA67310-X", + "uri": "/20141201/lineups/USA-CA67310-X" + } + ] + }, + { + "headend": "DISH803", + "transport": "Satellite", + "location": "Los Angeles", + "lineups": [ + { + "name": "DISH Los Angeles - Satellite", + "lineup": "USA-DISH803-DEFAULT", + "uri": "/20141201/lineups/USA-DISH803-DEFAULT" + } + ] + }, + { + "headend": "DITV803", + "transport": "Satellite", + "location": "Los Angeles", + "lineups": [ + { + "name": "DIRECTV Los Angeles - Satellite", + "lineup": "USA-DITV803-DEFAULT", + "uri": "/20141201/lineups/USA-DITV803-DEFAULT" + } + ] + }, + { + "headend": "90210", + "transport": "Antenna", + "location": "90210", + "lineups": [ + { + "name": "Antenna", + "lineup": "USA-OTA-90210", + "uri": "/20141201/lineups/USA-OTA-90210" + } + ] + } +] diff --git a/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/lineup_response.json b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/lineup_response.json new file mode 100644 index 0000000000..5c5e36e301 --- /dev/null +++ b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/lineup_response.json @@ -0,0 +1,18 @@ +{ + "map": [ + { + "stationID": "24326", + "channel": "001", + "providerCallsign": "BBC ONE South", + "logicalChannelNumber": "1", + "matchType": "providerCallsign" + }, + { + "stationID": "17154", + "channel": "002", + "providerCallsign": "BBC TWO", + "logicalChannelNumber": "2", + "matchType": "providerCallsign" + } + ] +} diff --git a/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/lineups_response.json b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/lineups_response.json new file mode 100644 index 0000000000..257b682eef --- /dev/null +++ b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/lineups_response.json @@ -0,0 +1,40 @@ +{ + "code": 0, + "serverID": "20141201.web.1", + "datetime": "2015-04-17T14:22:17Z", + "lineups": [ + { + "lineup": "GBR-0001317-DEFAULT", + "name": "Freeview - Carlton - LWT (Southeast)", + "transport": "DVB-T", + "location": "London", + "uri": "/20141201/lineups/GBR-0001317-DEFAULT" + }, + { + "lineup": "USA-IL57303-X", + "name": "Comcast Waukegan/Lake Forest Area - Digital", + "transport": "Cable", + "location": "Lake Forest", + "uri": "/20141201/lineups/USA-IL57303-X" + }, + { + "lineup": "USA-NY67791-X", + "name": "Verizon Fios Queens - Digital", + "transport": "Cable", + "location": "Fresh Meadows", + "uri": "/20141201/lineups/USA-NY67791-X" + }, + { + "lineup": "USA-OTA-60030", + "name": "Local Over the Air Broadcast", + "transport": "Antenna", + "location": "60030", + "uri": "/20141201/lineups/USA-OTA-60030" + }, + { + "lineup": "USA-WI61859-DEFAULT", + "name": "DELETED LINEUP", + "isDeleted": true + } + ] +} diff --git a/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/metadata_programs_response.json b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/metadata_programs_response.json new file mode 100644 index 0000000000..b75e777b48 --- /dev/null +++ b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/metadata_programs_response.json @@ -0,0 +1,51 @@ +[ + { + "programID": "SH00712240", + "data": [ + { + "width": "135", + "height": "180", + "uri": "assets/p282288_b_v2_aa.jpg", + "size": "Sm", + "aspect": "3x4", + "category": "Banner-L3", + "text": "yes", + "primary": "true", + "tier": "Series" + }, + { + "width": "720", + "height": "540", + "uri": "assets/p282288_b_h6_aa.jpg", + "size": "Lg", + "aspect": "4x3", + "category": "Banner-L3", + "text": "yes", + "primary": "true", + "tier": "Series" + }, + { + "width": "960", + "height": "1440", + "uri": "assets/p282288_b_v8_aa.jpg", + "size": "Ms", + "aspect": "2x3", + "category": "Banner-L3", + "text": "yes", + "primary": "true", + "tier": "Series" + }, + { + "width": "180", + "height": "135", + "uri": "assets/p282288_b_h5_aa.jpg", + "size": "Sm", + "aspect": "4x3", + "category": "Banner-L3", + "text": "yes", + "primary": "true", + "tier": "Series" + } + ] + } +] diff --git a/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/programs_response.json b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/programs_response.json new file mode 100644 index 0000000000..154c02f973 --- /dev/null +++ b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/programs_response.json @@ -0,0 +1,245 @@ +[ + { + "programID": "EP000000060003", + "titles": [{ + "title120": "'Allo 'Allo!" + }], + "eventDetails": { + "subType": "Series" + }, + "descriptions": { + "description1000": [{ + "descriptionLanguage": "en", + "description": "A disguised British Intelligence officer is sent to help the airmen." + }] + }, + "originalAirDate": "1985-11-04", + "genres": ["Sitcom"], + "episodeTitle150": "The Poloceman Cometh", + "metadata": [{ + "Gracenote": { + "season": 2, + "episode": 3 + } + }], + "cast": [{ + "personId": "383774", + "nameId": "392649", + "name": "Gorden Kaye", + "role": "Actor", + "billingOrder": "01" + }, { + "personId": "246840", + "nameId": "250387", + "name": "Carmen Silvera", + "role": "Actor", + "billingOrder": "02" + }, { + "personId": "376955", + "nameId": "385830", + "name": "Rose Hill", + "role": "Actor", + "billingOrder": "03" + }, { + "personId": "259773", + "nameId": "263340", + "name": "Vicki Michelle", + "role": "Actor", + "billingOrder": "04" + }, { + "personId": "353113", + "nameId": "361987", + "name": "Kirsten Cooke", + "role": "Actor", + "billingOrder": "05" + }, { + "personId": "77787", + "nameId": "77787", + "name": "Richard Marner", + "role": "Actor", + "billingOrder": "06" + }, { + "personId": "230921", + "nameId": "234193", + "name": "Guy Siner", + "role": "Actor", + "billingOrder": "07" + }, { + "personId": "374934", + "nameId": "383809", + "name": "Kim Hartman", + "role": "Actor", + "billingOrder": "08" + }, { + "personId": "369151", + "nameId": "378026", + "name": "Richard Gibson", + "role": "Actor", + "billingOrder": "09" + }, { + "personId": "343690", + "nameId": "352564", + "name": "Arthur Bostrom", + "role": "Actor", + "billingOrder": "10" + }, { + "personId": "352557", + "nameId": "361431", + "name": "John D. Collins", + "role": "Actor", + "billingOrder": "11" + }, { + "personId": "605275", + "nameId": "627734", + "name": "Nicholas Frankau", + "role": "Actor", + "billingOrder": "12" + }, { + "personId": "373394", + "nameId": "382269", + "name": "Jack Haig", + "role": "Actor", + "billingOrder": "13" + }], + "crew": [{ + "personId": "354407", + "nameId": "363281", + "name": "David Croft", + "role": "Director", + "billingOrder": "01" + }, { + "personId": "354407", + "nameId": "363281", + "name": "David Croft", + "role": "Writer", + "billingOrder": "02" + }, { + "personId": "105145", + "nameId": "105145", + "name": "Jeremy Lloyd", + "role": "Writer", + "billingOrder": "03" + }], + "showType": "Series", + "hasImageArtwork": true, + "md5": "Jo5NKxoo44xRvBCAq8QT2A" + }, + { + "programID": "EP000000510142", + "titles": [{ + "title120": "A Different World" + }], + "eventDetails": { + "subType": "Series" + }, + "descriptions": { + "description1000": [{ + "descriptionLanguage": "en", + "description": "Whitley and Dwayne tell new students about their honeymoon in Los Angeles." + }] + }, + "originalAirDate": "1992-09-24", + "genres": ["Sitcom"], + "episodeTitle150": "Honeymoon in L.A.", + "metadata": [{ + "Gracenote": { + "season": 6, + "episode": 1 + } + }], + "cast": [{ + "personId": "700", + "nameId": "700", + "name": "Jasmine Guy", + "role": "Actor", + "billingOrder": "01" + }, { + "personId": "729", + "nameId": "729", + "name": "Kadeem Hardison", + "role": "Actor", + "billingOrder": "02" + }, { + "personId": "120", + "nameId": "120", + "name": "Darryl M. Bell", + "role": "Actor", + "billingOrder": "03" + }, { + "personId": "1729", + "nameId": "1729", + "name": "Cree Summer", + "role": "Actor", + "billingOrder": "04" + }, { + "personId": "217", + "nameId": "217", + "name": "Charnele Brown", + "role": "Actor", + "billingOrder": "05" + }, { + "personId": "1811", + "nameId": "1811", + "name": "Glynn Turman", + "role": "Actor", + "billingOrder": "06" + }, { + "personId": "1232", + "nameId": "1232", + "name": "Lou Myers", + "role": "Actor", + "billingOrder": "07" + }, { + "personId": "1363", + "nameId": "1363", + "name": "Jada Pinkett", + "role": "Guest Star", + "billingOrder": "08" + }, { + "personId": "222967", + "nameId": "225536", + "name": "Ajai Sanders", + "role": "Guest Star", + "billingOrder": "09" + }, { + "personId": "181744", + "nameId": "183292", + "name": "Karen Malina White", + "role": "Guest Star", + "billingOrder": "10" + }, { + "personId": "305017", + "nameId": "318897", + "name": "Patrick Y. Malone", + "role": "Guest Star", + "billingOrder": "11" + }, { + "personId": "9841", + "nameId": "9841", + "name": "Bumper Robinson", + "role": "Guest Star", + "billingOrder": "12" + }, { + "personId": "426422", + "nameId": "435297", + "name": "Sister Souljah", + "role": "Guest Star", + "billingOrder": "13" + }, { + "personId": "25", + "nameId": "25", + "name": "Debbie Allen", + "role": "Guest Star", + "billingOrder": "14" + }, { + "personId": "668", + "nameId": "668", + "name": "Gilbert Gottfried", + "role": "Guest Star", + "billingOrder": "15" + }], + "showType": "Series", + "hasImageArtwork": true, + "md5": "P5kz0QmCeYxIA+yL0H4DWw" + } +] diff --git a/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/schedules_request.json b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/schedules_request.json new file mode 100644 index 0000000000..72248921ae --- /dev/null +++ b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/schedules_request.json @@ -0,0 +1,16 @@ +[ + { + "stationID": "20454", + "date": [ + "2015-03-13", + "2015-03-17" + ] + }, + { + "stationID": "10021", + "date": [ + "2015-03-12", + "2015-03-13" + ] + } +] diff --git a/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/schedules_response.json b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/schedules_response.json new file mode 100644 index 0000000000..f474f3aff2 --- /dev/null +++ b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/schedules_response.json @@ -0,0 +1,35 @@ +[ + { + "stationID": "20454", + "programs": [ + { + "programID": "SH005371070000", + "airDateTime": "2015-03-03T00:00:00Z", + "duration": 1800, + "md5": "Sy8HEMBPcuiAx3FBukUhKQ", + "new": true, + "audioProperties": [ + "stereo", + "cc" + ], + "videoProperties": [ + "hdtv" + ] + }, + { + "programID": "EP000014577244", + "airDateTime": "2015-03-03T00:30:00Z", + "duration": 1800, + "md5": "25DNXVXO192JI7Y9vSW9lQ", + "new": true, + "audioProperties": [ + "stereo", + "cc" + ], + "videoProperties": [ + "hdtv" + ] + } + ] + } +] diff --git a/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/token_live_response.json b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/token_live_response.json new file mode 100644 index 0000000000..73b0a54c4e --- /dev/null +++ b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/token_live_response.json @@ -0,0 +1,7 @@ +{ + "code": 0, + "message": "OK", + "serverID": "AWS-SD-web.1", + "datetime": "2016-08-23T13:55:25Z", + "token": "f3fca79989cafe7dead71beefedc812b" +} diff --git a/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/token_offline_response.json b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/token_offline_response.json new file mode 100644 index 0000000000..b630c24041 --- /dev/null +++ b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/token_offline_response.json @@ -0,0 +1,8 @@ +{ + "response": "SERVICE_OFFLINE", + "code": 3000, + "serverID": "20141201.web.1", + "message": "Server offline for maintenance.", + "datetime": "2015-04-23T00:03:32Z", + "token": "CAFEDEADBEEFCAFEDEADBEEFCAFEDEADBEEFCAFE" +} -- cgit v1.2.3 From 0587b539ec899c35b5bea73801d5007575f86b94 Mon Sep 17 00:00:00 2001 From: Cody Robibero Date: Fri, 3 Sep 2021 13:36:07 -0600 Subject: Suggestions from review --- .../LiveTv/Listings/SchedulesDirect.cs | 25 ++- .../Jellyfin.Server.Implementations.Tests.csproj | 3 - .../SchedulesDirectDeserializeTests.cs | 25 +-- .../TestData/headends_response.json | 113 ---------- .../SchedulesDirect/TestData/lineup_response.json | 18 -- .../SchedulesDirect/TestData/lineups_response.json | 40 ---- .../TestData/metadata_programs_response.json | 51 ----- .../TestData/programs_response.json | 245 --------------------- .../TestData/schedules_request.json | 16 -- .../TestData/schedules_response.json | 35 --- .../TestData/token_live_response.json | 7 - .../TestData/token_offline_response.json | 8 - .../SchedulesDirect/headends_response.json | 1 + .../Test Data/SchedulesDirect/lineup_response.json | 1 + .../SchedulesDirect/lineups_response.json | 1 + .../metadata_programs_response.json | 1 + .../SchedulesDirect/programs_response.json | 1 + .../SchedulesDirect/schedules_request.json | 1 + .../SchedulesDirect/schedules_response.json | 1 + .../SchedulesDirect/token_live_response.json | 1 + .../SchedulesDirect/token_offline_response.json | 1 + 21 files changed, 40 insertions(+), 555 deletions(-) delete mode 100644 tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/headends_response.json delete mode 100644 tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/lineup_response.json delete mode 100644 tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/lineups_response.json delete mode 100644 tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/metadata_programs_response.json delete mode 100644 tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/programs_response.json delete mode 100644 tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/schedules_request.json delete mode 100644 tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/schedules_response.json delete mode 100644 tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/token_live_response.json delete mode 100644 tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/token_offline_response.json create mode 100644 tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/headends_response.json create mode 100644 tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/lineup_response.json create mode 100644 tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/lineups_response.json create mode 100644 tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/metadata_programs_response.json create mode 100644 tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/programs_response.json create mode 100644 tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/schedules_request.json create mode 100644 tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/schedules_response.json create mode 100644 tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/token_live_response.json create mode 100644 tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/token_offline_response.json (limited to 'Emby.Server.Implementations/LiveTv') diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs index e8562b8c57..6686b625f4 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs @@ -9,6 +9,7 @@ using System.Globalization; using System.Linq; using System.Net; using System.Net.Http; +using System.Net.Http.Headers; using System.Net.Http.Json; using System.Net.Mime; using System.Text; @@ -113,18 +114,29 @@ namespace Emby.Server.Implementations.LiveTv.Listings 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 JsonSerializer.DeserializeAsync>(responseStream, _jsonOptions, cancellationToken).ConfigureAwait(false); - _logger.LogDebug("Found {ScheduleCount} programs on {ChannelID} ScheduleDirect", dailySchedules!.Count, channelId); + if (dailySchedules == null) + { + return Array.Empty(); + } + + _logger.LogDebug("Found {ScheduleCount} programs on {ChannelID} ScheduleDirect", dailySchedules.Count, channelId); using var programRequestOptions = new HttpRequestMessage(HttpMethod.Post, ApiUrl + "/programs"); programRequestOptions.Headers.TryAddWithoutValidation("token", token); var programIds = dailySchedules.SelectMany(d => d.Programs.Select(s => s.ProgramId)).Distinct(); - programRequestOptions.Content = new StringContent(JsonSerializer.Serialize(programIds), Encoding.UTF8, MediaTypeNames.Application.Json); + programRequestOptions.Content = new ByteArrayContent(JsonSerializer.SerializeToUtf8Bytes(programIds, _jsonOptions)); + programRequestOptions.Content.Headers.ContentType = MediaTypeHeaderValue.Parse(MediaTypeNames.Application.Json); 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 JsonSerializer.DeserializeAsync>(innerResponseStream, _jsonOptions, cancellationToken).ConfigureAwait(false); - var programDict = programDetails!.ToDictionary(p => p.ProgramId, y => y); + if (programDetails == null) + { + return Array.Empty(); + } + + var programDict = programDetails.ToDictionary(p => p.ProgramId, y => y); var programIdsWithImages = programDetails .Where(p => p.HasImageArtwork).Select(p => p.ProgramId) @@ -775,7 +787,12 @@ namespace Emby.Server.Implementations.LiveTv.Listings 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 JsonSerializer.DeserializeAsync(stream, _jsonOptions, cancellationToken).ConfigureAwait(false); - _logger.LogInformation("Found {ChannelCount} channels on the lineup on ScheduleDirect", root!.Map.Count); + if (root == null) + { + return new List(); + } + + _logger.LogInformation("Found {ChannelCount} channels on the lineup on ScheduleDirect", root.Map.Count); _logger.LogInformation("Mapping Stations to Channel"); var allStations = root.Stations; diff --git a/tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj b/tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj index e02e357ca0..9b6ab7bdf5 100644 --- a/tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj +++ b/tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj @@ -16,9 +16,6 @@ PreserveNewest - - PreserveNewest - diff --git a/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/SchedulesDirectDeserializeTests.cs b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/SchedulesDirectDeserializeTests.cs index 84ac3ea477..ab08e22ab1 100644 --- a/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/SchedulesDirectDeserializeTests.cs +++ b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/SchedulesDirectDeserializeTests.cs @@ -23,7 +23,7 @@ namespace Jellyfin.Server.Implementations.Tests.LiveTv.SchedulesDirect [Fact] public void Deserialize_Token_Response_Live_Success() { - var bytes = File.ReadAllBytes("LiveTv/SchedulesDirect/TestData/token_live_response.json"); + var bytes = File.ReadAllBytes("Test Data/SchedulesDirect/token_live_response.json"); var tokenDto = JsonSerializer.Deserialize(bytes); Assert.NotNull(tokenDto); @@ -40,7 +40,7 @@ namespace Jellyfin.Server.Implementations.Tests.LiveTv.SchedulesDirect [Fact] public void Deserialize_Token_Response_Offline_Success() { - var bytes = File.ReadAllBytes("LiveTv/SchedulesDirect/TestData/token_offline_response.json"); + var bytes = File.ReadAllBytes("Test Data/SchedulesDirect/token_offline_response.json"); var tokenDto = JsonSerializer.Deserialize(bytes); Assert.NotNull(tokenDto); @@ -58,7 +58,7 @@ namespace Jellyfin.Server.Implementations.Tests.LiveTv.SchedulesDirect [Fact] public void Serialize_Schedule_Request_Success() { - var expectedString = File.ReadAllText("LiveTv/SchedulesDirect/TestData/schedules_request.json").Trim(); + var expectedString = File.ReadAllText("Test Data/SchedulesDirect/schedules_request.json").Trim(); var requestObject = new RequestScheduleForChannelDto[] { @@ -82,12 +82,7 @@ namespace Jellyfin.Server.Implementations.Tests.LiveTv.SchedulesDirect } }; - var jsonOptions = new JsonSerializerOptions(_jsonOptions) - { - WriteIndented = true - }; - - var requestString = JsonSerializer.Serialize(requestObject, jsonOptions); + var requestString = JsonSerializer.Serialize(requestObject, _jsonOptions); Assert.Equal(expectedString, requestString); } @@ -97,7 +92,7 @@ namespace Jellyfin.Server.Implementations.Tests.LiveTv.SchedulesDirect [Fact] public void Deserialize_Schedule_Response_Success() { - var bytes = File.ReadAllBytes("LiveTv/SchedulesDirect/TestData/schedules_response.json"); + var bytes = File.ReadAllBytes("Test Data/SchedulesDirect/schedules_response.json"); var days = JsonSerializer.Deserialize>(bytes); Assert.NotNull(days); @@ -125,7 +120,7 @@ namespace Jellyfin.Server.Implementations.Tests.LiveTv.SchedulesDirect [Fact] public void Deserialize_Program_Response_Success() { - var bytes = File.ReadAllBytes("LiveTv/SchedulesDirect/TestData/programs_response.json"); + var bytes = File.ReadAllBytes("Test Data/SchedulesDirect/programs_response.json"); var programDtos = JsonSerializer.Deserialize>(bytes); Assert.NotNull(programDtos); @@ -162,7 +157,7 @@ namespace Jellyfin.Server.Implementations.Tests.LiveTv.SchedulesDirect [Fact] public void Deserialize_Metadata_Programs_Response_Success() { - var bytes = File.ReadAllBytes("LiveTv/SchedulesDirect/TestData/metadata_programs_response.json"); + var bytes = File.ReadAllBytes("Test Data/SchedulesDirect/metadata_programs_response.json"); var showImagesDtos = JsonSerializer.Deserialize>(bytes); Assert.NotNull(showImagesDtos); @@ -186,7 +181,7 @@ namespace Jellyfin.Server.Implementations.Tests.LiveTv.SchedulesDirect [Fact] public void Deserialize_Headends_Response_Success() { - var bytes = File.ReadAllBytes("LiveTv/SchedulesDirect/TestData/headends_response.json"); + var bytes = File.ReadAllBytes("Test Data/SchedulesDirect/headends_response.json"); var headendsDtos = JsonSerializer.Deserialize>(bytes); Assert.NotNull(headendsDtos); @@ -206,7 +201,7 @@ namespace Jellyfin.Server.Implementations.Tests.LiveTv.SchedulesDirect [Fact] public void Deserialize_Lineups_Response_Success() { - var bytes = File.ReadAllBytes("LiveTv/SchedulesDirect/TestData/lineups_response.json"); + var bytes = File.ReadAllBytes("Test Data/SchedulesDirect/lineups_response.json"); var lineupsDto = JsonSerializer.Deserialize(bytes); Assert.NotNull(lineupsDto); @@ -230,7 +225,7 @@ namespace Jellyfin.Server.Implementations.Tests.LiveTv.SchedulesDirect [Fact] public void Deserialize_Lineup_Response_Success() { - var bytes = File.ReadAllBytes("LiveTv/SchedulesDirect/TestData/lineup_response.json"); + var bytes = File.ReadAllBytes("Test Data/SchedulesDirect/lineup_response.json"); var channelDto = JsonSerializer.Deserialize(bytes); Assert.NotNull(channelDto); diff --git a/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/headends_response.json b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/headends_response.json deleted file mode 100644 index a1a96cf87a..0000000000 --- a/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/headends_response.json +++ /dev/null @@ -1,113 +0,0 @@ -[ - { - "headend": "CA00053", - "transport": "Cable", - "location": "Beverly Hills", - "lineups": [ - { - "name": "Time Warner Cable - Cable", - "lineup": "USA-CA00053-DEFAULT", - "uri": "/20141201/lineups/USA-CA00053-DEFAULT" - }, - { - "name": "Time Warner Cable - Digital", - "lineup": "USA-CA00053-X", - "uri": "/20141201/lineups/USA-CA00053-X" - } - ] - }, - { - "headend": "CA61222", - "transport": "Cable", - "location": "Beverly Hills", - "lineups": [ - { - "name": "Mulholland Estates - Cable", - "lineup": "USA-CA61222-DEFAULT", - "uri": "/20141201/lineups/USA-CA61222-DEFAULT" - } - ] - }, - { - "headend": "CA66511", - "transport": "Cable", - "location": "Los Angeles", - "lineups": [ - { - "name": "AT&T U-verse TV - Digital", - "lineup": "USA-CA66511-X", - "uri": "/20141201/lineups/USA-CA66511-X" - } - ] - }, - { - "headend": "CA67309", - "transport": "Cable", - "location": "Westchester", - "lineups": [ - { - "name": "Time Warner Cable Sherman Oaks - Cable", - "lineup": "USA-CA67309-DEFAULT", - "uri": "/20141201/lineups/USA-CA67309-DEFAULT" - }, - { - "name": "Time Warner Cable Sherman Oaks - Digital", - "lineup": "USA-CA67309-X", - "uri": "/20141201/lineups/USA-CA67309-X" - } - ] - }, - { - "headend": "CA67310", - "transport": "Cable", - "location": "Eagle Rock", - "lineups": [ - { - "name": "Time Warner Cable City of Los Angeles - Cable", - "lineup": "USA-CA67310-DEFAULT", - "uri": "/20141201/lineups/USA-CA67310-DEFAULT" - }, - { - "name": "Time Warner Cable City of Los Angeles - Digital", - "lineup": "USA-CA67310-X", - "uri": "/20141201/lineups/USA-CA67310-X" - } - ] - }, - { - "headend": "DISH803", - "transport": "Satellite", - "location": "Los Angeles", - "lineups": [ - { - "name": "DISH Los Angeles - Satellite", - "lineup": "USA-DISH803-DEFAULT", - "uri": "/20141201/lineups/USA-DISH803-DEFAULT" - } - ] - }, - { - "headend": "DITV803", - "transport": "Satellite", - "location": "Los Angeles", - "lineups": [ - { - "name": "DIRECTV Los Angeles - Satellite", - "lineup": "USA-DITV803-DEFAULT", - "uri": "/20141201/lineups/USA-DITV803-DEFAULT" - } - ] - }, - { - "headend": "90210", - "transport": "Antenna", - "location": "90210", - "lineups": [ - { - "name": "Antenna", - "lineup": "USA-OTA-90210", - "uri": "/20141201/lineups/USA-OTA-90210" - } - ] - } -] diff --git a/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/lineup_response.json b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/lineup_response.json deleted file mode 100644 index 5c5e36e301..0000000000 --- a/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/lineup_response.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "map": [ - { - "stationID": "24326", - "channel": "001", - "providerCallsign": "BBC ONE South", - "logicalChannelNumber": "1", - "matchType": "providerCallsign" - }, - { - "stationID": "17154", - "channel": "002", - "providerCallsign": "BBC TWO", - "logicalChannelNumber": "2", - "matchType": "providerCallsign" - } - ] -} diff --git a/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/lineups_response.json b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/lineups_response.json deleted file mode 100644 index 257b682eef..0000000000 --- a/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/lineups_response.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "code": 0, - "serverID": "20141201.web.1", - "datetime": "2015-04-17T14:22:17Z", - "lineups": [ - { - "lineup": "GBR-0001317-DEFAULT", - "name": "Freeview - Carlton - LWT (Southeast)", - "transport": "DVB-T", - "location": "London", - "uri": "/20141201/lineups/GBR-0001317-DEFAULT" - }, - { - "lineup": "USA-IL57303-X", - "name": "Comcast Waukegan/Lake Forest Area - Digital", - "transport": "Cable", - "location": "Lake Forest", - "uri": "/20141201/lineups/USA-IL57303-X" - }, - { - "lineup": "USA-NY67791-X", - "name": "Verizon Fios Queens - Digital", - "transport": "Cable", - "location": "Fresh Meadows", - "uri": "/20141201/lineups/USA-NY67791-X" - }, - { - "lineup": "USA-OTA-60030", - "name": "Local Over the Air Broadcast", - "transport": "Antenna", - "location": "60030", - "uri": "/20141201/lineups/USA-OTA-60030" - }, - { - "lineup": "USA-WI61859-DEFAULT", - "name": "DELETED LINEUP", - "isDeleted": true - } - ] -} diff --git a/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/metadata_programs_response.json b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/metadata_programs_response.json deleted file mode 100644 index b75e777b48..0000000000 --- a/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/metadata_programs_response.json +++ /dev/null @@ -1,51 +0,0 @@ -[ - { - "programID": "SH00712240", - "data": [ - { - "width": "135", - "height": "180", - "uri": "assets/p282288_b_v2_aa.jpg", - "size": "Sm", - "aspect": "3x4", - "category": "Banner-L3", - "text": "yes", - "primary": "true", - "tier": "Series" - }, - { - "width": "720", - "height": "540", - "uri": "assets/p282288_b_h6_aa.jpg", - "size": "Lg", - "aspect": "4x3", - "category": "Banner-L3", - "text": "yes", - "primary": "true", - "tier": "Series" - }, - { - "width": "960", - "height": "1440", - "uri": "assets/p282288_b_v8_aa.jpg", - "size": "Ms", - "aspect": "2x3", - "category": "Banner-L3", - "text": "yes", - "primary": "true", - "tier": "Series" - }, - { - "width": "180", - "height": "135", - "uri": "assets/p282288_b_h5_aa.jpg", - "size": "Sm", - "aspect": "4x3", - "category": "Banner-L3", - "text": "yes", - "primary": "true", - "tier": "Series" - } - ] - } -] diff --git a/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/programs_response.json b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/programs_response.json deleted file mode 100644 index 154c02f973..0000000000 --- a/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/programs_response.json +++ /dev/null @@ -1,245 +0,0 @@ -[ - { - "programID": "EP000000060003", - "titles": [{ - "title120": "'Allo 'Allo!" - }], - "eventDetails": { - "subType": "Series" - }, - "descriptions": { - "description1000": [{ - "descriptionLanguage": "en", - "description": "A disguised British Intelligence officer is sent to help the airmen." - }] - }, - "originalAirDate": "1985-11-04", - "genres": ["Sitcom"], - "episodeTitle150": "The Poloceman Cometh", - "metadata": [{ - "Gracenote": { - "season": 2, - "episode": 3 - } - }], - "cast": [{ - "personId": "383774", - "nameId": "392649", - "name": "Gorden Kaye", - "role": "Actor", - "billingOrder": "01" - }, { - "personId": "246840", - "nameId": "250387", - "name": "Carmen Silvera", - "role": "Actor", - "billingOrder": "02" - }, { - "personId": "376955", - "nameId": "385830", - "name": "Rose Hill", - "role": "Actor", - "billingOrder": "03" - }, { - "personId": "259773", - "nameId": "263340", - "name": "Vicki Michelle", - "role": "Actor", - "billingOrder": "04" - }, { - "personId": "353113", - "nameId": "361987", - "name": "Kirsten Cooke", - "role": "Actor", - "billingOrder": "05" - }, { - "personId": "77787", - "nameId": "77787", - "name": "Richard Marner", - "role": "Actor", - "billingOrder": "06" - }, { - "personId": "230921", - "nameId": "234193", - "name": "Guy Siner", - "role": "Actor", - "billingOrder": "07" - }, { - "personId": "374934", - "nameId": "383809", - "name": "Kim Hartman", - "role": "Actor", - "billingOrder": "08" - }, { - "personId": "369151", - "nameId": "378026", - "name": "Richard Gibson", - "role": "Actor", - "billingOrder": "09" - }, { - "personId": "343690", - "nameId": "352564", - "name": "Arthur Bostrom", - "role": "Actor", - "billingOrder": "10" - }, { - "personId": "352557", - "nameId": "361431", - "name": "John D. Collins", - "role": "Actor", - "billingOrder": "11" - }, { - "personId": "605275", - "nameId": "627734", - "name": "Nicholas Frankau", - "role": "Actor", - "billingOrder": "12" - }, { - "personId": "373394", - "nameId": "382269", - "name": "Jack Haig", - "role": "Actor", - "billingOrder": "13" - }], - "crew": [{ - "personId": "354407", - "nameId": "363281", - "name": "David Croft", - "role": "Director", - "billingOrder": "01" - }, { - "personId": "354407", - "nameId": "363281", - "name": "David Croft", - "role": "Writer", - "billingOrder": "02" - }, { - "personId": "105145", - "nameId": "105145", - "name": "Jeremy Lloyd", - "role": "Writer", - "billingOrder": "03" - }], - "showType": "Series", - "hasImageArtwork": true, - "md5": "Jo5NKxoo44xRvBCAq8QT2A" - }, - { - "programID": "EP000000510142", - "titles": [{ - "title120": "A Different World" - }], - "eventDetails": { - "subType": "Series" - }, - "descriptions": { - "description1000": [{ - "descriptionLanguage": "en", - "description": "Whitley and Dwayne tell new students about their honeymoon in Los Angeles." - }] - }, - "originalAirDate": "1992-09-24", - "genres": ["Sitcom"], - "episodeTitle150": "Honeymoon in L.A.", - "metadata": [{ - "Gracenote": { - "season": 6, - "episode": 1 - } - }], - "cast": [{ - "personId": "700", - "nameId": "700", - "name": "Jasmine Guy", - "role": "Actor", - "billingOrder": "01" - }, { - "personId": "729", - "nameId": "729", - "name": "Kadeem Hardison", - "role": "Actor", - "billingOrder": "02" - }, { - "personId": "120", - "nameId": "120", - "name": "Darryl M. Bell", - "role": "Actor", - "billingOrder": "03" - }, { - "personId": "1729", - "nameId": "1729", - "name": "Cree Summer", - "role": "Actor", - "billingOrder": "04" - }, { - "personId": "217", - "nameId": "217", - "name": "Charnele Brown", - "role": "Actor", - "billingOrder": "05" - }, { - "personId": "1811", - "nameId": "1811", - "name": "Glynn Turman", - "role": "Actor", - "billingOrder": "06" - }, { - "personId": "1232", - "nameId": "1232", - "name": "Lou Myers", - "role": "Actor", - "billingOrder": "07" - }, { - "personId": "1363", - "nameId": "1363", - "name": "Jada Pinkett", - "role": "Guest Star", - "billingOrder": "08" - }, { - "personId": "222967", - "nameId": "225536", - "name": "Ajai Sanders", - "role": "Guest Star", - "billingOrder": "09" - }, { - "personId": "181744", - "nameId": "183292", - "name": "Karen Malina White", - "role": "Guest Star", - "billingOrder": "10" - }, { - "personId": "305017", - "nameId": "318897", - "name": "Patrick Y. Malone", - "role": "Guest Star", - "billingOrder": "11" - }, { - "personId": "9841", - "nameId": "9841", - "name": "Bumper Robinson", - "role": "Guest Star", - "billingOrder": "12" - }, { - "personId": "426422", - "nameId": "435297", - "name": "Sister Souljah", - "role": "Guest Star", - "billingOrder": "13" - }, { - "personId": "25", - "nameId": "25", - "name": "Debbie Allen", - "role": "Guest Star", - "billingOrder": "14" - }, { - "personId": "668", - "nameId": "668", - "name": "Gilbert Gottfried", - "role": "Guest Star", - "billingOrder": "15" - }], - "showType": "Series", - "hasImageArtwork": true, - "md5": "P5kz0QmCeYxIA+yL0H4DWw" - } -] diff --git a/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/schedules_request.json b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/schedules_request.json deleted file mode 100644 index 72248921ae..0000000000 --- a/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/schedules_request.json +++ /dev/null @@ -1,16 +0,0 @@ -[ - { - "stationID": "20454", - "date": [ - "2015-03-13", - "2015-03-17" - ] - }, - { - "stationID": "10021", - "date": [ - "2015-03-12", - "2015-03-13" - ] - } -] diff --git a/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/schedules_response.json b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/schedules_response.json deleted file mode 100644 index f474f3aff2..0000000000 --- a/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/schedules_response.json +++ /dev/null @@ -1,35 +0,0 @@ -[ - { - "stationID": "20454", - "programs": [ - { - "programID": "SH005371070000", - "airDateTime": "2015-03-03T00:00:00Z", - "duration": 1800, - "md5": "Sy8HEMBPcuiAx3FBukUhKQ", - "new": true, - "audioProperties": [ - "stereo", - "cc" - ], - "videoProperties": [ - "hdtv" - ] - }, - { - "programID": "EP000014577244", - "airDateTime": "2015-03-03T00:30:00Z", - "duration": 1800, - "md5": "25DNXVXO192JI7Y9vSW9lQ", - "new": true, - "audioProperties": [ - "stereo", - "cc" - ], - "videoProperties": [ - "hdtv" - ] - } - ] - } -] diff --git a/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/token_live_response.json b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/token_live_response.json deleted file mode 100644 index 73b0a54c4e..0000000000 --- a/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/token_live_response.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "code": 0, - "message": "OK", - "serverID": "AWS-SD-web.1", - "datetime": "2016-08-23T13:55:25Z", - "token": "f3fca79989cafe7dead71beefedc812b" -} diff --git a/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/token_offline_response.json b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/token_offline_response.json deleted file mode 100644 index b630c24041..0000000000 --- a/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/token_offline_response.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "response": "SERVICE_OFFLINE", - "code": 3000, - "serverID": "20141201.web.1", - "message": "Server offline for maintenance.", - "datetime": "2015-04-23T00:03:32Z", - "token": "CAFEDEADBEEFCAFEDEADBEEFCAFEDEADBEEFCAFE" -} diff --git a/tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/headends_response.json b/tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/headends_response.json new file mode 100644 index 0000000000..015afeecc0 --- /dev/null +++ b/tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/headends_response.json @@ -0,0 +1 @@ +[{"headend":"CA00053","transport":"Cable","location":"Beverly Hills","lineups":[{"name":"Time Warner Cable - Cable","lineup":"USA-CA00053-DEFAULT","uri":"/20141201/lineups/USA-CA00053-DEFAULT"},{"name":"Time Warner Cable - Digital","lineup":"USA-CA00053-X","uri":"/20141201/lineups/USA-CA00053-X"}]},{"headend":"CA61222","transport":"Cable","location":"Beverly Hills","lineups":[{"name":"Mulholland Estates - Cable","lineup":"USA-CA61222-DEFAULT","uri":"/20141201/lineups/USA-CA61222-DEFAULT"}]},{"headend":"CA66511","transport":"Cable","location":"Los Angeles","lineups":[{"name":"AT&T U-verse TV - Digital","lineup":"USA-CA66511-X","uri":"/20141201/lineups/USA-CA66511-X"}]},{"headend":"CA67309","transport":"Cable","location":"Westchester","lineups":[{"name":"Time Warner Cable Sherman Oaks - Cable","lineup":"USA-CA67309-DEFAULT","uri":"/20141201/lineups/USA-CA67309-DEFAULT"},{"name":"Time Warner Cable Sherman Oaks - Digital","lineup":"USA-CA67309-X","uri":"/20141201/lineups/USA-CA67309-X"}]},{"headend":"CA67310","transport":"Cable","location":"Eagle Rock","lineups":[{"name":"Time Warner Cable City of Los Angeles - Cable","lineup":"USA-CA67310-DEFAULT","uri":"/20141201/lineups/USA-CA67310-DEFAULT"},{"name":"Time Warner Cable City of Los Angeles - Digital","lineup":"USA-CA67310-X","uri":"/20141201/lineups/USA-CA67310-X"}]},{"headend":"DISH803","transport":"Satellite","location":"Los Angeles","lineups":[{"name":"DISH Los Angeles - Satellite","lineup":"USA-DISH803-DEFAULT","uri":"/20141201/lineups/USA-DISH803-DEFAULT"}]},{"headend":"DITV803","transport":"Satellite","location":"Los Angeles","lineups":[{"name":"DIRECTV Los Angeles - Satellite","lineup":"USA-DITV803-DEFAULT","uri":"/20141201/lineups/USA-DITV803-DEFAULT"}]},{"headend":"90210","transport":"Antenna","location":"90210","lineups":[{"name":"Antenna","lineup":"USA-OTA-90210","uri":"/20141201/lineups/USA-OTA-90210"}]}] diff --git a/tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/lineup_response.json b/tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/lineup_response.json new file mode 100644 index 0000000000..0720894702 --- /dev/null +++ b/tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/lineup_response.json @@ -0,0 +1 @@ +{"map":[{"stationID":"24326","channel":"001","providerCallsign":"BBC ONE South","logicalChannelNumber":"1","matchType":"providerCallsign"},{"stationID":"17154","channel":"002","providerCallsign":"BBC TWO","logicalChannelNumber":"2","matchType":"providerCallsign"}]} diff --git a/tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/lineups_response.json b/tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/lineups_response.json new file mode 100644 index 0000000000..032a84e59e --- /dev/null +++ b/tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/lineups_response.json @@ -0,0 +1 @@ +{"code":0,"serverID":"20141201.web.1","datetime":"2015-04-17T14:22:17Z","lineups":[{"lineup":"GBR-0001317-DEFAULT","name":"Freeview - Carlton - LWT (Southeast)","transport":"DVB-T","location":"London","uri":"/20141201/lineups/GBR-0001317-DEFAULT"},{"lineup":"USA-IL57303-X","name":"Comcast Waukegan/Lake Forest Area - Digital","transport":"Cable","location":"Lake Forest","uri":"/20141201/lineups/USA-IL57303-X"},{"lineup":"USA-NY67791-X","name":"Verizon Fios Queens - Digital","transport":"Cable","location":"Fresh Meadows","uri":"/20141201/lineups/USA-NY67791-X"},{"lineup":"USA-OTA-60030","name":"Local Over the Air Broadcast","transport":"Antenna","location":"60030","uri":"/20141201/lineups/USA-OTA-60030"},{"lineup":"USA-WI61859-DEFAULT","name":"DELETED LINEUP","isDeleted":true}]} diff --git a/tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/metadata_programs_response.json b/tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/metadata_programs_response.json new file mode 100644 index 0000000000..78166f09a4 --- /dev/null +++ b/tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/metadata_programs_response.json @@ -0,0 +1 @@ +[{"programID":"SH00712240","data":[{"width":"135","height":"180","uri":"assets/p282288_b_v2_aa.jpg","size":"Sm","aspect":"3x4","category":"Banner-L3","text":"yes","primary":"true","tier":"Series"},{"width":"720","height":"540","uri":"assets/p282288_b_h6_aa.jpg","size":"Lg","aspect":"4x3","category":"Banner-L3","text":"yes","primary":"true","tier":"Series"},{"width":"960","height":"1440","uri":"assets/p282288_b_v8_aa.jpg","size":"Ms","aspect":"2x3","category":"Banner-L3","text":"yes","primary":"true","tier":"Series"},{"width":"180","height":"135","uri":"assets/p282288_b_h5_aa.jpg","size":"Sm","aspect":"4x3","category":"Banner-L3","text":"yes","primary":"true","tier":"Series"}]}] diff --git a/tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/programs_response.json b/tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/programs_response.json new file mode 100644 index 0000000000..fe2a944364 --- /dev/null +++ b/tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/programs_response.json @@ -0,0 +1 @@ +[{"programID":"EP000000060003","titles":[{"title120":"'Allo 'Allo!"}],"eventDetails":{"subType":"Series"},"descriptions":{"description1000":[{"descriptionLanguage":"en","description":"A disguised British Intelligence officer is sent to help the airmen."}]},"originalAirDate":"1985-11-04","genres":["Sitcom"],"episodeTitle150":"The Poloceman Cometh","metadata":[{"Gracenote":{"season":2,"episode":3}}],"cast":[{"personId":"383774","nameId":"392649","name":"Gorden Kaye","role":"Actor","billingOrder":"01"},{"personId":"246840","nameId":"250387","name":"Carmen Silvera","role":"Actor","billingOrder":"02"},{"personId":"376955","nameId":"385830","name":"Rose Hill","role":"Actor","billingOrder":"03"},{"personId":"259773","nameId":"263340","name":"Vicki Michelle","role":"Actor","billingOrder":"04"},{"personId":"353113","nameId":"361987","name":"Kirsten Cooke","role":"Actor","billingOrder":"05"},{"personId":"77787","nameId":"77787","name":"Richard Marner","role":"Actor","billingOrder":"06"},{"personId":"230921","nameId":"234193","name":"Guy Siner","role":"Actor","billingOrder":"07"},{"personId":"374934","nameId":"383809","name":"Kim Hartman","role":"Actor","billingOrder":"08"},{"personId":"369151","nameId":"378026","name":"Richard Gibson","role":"Actor","billingOrder":"09"},{"personId":"343690","nameId":"352564","name":"Arthur Bostrom","role":"Actor","billingOrder":"10"},{"personId":"352557","nameId":"361431","name":"John D. Collins","role":"Actor","billingOrder":"11"},{"personId":"605275","nameId":"627734","name":"Nicholas Frankau","role":"Actor","billingOrder":"12"},{"personId":"373394","nameId":"382269","name":"Jack Haig","role":"Actor","billingOrder":"13"}],"crew":[{"personId":"354407","nameId":"363281","name":"David Croft","role":"Director","billingOrder":"01"},{"personId":"354407","nameId":"363281","name":"David Croft","role":"Writer","billingOrder":"02"},{"personId":"105145","nameId":"105145","name":"Jeremy Lloyd","role":"Writer","billingOrder":"03"}],"showType":"Series","hasImageArtwork":true,"md5":"Jo5NKxoo44xRvBCAq8QT2A"},{"programID":"EP000000510142","titles":[{"title120":"A Different World"}],"eventDetails":{"subType":"Series"},"descriptions":{"description1000":[{"descriptionLanguage":"en","description":"Whitley and Dwayne tell new students about their honeymoon in Los Angeles."}]},"originalAirDate":"1992-09-24","genres":["Sitcom"],"episodeTitle150":"Honeymoon in L.A.","metadata":[{"Gracenote":{"season":6,"episode":1}}],"cast":[{"personId":"700","nameId":"700","name":"Jasmine Guy","role":"Actor","billingOrder":"01"},{"personId":"729","nameId":"729","name":"Kadeem Hardison","role":"Actor","billingOrder":"02"},{"personId":"120","nameId":"120","name":"Darryl M. Bell","role":"Actor","billingOrder":"03"},{"personId":"1729","nameId":"1729","name":"Cree Summer","role":"Actor","billingOrder":"04"},{"personId":"217","nameId":"217","name":"Charnele Brown","role":"Actor","billingOrder":"05"},{"personId":"1811","nameId":"1811","name":"Glynn Turman","role":"Actor","billingOrder":"06"},{"personId":"1232","nameId":"1232","name":"Lou Myers","role":"Actor","billingOrder":"07"},{"personId":"1363","nameId":"1363","name":"Jada Pinkett","role":"Guest Star","billingOrder":"08"},{"personId":"222967","nameId":"225536","name":"Ajai Sanders","role":"Guest Star","billingOrder":"09"},{"personId":"181744","nameId":"183292","name":"Karen Malina White","role":"Guest Star","billingOrder":"10"},{"personId":"305017","nameId":"318897","name":"Patrick Y. Malone","role":"Guest Star","billingOrder":"11"},{"personId":"9841","nameId":"9841","name":"Bumper Robinson","role":"Guest Star","billingOrder":"12"},{"personId":"426422","nameId":"435297","name":"Sister Souljah","role":"Guest Star","billingOrder":"13"},{"personId":"25","nameId":"25","name":"Debbie Allen","role":"Guest Star","billingOrder":"14"},{"personId":"668","nameId":"668","name":"Gilbert Gottfried","role":"Guest Star","billingOrder":"15"}],"showType":"Series","hasImageArtwork":true,"md5":"P5kz0QmCeYxIA+yL0H4DWw"}] diff --git a/tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/schedules_request.json b/tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/schedules_request.json new file mode 100644 index 0000000000..5ef1bfb1c4 --- /dev/null +++ b/tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/schedules_request.json @@ -0,0 +1 @@ +[{"stationID":"20454","date":["2015-03-13","2015-03-17"]},{"stationID":"10021","date":["2015-03-12","2015-03-13"]}] diff --git a/tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/schedules_response.json b/tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/schedules_response.json new file mode 100644 index 0000000000..4a97e55172 --- /dev/null +++ b/tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/schedules_response.json @@ -0,0 +1 @@ +[{"stationID":"20454","programs":[{"programID":"SH005371070000","airDateTime":"2015-03-03T00:00:00Z","duration":1800,"md5":"Sy8HEMBPcuiAx3FBukUhKQ","new":true,"audioProperties":["stereo","cc"],"videoProperties":["hdtv"]},{"programID":"EP000014577244","airDateTime":"2015-03-03T00:30:00Z","duration":1800,"md5":"25DNXVXO192JI7Y9vSW9lQ","new":true,"audioProperties":["stereo","cc"],"videoProperties":["hdtv"]}]}] diff --git a/tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/token_live_response.json b/tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/token_live_response.json new file mode 100644 index 0000000000..e5fb64a6fa --- /dev/null +++ b/tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/token_live_response.json @@ -0,0 +1 @@ +{"code":0,"message":"OK","serverID":"AWS-SD-web.1","datetime":"2016-08-23T13:55:25Z","token":"f3fca79989cafe7dead71beefedc812b"} diff --git a/tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/token_offline_response.json b/tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/token_offline_response.json new file mode 100644 index 0000000000..b66a4ed0c4 --- /dev/null +++ b/tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/token_offline_response.json @@ -0,0 +1 @@ +{"response":"SERVICE_OFFLINE","code":3000,"serverID":"20141201.web.1","message":"Server offline for maintenance.","datetime":"2015-04-23T00:03:32Z","token":"CAFEDEADBEEFCAFEDEADBEEFCAFEDEADBEEFCAFE"} -- cgit v1.2.3 From 23e6c918a22c85751cc0907cd0074ee3f3445664 Mon Sep 17 00:00:00 2001 From: Cody Robibero Date: Mon, 6 Sep 2021 11:08:40 -0600 Subject: Remove Linq to index search --- Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'Emby.Server.Implementations/LiveTv') diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs index 6686b625f4..1f963e4a29 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs @@ -10,7 +10,6 @@ using System.Linq; using System.Net; using System.Net.Http; using System.Net.Http.Headers; -using System.Net.Http.Json; using System.Net.Mime; using System.Text; using System.Text.Json; @@ -803,11 +802,10 @@ namespace Emby.Server.Implementations.LiveTv.Listings { var channelNumber = GetChannelNumber(channel); - var station = allStations.FirstOrDefault(item => string.Equals(item.StationId, channel.StationId, StringComparison.OrdinalIgnoreCase)) - ?? new StationDto - { - StationId = channel.StationId - }; + var stationIndex = allStations.FindIndex(item => string.Equals(item.StationId, channel.StationId, StringComparison.OrdinalIgnoreCase)); + var station = stationIndex == -1 + ? new StationDto { StationId = channel.StationId } + : allStations[stationIndex]; var channelInfo = new ChannelInfo { -- cgit v1.2.3 From 1603d1928e888abeccc6a5fab2e1f13aa65eea6c Mon Sep 17 00:00:00 2001 From: cvium Date: Fri, 10 Sep 2021 09:29:14 +0200 Subject: Kill ProgressiveFileCopier and seek to end for ongoing livetv --- .../Library/ExclusiveLiveStream.cs | 6 + .../Library/MediaSourceManager.cs | 18 +- .../LiveTv/EmbyTV/DirectRecorder.cs | 16 +- .../TunerHosts/HdHomerun/HdHomerunUdpStream.cs | 7 +- .../LiveTv/TunerHosts/LiveStream.cs | 117 +++---------- .../LiveTv/TunerHosts/SharedHttpStream.cs | 49 ++---- Jellyfin.Api/Controllers/LiveTvController.cs | 6 +- Jellyfin.Api/Controllers/VideosController.cs | 19 +-- Jellyfin.Api/Helpers/AudioHelper.cs | 19 +-- Jellyfin.Api/Helpers/ProgressiveFileCopier.cs | 187 --------------------- Jellyfin.Api/Helpers/ProgressiveFileStream.cs | 37 ++-- Jellyfin.Api/Models/StreamingDtos/StreamState.cs | 3 + .../Library/IDirectStreamProvider.cs | 20 +++ MediaBrowser.Controller/Library/ILiveStream.cs | 3 + .../Library/IMediaSourceManager.cs | 15 +- 15 files changed, 136 insertions(+), 386 deletions(-) delete mode 100644 Jellyfin.Api/Helpers/ProgressiveFileCopier.cs create mode 100644 MediaBrowser.Controller/Library/IDirectStreamProvider.cs (limited to 'Emby.Server.Implementations/LiveTv') diff --git a/Emby.Server.Implementations/Library/ExclusiveLiveStream.cs b/Emby.Server.Implementations/Library/ExclusiveLiveStream.cs index 6c65b58999..9ba9f2115e 100644 --- a/Emby.Server.Implementations/Library/ExclusiveLiveStream.cs +++ b/Emby.Server.Implementations/Library/ExclusiveLiveStream.cs @@ -4,6 +4,7 @@ using System; using System.Globalization; +using System.IO; using System.Threading; using System.Threading.Tasks; using MediaBrowser.Controller.Library; @@ -41,6 +42,11 @@ namespace Emby.Server.Implementations.Library return _closeFn(); } + public Stream GetStream(bool seekNearEnd) + { + throw new NotSupportedException(); + } + public Task Open(CancellationToken openCancellationToken) { return Task.CompletedTask; diff --git a/Emby.Server.Implementations/Library/MediaSourceManager.cs b/Emby.Server.Implementations/Library/MediaSourceManager.cs index 6f83973ba1..8e4b32a9c9 100644 --- a/Emby.Server.Implementations/Library/MediaSourceManager.cs +++ b/Emby.Server.Implementations/Library/MediaSourceManager.cs @@ -602,7 +602,7 @@ namespace Emby.Server.Implementations.Library public async Task GetLiveStreamMediaInfo(string id, CancellationToken cancellationToken) { - var liveStreamInfo = await GetLiveStreamInfo(id, cancellationToken).ConfigureAwait(false); + var liveStreamInfo = GetLiveStreamInfo(id); var mediaSource = liveStreamInfo.MediaSource; @@ -771,18 +771,18 @@ namespace Emby.Server.Implementations.Library mediaSource.InferTotalBitrate(true); } - public async Task> GetLiveStreamWithDirectStreamProvider(string id, CancellationToken cancellationToken) + public Task> GetLiveStreamWithDirectStreamProvider(string id, CancellationToken cancellationToken) { if (string.IsNullOrEmpty(id)) { throw new ArgumentNullException(nameof(id)); } - var info = await GetLiveStreamInfo(id, cancellationToken).ConfigureAwait(false); - return new Tuple(info.MediaSource, info as IDirectStreamProvider); + var info = GetLiveStreamInfo(id); + return Task.FromResult(new Tuple(info.MediaSource, info as IDirectStreamProvider)); } - private Task GetLiveStreamInfo(string id, CancellationToken cancellationToken) + public ILiveStream GetLiveStreamInfo(string id) { if (string.IsNullOrEmpty(id)) { @@ -791,12 +791,10 @@ namespace Emby.Server.Implementations.Library if (_openStreams.TryGetValue(id, out ILiveStream info)) { - return Task.FromResult(info); - } - else - { - return Task.FromException(new ResourceNotFoundException()); + return info; } + + throw new ResourceNotFoundException(); } public async Task GetLiveStream(string id, CancellationToken cancellationToken) diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs index c5a9a92ec2..fdefa2679a 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs @@ -5,6 +5,7 @@ using System.IO; using System.Net.Http; using System.Threading; using System.Threading.Tasks; +using Jellyfin.Api.Helpers; using MediaBrowser.Common.Net; using MediaBrowser.Controller.Library; using MediaBrowser.Model.Dto; @@ -50,16 +51,23 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV { onStarted(); - _logger.LogInformation("Copying recording stream to file {0}", targetFile); + _logger.LogInformation("Copying recording to file {FilePath}", targetFile); // The media source is infinite so we need to handle stopping ourselves using var durationToken = new CancellationTokenSource(duration); using var cancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, durationToken.Token); - - await directStreamProvider.CopyToAsync(output, cancellationTokenSource.Token).ConfigureAwait(false); + var linkedCancellationToken = cancellationTokenSource.Token; + + await using var fileStream = new ProgressiveFileStream(directStreamProvider.GetStream(), null, null); + await _streamHelper.CopyToAsync( + fileStream, + output, + IODefaults.CopyToBufferSize, + 1000, + linkedCancellationToken).ConfigureAwait(false); } - _logger.LogInformation("Recording completed to file {0}", targetFile); + _logger.LogInformation("Recording completed: {FilePath}", targetFile); } private async Task RecordFromMediaSource(MediaSourceInfo mediaSource, string targetFile, TimeSpan duration, Action onStarted, CancellationToken cancellationToken) diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs index 58e0c7448a..a8f761fdeb 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs @@ -156,11 +156,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun await taskCompletionSource.Task.ConfigureAwait(false); } - public string GetFilePath() - { - return TempFilePath; - } - private async Task StartStreaming(UdpClient udpClient, HdHomerunManager hdHomerunManager, IPAddress remoteAddress, TaskCompletionSource openTaskCompletionSource, CancellationToken cancellationToken) { using (udpClient) @@ -184,7 +179,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun EnableStreamSharing = false; } - await DeleteTempFiles(new List { TempFilePath }).ConfigureAwait(false); + await DeleteTempFiles(TempFilePath).ConfigureAwait(false); } private async Task CopyTo(UdpClient udpClient, string file, TaskCompletionSource openTaskCompletionSource, CancellationToken cancellationToken) diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs index 2c21a4a893..4f9d343276 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs @@ -3,10 +3,8 @@ #pragma warning disable CS1591 using System; -using System.Collections.Generic; using System.Globalization; using System.IO; -using System.Linq; using System.Threading; using System.Threading.Tasks; using MediaBrowser.Common.Configuration; @@ -97,6 +95,18 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts return Task.CompletedTask; } + public Stream GetStream(bool seekNearEnd = true) + { + var stream = GetInputStream(TempFilePath, AsyncFile.UseAsyncIO); + bool seekFile = (DateTime.UtcNow - DateOpened).TotalSeconds > 10; + if (seekFile) + { + TrySeek(stream, -20000); + } + + return stream; + } + protected FileStream GetInputStream(string path, bool allowAsyncFileRead) => new FileStream( path, @@ -106,112 +116,29 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts IODefaults.FileStreamBufferSize, allowAsyncFileRead ? FileOptions.SequentialScan | FileOptions.Asynchronous : FileOptions.SequentialScan); - public Task DeleteTempFiles() - { - return DeleteTempFiles(GetStreamFilePaths()); - } - - protected async Task DeleteTempFiles(IEnumerable paths, int retryCount = 0) + protected async Task DeleteTempFiles(string path, int retryCount = 0) { if (retryCount == 0) { - Logger.LogInformation("Deleting temp files {0}", paths); - } - - var failedFiles = new List(); - - foreach (var path in paths) - { - if (!File.Exists(path)) - { - continue; - } - - try - { - FileSystem.DeleteFile(path); - } - catch (Exception ex) - { - Logger.LogError(ex, "Error deleting file {path}", path); - failedFiles.Add(path); - } - } - - if (failedFiles.Count > 0 && retryCount <= 40) - { - await Task.Delay(500).ConfigureAwait(false); - await DeleteTempFiles(failedFiles, retryCount + 1).ConfigureAwait(false); + Logger.LogInformation("Deleting temp file {FilePath}", path); } - } - protected virtual List GetStreamFilePaths() - { - return new List { TempFilePath }; - } - - public async Task CopyToAsync(Stream stream, CancellationToken cancellationToken) - { - using var linkedCancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, LiveStreamCancellationTokenSource.Token); - cancellationToken = linkedCancellationTokenSource.Token; - - bool seekFile = (DateTime.UtcNow - DateOpened).TotalSeconds > 10; - - var nextFileInfo = GetNextFile(null); - var nextFile = nextFileInfo.file; - var isLastFile = nextFileInfo.isLastFile; - - var allowAsync = AsyncFile.UseAsyncIO; - while (!string.IsNullOrEmpty(nextFile)) - { - var emptyReadLimit = isLastFile ? EmptyReadLimit : 1; - - await CopyFile(nextFile, seekFile, emptyReadLimit, allowAsync, stream, cancellationToken).ConfigureAwait(false); - - seekFile = false; - nextFileInfo = GetNextFile(nextFile); - nextFile = nextFileInfo.file; - isLastFile = nextFileInfo.isLastFile; - } - - Logger.LogInformation("Live Stream ended."); - } - - private (string file, bool isLastFile) GetNextFile(string currentFile) - { - var files = GetStreamFilePaths(); - - if (string.IsNullOrEmpty(currentFile)) + try { - return (files[^1], true); + FileSystem.DeleteFile(path); } - - var nextIndex = files.FindIndex(i => string.Equals(i, currentFile, StringComparison.OrdinalIgnoreCase)) + 1; - - var isLastFile = nextIndex == files.Count - 1; - - return (files.ElementAtOrDefault(nextIndex), isLastFile); - } - - private async Task CopyFile(string path, bool seekFile, int emptyReadLimit, bool allowAsync, Stream stream, CancellationToken cancellationToken) - { - using (var inputStream = GetInputStream(path, allowAsync)) + catch (Exception ex) { - if (seekFile) + Logger.LogError(ex, "Error deleting file {FilePath}", path); + if (retryCount <= 40) { - TrySeek(inputStream, -20000); + await Task.Delay(500).ConfigureAwait(false); + await DeleteTempFiles(path, retryCount + 1).ConfigureAwait(false); } - - await StreamHelper.CopyToAsync( - inputStream, - stream, - IODefaults.CopyToBufferSize, - emptyReadLimit, - cancellationToken).ConfigureAwait(false); } } - private void TrySeek(FileStream stream, long offset) + private void TrySeek(Stream stream, long offset) { if (!stream.CanSeek) { diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs index 8629938777..84a878e517 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs @@ -3,7 +3,6 @@ #pragma warning disable CS1591 using System; -using System.Collections.Generic; using System.Globalization; using System.IO; using System.Net.Http; @@ -55,39 +54,26 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts Directory.CreateDirectory(Path.GetDirectoryName(TempFilePath)); var typeName = GetType().Name; - Logger.LogInformation("Opening " + typeName + " Live stream from {0}", url); + Logger.LogInformation("Opening {StreamType} Live stream from {Url}", typeName, url); // Response stream is disposed manually. var response = await _httpClientFactory.CreateClient(NamedClient.Default) .GetAsync(url, HttpCompletionOption.ResponseHeadersRead, CancellationToken.None) .ConfigureAwait(false); - var extension = "ts"; - var requiresRemux = false; - var contentType = response.Content.Headers.ContentType?.ToString() ?? string.Empty; - if (contentType.IndexOf("matroska", StringComparison.OrdinalIgnoreCase) != -1) - { - requiresRemux = true; - } - else if (contentType.IndexOf("mp4", StringComparison.OrdinalIgnoreCase) != -1 || - contentType.IndexOf("dash", StringComparison.OrdinalIgnoreCase) != -1 || - contentType.IndexOf("mpegURL", StringComparison.OrdinalIgnoreCase) != -1 || - contentType.IndexOf("text/", StringComparison.OrdinalIgnoreCase) != -1) - { - requiresRemux = true; - } - - // Close the stream without any sharing features - if (requiresRemux) + if (contentType.Contains("matroska", StringComparison.OrdinalIgnoreCase) + || contentType.Contains("mp4", StringComparison.OrdinalIgnoreCase) + || contentType.Contains("dash", StringComparison.OrdinalIgnoreCase) + || contentType.Contains("mpegURL", StringComparison.OrdinalIgnoreCase) + || contentType.Contains("text/", StringComparison.OrdinalIgnoreCase)) { - using (response) - { - return; - } + // Close the stream without any sharing features + response.Dispose(); + return; } - SetTempFilePath(extension); + SetTempFilePath("ts"); var taskCompletionSource = new TaskCompletionSource(); @@ -117,16 +103,11 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts if (!taskCompletionSource.Task.Result) { - Logger.LogWarning("Zero bytes copied from stream {0} to {1} but no exception raised", GetType().Name, TempFilePath); + Logger.LogWarning("Zero bytes copied from stream {StreamType} to {FilePath} but no exception raised", GetType().Name, TempFilePath); throw new EndOfStreamException(string.Format(CultureInfo.InvariantCulture, "Zero bytes copied from stream {0}", GetType().Name)); } } - public string GetFilePath() - { - return TempFilePath; - } - private Task StartStreaming(HttpResponseMessage response, TaskCompletionSource openTaskCompletionSource, CancellationToken cancellationToken) { return Task.Run( @@ -134,7 +115,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts { try { - Logger.LogInformation("Beginning {0} stream to {1}", GetType().Name, TempFilePath); + Logger.LogInformation("Beginning {StreamType} stream to {FilePath}", GetType().Name, TempFilePath); using var message = response; await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); await using var fileStream = new FileStream(TempFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, IODefaults.FileStreamBufferSize, AsyncFile.UseAsyncIO); @@ -147,19 +128,19 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts } catch (OperationCanceledException ex) { - Logger.LogInformation("Copying of {0} to {1} was canceled", GetType().Name, TempFilePath); + Logger.LogInformation("Copying of {StreamType} to {FilePath} was canceled", GetType().Name, TempFilePath); openTaskCompletionSource.TrySetException(ex); } catch (Exception ex) { - Logger.LogError(ex, "Error copying live stream {0} to {1}.", GetType().Name, TempFilePath); + Logger.LogError(ex, "Error copying live stream {StreamType} to {FilePath}", GetType().Name, TempFilePath); openTaskCompletionSource.TrySetException(ex); } openTaskCompletionSource.TrySetResult(false); EnableStreamSharing = false; - await DeleteTempFiles(new List { TempFilePath }).ConfigureAwait(false); + await DeleteTempFiles(TempFilePath).ConfigureAwait(false); }, CancellationToken.None); } diff --git a/Jellyfin.Api/Controllers/LiveTvController.cs b/Jellyfin.Api/Controllers/LiveTvController.cs index 93dc767291..c3856b882e 100644 --- a/Jellyfin.Api/Controllers/LiveTvController.cs +++ b/Jellyfin.Api/Controllers/LiveTvController.cs @@ -1199,15 +1199,15 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] [ProducesVideoFile] - public async Task GetLiveStreamFile([FromRoute, Required] string streamId, [FromRoute, Required] string container) + public ActionResult GetLiveStreamFile([FromRoute, Required] string streamId, [FromRoute, Required] string container) { - var liveStreamInfo = await _mediaSourceManager.GetDirectStreamProviderByUniqueId(streamId, CancellationToken.None).ConfigureAwait(false); + var liveStreamInfo = _mediaSourceManager.GetLiveStreamInfo(streamId); if (liveStreamInfo == null) { return NotFound(); } - var liveStream = new ProgressiveFileStream(liveStreamInfo.GetFilePath(), null, _transcodingJobHelper); + var liveStream = new ProgressiveFileStream(liveStreamInfo.GetStream(), null, _transcodingJobHelper); return new FileStreamResult(liveStream, MimeTypes.GetMimeType("file." + container)); } diff --git a/Jellyfin.Api/Controllers/VideosController.cs b/Jellyfin.Api/Controllers/VideosController.cs index bc6fc904a1..0af10ceefa 100644 --- a/Jellyfin.Api/Controllers/VideosController.cs +++ b/Jellyfin.Api/Controllers/VideosController.cs @@ -453,14 +453,10 @@ namespace Jellyfin.Api.Controllers { StreamingHelpers.AddDlnaHeaders(state, Response.Headers, true, startTimeTicks, Request, _dlnaManager); - await new ProgressiveFileCopier(state.DirectStreamProvider, null, _transcodingJobHelper, CancellationToken.None) - { - AllowEndOfFile = false - }.WriteToAsync(Response.Body, CancellationToken.None) - .ConfigureAwait(false); - + var liveStreamInfo = _mediaSourceManager.GetLiveStreamInfo(streamingRequest.LiveStreamId); + var liveStream = new ProgressiveFileStream(liveStreamInfo.GetStream(), null, _transcodingJobHelper); // TODO (moved from MediaBrowser.Api): Don't hardcode contentType - return File(Response.Body, MimeTypes.GetMimeType("file.ts")!); + return File(liveStream, MimeTypes.GetMimeType("file.ts")!); } // Static remote stream @@ -492,13 +488,8 @@ namespace Jellyfin.Api.Controllers if (state.MediaSource.IsInfiniteStream) { - await new ProgressiveFileCopier(state.MediaPath, null, _transcodingJobHelper, CancellationToken.None) - { - AllowEndOfFile = false - }.WriteToAsync(Response.Body, CancellationToken.None) - .ConfigureAwait(false); - - return File(Response.Body, contentType); + var liveStream = new ProgressiveFileStream(state.MediaPath, null, _transcodingJobHelper); + return File(liveStream, contentType); } return FileStreamResponseHelpers.GetStaticFileResult( diff --git a/Jellyfin.Api/Helpers/AudioHelper.cs b/Jellyfin.Api/Helpers/AudioHelper.cs index ddcde1cf6d..19da180e53 100644 --- a/Jellyfin.Api/Helpers/AudioHelper.cs +++ b/Jellyfin.Api/Helpers/AudioHelper.cs @@ -120,14 +120,10 @@ namespace Jellyfin.Api.Helpers { StreamingHelpers.AddDlnaHeaders(state, _httpContextAccessor.HttpContext.Response.Headers, true, streamingRequest.StartTimeTicks, _httpContextAccessor.HttpContext.Request, _dlnaManager); - await new ProgressiveFileCopier(state.DirectStreamProvider, null, _transcodingJobHelper, CancellationToken.None) - { - AllowEndOfFile = false - }.WriteToAsync(_httpContextAccessor.HttpContext.Response.Body, CancellationToken.None) - .ConfigureAwait(false); - + var liveStreamInfo = _mediaSourceManager.GetLiveStreamInfo(streamingRequest.LiveStreamId); + var liveStream = new ProgressiveFileStream(liveStreamInfo.GetStream(), null, _transcodingJobHelper); // TODO (moved from MediaBrowser.Api): Don't hardcode contentType - return new FileStreamResult(_httpContextAccessor.HttpContext.Response.Body, MimeTypes.GetMimeType("file.ts")!); + return new FileStreamResult(liveStream, MimeTypes.GetMimeType("file.ts")); } // Static remote stream @@ -159,13 +155,8 @@ namespace Jellyfin.Api.Helpers if (state.MediaSource.IsInfiniteStream) { - await new ProgressiveFileCopier(state.MediaPath, null, _transcodingJobHelper, CancellationToken.None) - { - AllowEndOfFile = false - }.WriteToAsync(_httpContextAccessor.HttpContext.Response.Body, CancellationToken.None) - .ConfigureAwait(false); - - return new FileStreamResult(_httpContextAccessor.HttpContext.Response.Body, contentType); + var stream = new ProgressiveFileStream(state.MediaPath, null, _transcodingJobHelper); + return new FileStreamResult(stream, contentType); } return FileStreamResponseHelpers.GetStaticFileResult( diff --git a/Jellyfin.Api/Helpers/ProgressiveFileCopier.cs b/Jellyfin.Api/Helpers/ProgressiveFileCopier.cs deleted file mode 100644 index 81970b041a..0000000000 --- a/Jellyfin.Api/Helpers/ProgressiveFileCopier.cs +++ /dev/null @@ -1,187 +0,0 @@ -using System; -using System.Buffers; -using System.IO; -using System.Threading; -using System.Threading.Tasks; -using Jellyfin.Api.Models.PlaybackDtos; -using MediaBrowser.Common.Extensions; -using MediaBrowser.Controller.Library; -using MediaBrowser.Model.IO; - -namespace Jellyfin.Api.Helpers -{ - /// - /// Progressive file copier. - /// - public class ProgressiveFileCopier - { - private readonly TranscodingJobDto? _job; - private readonly string? _path; - private readonly CancellationToken _cancellationToken; - private readonly IDirectStreamProvider? _directStreamProvider; - private readonly TranscodingJobHelper _transcodingJobHelper; - private long _bytesWritten; - - /// - /// Initializes a new instance of the class. - /// - /// The path to copy from. - /// The transcoding job. - /// Instance of the . - /// The cancellation token. - public ProgressiveFileCopier(string path, TranscodingJobDto? job, TranscodingJobHelper transcodingJobHelper, CancellationToken cancellationToken) - { - _path = path; - _job = job; - _cancellationToken = cancellationToken; - _transcodingJobHelper = transcodingJobHelper; - } - - /// - /// Initializes a new instance of the class. - /// - /// Instance of the interface. - /// The transcoding job. - /// Instance of the . - /// The cancellation token. - public ProgressiveFileCopier(IDirectStreamProvider directStreamProvider, TranscodingJobDto? job, TranscodingJobHelper transcodingJobHelper, CancellationToken cancellationToken) - { - _directStreamProvider = directStreamProvider; - _job = job; - _cancellationToken = cancellationToken; - _transcodingJobHelper = transcodingJobHelper; - } - - /// - /// Gets or sets a value indicating whether allow read end of file. - /// - public bool AllowEndOfFile { get; set; } = true; - - /// - /// Gets or sets copy start position. - /// - public long StartPosition { get; set; } - - /// - /// Write source stream to output. - /// - /// Output stream. - /// Cancellation token. - /// A . - public async Task WriteToAsync(Stream outputStream, CancellationToken cancellationToken) - { - using var linkedCancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, _cancellationToken); - cancellationToken = linkedCancellationTokenSource.Token; - - try - { - if (_directStreamProvider != null) - { - await _directStreamProvider.CopyToAsync(outputStream, cancellationToken).ConfigureAwait(false); - return; - } - - var fileOptions = FileOptions.SequentialScan; - var allowAsyncFileRead = false; - - if (AsyncFile.UseAsyncIO) - { - fileOptions |= FileOptions.Asynchronous; - allowAsyncFileRead = true; - } - - if (_path == null) - { - throw new ResourceNotFoundException(nameof(_path)); - } - - await using var inputStream = new FileStream(_path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, IODefaults.FileStreamBufferSize, fileOptions); - - var eofCount = 0; - const int EmptyReadLimit = 20; - if (StartPosition > 0) - { - inputStream.Position = StartPosition; - } - - while (eofCount < EmptyReadLimit || !AllowEndOfFile) - { - var bytesRead = await CopyToInternalAsync(inputStream, outputStream, allowAsyncFileRead, cancellationToken).ConfigureAwait(false); - - if (bytesRead == 0) - { - if (_job == null || _job.HasExited) - { - eofCount++; - } - - await Task.Delay(100, cancellationToken).ConfigureAwait(false); - } - else - { - eofCount = 0; - } - } - } - finally - { - if (_job != null) - { - _transcodingJobHelper.OnTranscodeEndRequest(_job); - } - } - } - - private async Task CopyToInternalAsync(Stream source, Stream destination, bool readAsync, CancellationToken cancellationToken) - { - var array = ArrayPool.Shared.Rent(IODefaults.CopyToBufferSize); - try - { - int bytesRead; - int totalBytesRead = 0; - - if (readAsync) - { - bytesRead = await source.ReadAsync(array, 0, array.Length, cancellationToken).ConfigureAwait(false); - } - else - { - bytesRead = source.Read(array, 0, array.Length); - } - - while (bytesRead != 0) - { - var bytesToWrite = bytesRead; - - if (bytesToWrite > 0) - { - await destination.WriteAsync(array, 0, Convert.ToInt32(bytesToWrite), cancellationToken).ConfigureAwait(false); - - _bytesWritten += bytesRead; - totalBytesRead += bytesRead; - - if (_job != null) - { - _job.BytesDownloaded = Math.Max(_job.BytesDownloaded ?? _bytesWritten, _bytesWritten); - } - } - - if (readAsync) - { - bytesRead = await source.ReadAsync(array, 0, array.Length, cancellationToken).ConfigureAwait(false); - } - else - { - bytesRead = source.Read(array, 0, array.Length); - } - } - - return totalBytesRead; - } - finally - { - ArrayPool.Shared.Return(array); - } - } - } -} diff --git a/Jellyfin.Api/Helpers/ProgressiveFileStream.cs b/Jellyfin.Api/Helpers/ProgressiveFileStream.cs index d4cc0172d9..9939734179 100644 --- a/Jellyfin.Api/Helpers/ProgressiveFileStream.cs +++ b/Jellyfin.Api/Helpers/ProgressiveFileStream.cs @@ -13,9 +13,9 @@ namespace Jellyfin.Api.Helpers /// public class ProgressiveFileStream : Stream { - private readonly FileStream _fileStream; + private readonly Stream _stream; private readonly TranscodingJobDto? _job; - private readonly TranscodingJobHelper _transcodingJobHelper; + private readonly TranscodingJobHelper? _transcodingJobHelper; private readonly int _timeoutMs; private readonly bool _allowAsyncFileRead; private int _bytesWritten; @@ -33,7 +33,6 @@ namespace Jellyfin.Api.Helpers _job = job; _transcodingJobHelper = transcodingJobHelper; _timeoutMs = timeoutMs; - _bytesWritten = 0; var fileOptions = FileOptions.SequentialScan; _allowAsyncFileRead = false; @@ -45,11 +44,27 @@ namespace Jellyfin.Api.Helpers _allowAsyncFileRead = true; } - _fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, IODefaults.FileStreamBufferSize, fileOptions); + _stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, IODefaults.FileStreamBufferSize, fileOptions); + } + + /// + /// Initializes a new instance of the class. + /// + /// The stream to progressively copy. + /// The transcoding job information. + /// The transcoding job helper. + /// The timeout duration in milliseconds. + public ProgressiveFileStream(Stream stream, TranscodingJobDto? job, TranscodingJobHelper? transcodingJobHelper, int timeoutMs = 30000) + { + _job = job; + _transcodingJobHelper = transcodingJobHelper; + _timeoutMs = timeoutMs; + _allowAsyncFileRead = AsyncFile.UseAsyncIO; + _stream = stream; } /// - public override bool CanRead => _fileStream.CanRead; + public override bool CanRead => _stream.CanRead; /// public override bool CanSeek => false; @@ -70,13 +85,13 @@ namespace Jellyfin.Api.Helpers /// public override void Flush() { - _fileStream.Flush(); + _stream.Flush(); } /// public override int Read(byte[] buffer, int offset, int count) { - return _fileStream.Read(buffer, offset, count); + return _stream.Read(buffer, offset, count); } /// @@ -93,11 +108,11 @@ namespace Jellyfin.Api.Helpers int bytesRead; if (_allowAsyncFileRead) { - bytesRead = await _fileStream.ReadAsync(buffer, newOffset, remainingBytesToRead, cancellationToken).ConfigureAwait(false); + bytesRead = await _stream.ReadAsync(buffer, newOffset, remainingBytesToRead, cancellationToken).ConfigureAwait(false); } else { - bytesRead = _fileStream.Read(buffer, newOffset, remainingBytesToRead); + bytesRead = _stream.Read(buffer, newOffset, remainingBytesToRead); } remainingBytesToRead -= bytesRead; @@ -152,11 +167,11 @@ namespace Jellyfin.Api.Helpers { if (disposing) { - _fileStream.Dispose(); + _stream.Dispose(); if (_job != null) { - _transcodingJobHelper.OnTranscodeEndRequest(_job); + _transcodingJobHelper?.OnTranscodeEndRequest(_job); } } } diff --git a/Jellyfin.Api/Models/StreamingDtos/StreamState.cs b/Jellyfin.Api/Models/StreamingDtos/StreamState.cs index e95f2d1f43..0f84faeafc 100644 --- a/Jellyfin.Api/Models/StreamingDtos/StreamState.cs +++ b/Jellyfin.Api/Models/StreamingDtos/StreamState.cs @@ -60,6 +60,9 @@ namespace Jellyfin.Api.Models.StreamingDtos /// /// Gets or sets the direct stream provicer. /// + /// + /// Deprecated. + /// public IDirectStreamProvider? DirectStreamProvider { get; set; } /// diff --git a/MediaBrowser.Controller/Library/IDirectStreamProvider.cs b/MediaBrowser.Controller/Library/IDirectStreamProvider.cs new file mode 100644 index 0000000000..2939668f7d --- /dev/null +++ b/MediaBrowser.Controller/Library/IDirectStreamProvider.cs @@ -0,0 +1,20 @@ +using System.IO; + +namespace MediaBrowser.Controller.Library +{ + /// + /// The direct live TV stream provider. + /// + /// + /// Deprecated. + /// + public interface IDirectStreamProvider + { + /// + /// Gets the live stream, optionally seeks to the end of the file first. + /// + /// A value indicating whether to seek to the end of the file. + /// The stream. + Stream GetStream(bool seekNearEnd = true); + } +} diff --git a/MediaBrowser.Controller/Library/ILiveStream.cs b/MediaBrowser.Controller/Library/ILiveStream.cs index 323aa48768..a29a91fe9c 100644 --- a/MediaBrowser.Controller/Library/ILiveStream.cs +++ b/MediaBrowser.Controller/Library/ILiveStream.cs @@ -2,6 +2,7 @@ #pragma warning disable CA1711, CS1591 +using System.IO; using System.Threading; using System.Threading.Tasks; using MediaBrowser.Model.Dto; @@ -25,5 +26,7 @@ namespace MediaBrowser.Controller.Library Task Open(CancellationToken openCancellationToken); Task Close(); + + Stream GetStream(bool seekNearEnd = true); } } diff --git a/MediaBrowser.Controller/Library/IMediaSourceManager.cs b/MediaBrowser.Controller/Library/IMediaSourceManager.cs index fd3631da9c..0de3ccf3f0 100644 --- a/MediaBrowser.Controller/Library/IMediaSourceManager.cs +++ b/MediaBrowser.Controller/Library/IMediaSourceManager.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; -using System.IO; using System.Threading; using System.Threading.Tasks; using Jellyfin.Data.Entities; @@ -110,6 +109,13 @@ namespace MediaBrowser.Controller.Library Task> GetLiveStreamWithDirectStreamProvider(string id, CancellationToken cancellationToken); + /// + /// Gets the live stream info. + /// + /// The identifier. + /// An instance of . + public ILiveStream GetLiveStreamInfo(string id); + /// /// Closes the media source. /// @@ -129,11 +135,4 @@ namespace MediaBrowser.Controller.Library Task GetDirectStreamProviderByUniqueId(string uniqueId, CancellationToken cancellationToken); } - - public interface IDirectStreamProvider - { - Task CopyToAsync(Stream stream, CancellationToken cancellationToken); - - string GetFilePath(); - } } -- cgit v1.2.3 From f3573b061c4d9eb869316ce3de320fd8803aeef8 Mon Sep 17 00:00:00 2001 From: cvium Date: Fri, 10 Sep 2021 09:56:48 +0200 Subject: Remove the unused arg --- Emby.Server.Implementations/Library/ExclusiveLiveStream.cs | 2 +- Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs | 2 +- MediaBrowser.Controller/Library/IDirectStreamProvider.cs | 5 ++--- MediaBrowser.Controller/Library/ILiveStream.cs | 2 +- 4 files changed, 5 insertions(+), 6 deletions(-) (limited to 'Emby.Server.Implementations/LiveTv') diff --git a/Emby.Server.Implementations/Library/ExclusiveLiveStream.cs b/Emby.Server.Implementations/Library/ExclusiveLiveStream.cs index 9ba9f2115e..868071a992 100644 --- a/Emby.Server.Implementations/Library/ExclusiveLiveStream.cs +++ b/Emby.Server.Implementations/Library/ExclusiveLiveStream.cs @@ -42,7 +42,7 @@ namespace Emby.Server.Implementations.Library return _closeFn(); } - public Stream GetStream(bool seekNearEnd) + public Stream GetStream() { throw new NotSupportedException(); } diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs index 4f9d343276..817b1f8046 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs @@ -95,7 +95,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts return Task.CompletedTask; } - public Stream GetStream(bool seekNearEnd = true) + public Stream GetStream() { var stream = GetInputStream(TempFilePath, AsyncFile.UseAsyncIO); bool seekFile = (DateTime.UtcNow - DateOpened).TotalSeconds > 10; diff --git a/MediaBrowser.Controller/Library/IDirectStreamProvider.cs b/MediaBrowser.Controller/Library/IDirectStreamProvider.cs index 2939668f7d..96f8b7eba9 100644 --- a/MediaBrowser.Controller/Library/IDirectStreamProvider.cs +++ b/MediaBrowser.Controller/Library/IDirectStreamProvider.cs @@ -11,10 +11,9 @@ namespace MediaBrowser.Controller.Library public interface IDirectStreamProvider { /// - /// Gets the live stream, optionally seeks to the end of the file first. + /// Gets the live stream, shared streams seek to the end of the file first. /// - /// A value indicating whether to seek to the end of the file. /// The stream. - Stream GetStream(bool seekNearEnd = true); + Stream GetStream(); } } diff --git a/MediaBrowser.Controller/Library/ILiveStream.cs b/MediaBrowser.Controller/Library/ILiveStream.cs index a29a91fe9c..4c44a17fdd 100644 --- a/MediaBrowser.Controller/Library/ILiveStream.cs +++ b/MediaBrowser.Controller/Library/ILiveStream.cs @@ -27,6 +27,6 @@ namespace MediaBrowser.Controller.Library Task Close(); - Stream GetStream(bool seekNearEnd = true); + Stream GetStream(); } } -- cgit v1.2.3 From 1a5a74d2a95506249cf071c659e3c6cf01f28f78 Mon Sep 17 00:00:00 2001 From: cvium Date: Fri, 10 Sep 2021 10:03:42 +0200 Subject: Remove more unused args --- Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs | 2 +- Jellyfin.Api/Controllers/LiveTvController.cs | 2 +- Jellyfin.Api/Controllers/VideosController.cs | 2 +- Jellyfin.Api/Helpers/AudioHelper.cs | 2 +- Jellyfin.Api/Helpers/ProgressiveFileStream.cs | 8 +++----- 5 files changed, 7 insertions(+), 9 deletions(-) (limited to 'Emby.Server.Implementations/LiveTv') diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs index fdefa2679a..f6e0111b6d 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs @@ -58,7 +58,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV using var cancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, durationToken.Token); var linkedCancellationToken = cancellationTokenSource.Token; - await using var fileStream = new ProgressiveFileStream(directStreamProvider.GetStream(), null, null); + await using var fileStream = new ProgressiveFileStream(directStreamProvider.GetStream()); await _streamHelper.CopyToAsync( fileStream, output, diff --git a/Jellyfin.Api/Controllers/LiveTvController.cs b/Jellyfin.Api/Controllers/LiveTvController.cs index c3856b882e..3f68b267f3 100644 --- a/Jellyfin.Api/Controllers/LiveTvController.cs +++ b/Jellyfin.Api/Controllers/LiveTvController.cs @@ -1207,7 +1207,7 @@ namespace Jellyfin.Api.Controllers return NotFound(); } - var liveStream = new ProgressiveFileStream(liveStreamInfo.GetStream(), null, _transcodingJobHelper); + var liveStream = new ProgressiveFileStream(liveStreamInfo.GetStream()); return new FileStreamResult(liveStream, MimeTypes.GetMimeType("file." + container)); } diff --git a/Jellyfin.Api/Controllers/VideosController.cs b/Jellyfin.Api/Controllers/VideosController.cs index 0af10ceefa..d7d48ba3e7 100644 --- a/Jellyfin.Api/Controllers/VideosController.cs +++ b/Jellyfin.Api/Controllers/VideosController.cs @@ -454,7 +454,7 @@ namespace Jellyfin.Api.Controllers StreamingHelpers.AddDlnaHeaders(state, Response.Headers, true, startTimeTicks, Request, _dlnaManager); var liveStreamInfo = _mediaSourceManager.GetLiveStreamInfo(streamingRequest.LiveStreamId); - var liveStream = new ProgressiveFileStream(liveStreamInfo.GetStream(), null, _transcodingJobHelper); + var liveStream = new ProgressiveFileStream(liveStreamInfo.GetStream()); // TODO (moved from MediaBrowser.Api): Don't hardcode contentType return File(liveStream, MimeTypes.GetMimeType("file.ts")!); } diff --git a/Jellyfin.Api/Helpers/AudioHelper.cs b/Jellyfin.Api/Helpers/AudioHelper.cs index 19da180e53..06f889f085 100644 --- a/Jellyfin.Api/Helpers/AudioHelper.cs +++ b/Jellyfin.Api/Helpers/AudioHelper.cs @@ -121,7 +121,7 @@ namespace Jellyfin.Api.Helpers StreamingHelpers.AddDlnaHeaders(state, _httpContextAccessor.HttpContext.Response.Headers, true, streamingRequest.StartTimeTicks, _httpContextAccessor.HttpContext.Request, _dlnaManager); var liveStreamInfo = _mediaSourceManager.GetLiveStreamInfo(streamingRequest.LiveStreamId); - var liveStream = new ProgressiveFileStream(liveStreamInfo.GetStream(), null, _transcodingJobHelper); + var liveStream = new ProgressiveFileStream(liveStreamInfo.GetStream()); // TODO (moved from MediaBrowser.Api): Don't hardcode contentType return new FileStreamResult(liveStream, MimeTypes.GetMimeType("file.ts")); } diff --git a/Jellyfin.Api/Helpers/ProgressiveFileStream.cs b/Jellyfin.Api/Helpers/ProgressiveFileStream.cs index 9939734179..c570183514 100644 --- a/Jellyfin.Api/Helpers/ProgressiveFileStream.cs +++ b/Jellyfin.Api/Helpers/ProgressiveFileStream.cs @@ -51,13 +51,11 @@ namespace Jellyfin.Api.Helpers /// Initializes a new instance of the class. /// /// The stream to progressively copy. - /// The transcoding job information. - /// The transcoding job helper. /// The timeout duration in milliseconds. - public ProgressiveFileStream(Stream stream, TranscodingJobDto? job, TranscodingJobHelper? transcodingJobHelper, int timeoutMs = 30000) + public ProgressiveFileStream(Stream stream, int timeoutMs = 30000) { - _job = job; - _transcodingJobHelper = transcodingJobHelper; + _job = null; + _transcodingJobHelper = null; _timeoutMs = timeoutMs; _allowAsyncFileRead = AsyncFile.UseAsyncIO; _stream = stream; -- cgit v1.2.3 From 1a8dcae5e4024ba30aa2f3e998e0df87ea6f4f1b Mon Sep 17 00:00:00 2001 From: "Mr. Chip53" Date: Sun, 12 Sep 2021 13:30:53 -0500 Subject: Fix #6171 --- .../LiveTv/Listings/XmlTvListingsProvider.cs | 24 +++++++++++----------- 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'Emby.Server.Implementations/LiveTv') diff --git a/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs b/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs index 8202fab861..1c103f402a 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs @@ -59,34 +59,34 @@ namespace Emby.Server.Implementations.LiveTv.Listings return _config.Configuration.PreferredMetadataLanguage; } - private async Task GetXml(string path, CancellationToken cancellationToken) + private async Task GetXml(ListingsProviderInfo info, CancellationToken cancellationToken) { - _logger.LogInformation("xmltv path: {Path}", path); + _logger.LogInformation("xmltv path: {Path}", info.Path); - if (!path.StartsWith("http", StringComparison.OrdinalIgnoreCase)) + if (!info.Path.StartsWith("http", StringComparison.OrdinalIgnoreCase)) { - return UnzipIfNeeded(path, path); + return UnzipIfNeeded(info.Path, info.Path); } - string cacheFilename = DateTime.UtcNow.DayOfYear.ToString(CultureInfo.InvariantCulture) + "-" + DateTime.UtcNow.Hour.ToString(CultureInfo.InvariantCulture) + ".xml"; + string cacheFilename = DateTime.UtcNow.DayOfYear.ToString(CultureInfo.InvariantCulture) + "-" + DateTime.UtcNow.Hour.ToString(CultureInfo.InvariantCulture) + "-" + info.Id + ".xml"; string cacheFile = Path.Combine(_config.ApplicationPaths.CachePath, "xmltv", cacheFilename); if (File.Exists(cacheFile)) { - return UnzipIfNeeded(path, cacheFile); + return UnzipIfNeeded(info.Path, cacheFile); } - _logger.LogInformation("Downloading xmltv listings from {Path}", path); + _logger.LogInformation("Downloading xmltv listings from {Path}", info.Path); Directory.CreateDirectory(Path.GetDirectoryName(cacheFile)); - using var response = await _httpClientFactory.CreateClient(NamedClient.Default).GetAsync(path, cancellationToken).ConfigureAwait(false); + using var response = await _httpClientFactory.CreateClient(NamedClient.Default).GetAsync(info.Path, cancellationToken).ConfigureAwait(false); await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); await using (var fileStream = new FileStream(cacheFile, FileMode.CreateNew, FileAccess.Write, FileShare.None, IODefaults.CopyToBufferSize, AsyncFile.UseAsyncIO)) { await stream.CopyToAsync(fileStream, cancellationToken).ConfigureAwait(false); } - return UnzipIfNeeded(path, cacheFile); + return UnzipIfNeeded(info.Path, cacheFile); } private string UnzipIfNeeded(string originalUrl, string file) @@ -162,7 +162,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings _logger.LogDebug("Getting xmltv programs for channel {Id}", channelId); - string path = await GetXml(info.Path, cancellationToken).ConfigureAwait(false); + string path = await GetXml(info, cancellationToken).ConfigureAwait(false); _logger.LogDebug("Opening XmlTvReader for {Path}", path); var reader = new XmlTvReader(path, GetLanguage(info)); @@ -256,7 +256,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings public async Task> GetLineups(ListingsProviderInfo info, string country, string location) { // In theory this should never be called because there is always only one lineup - string path = await GetXml(info.Path, CancellationToken.None).ConfigureAwait(false); + string path = await GetXml(info, CancellationToken.None).ConfigureAwait(false); _logger.LogDebug("Opening XmlTvReader for {Path}", path); var reader = new XmlTvReader(path, GetLanguage(info)); IEnumerable results = reader.GetChannels(); @@ -268,7 +268,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings public async Task> GetChannels(ListingsProviderInfo info, CancellationToken cancellationToken) { // In theory this should never be called because there is always only one lineup - string path = await GetXml(info.Path, cancellationToken).ConfigureAwait(false); + string path = await GetXml(info, cancellationToken).ConfigureAwait(false); _logger.LogDebug("Opening XmlTvReader for {Path}", path); var reader = new XmlTvReader(path, GetLanguage(info)); var results = reader.GetChannels(); -- cgit v1.2.3 From 7a7fe3e681eca87cde631336c9af565fd6dfe0d7 Mon Sep 17 00:00:00 2001 From: Cody Robibero Date: Sun, 12 Sep 2021 13:56:26 -0600 Subject: Fix types and property names --- .../LiveTv/Listings/SchedulesDirectDtos/LineupsDto.cs | 2 +- .../LiveTv/Listings/SchedulesDirectDtos/MetadataScheduleDto.cs | 5 +++-- .../LiveTv/Listings/SchedulesDirectDtos/TokenDto.cs | 2 +- .../LiveTv/SchedulesDirect/SchedulesDirectDeserializeTests.cs | 6 +++--- 4 files changed, 8 insertions(+), 7 deletions(-) (limited to 'Emby.Server.Implementations/LiveTv') diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/LineupsDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/LineupsDto.cs index a635c59870..f190817813 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/LineupsDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/LineupsDto.cs @@ -25,7 +25,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the datetime. /// [JsonPropertyName("datetime")] - public DateTime? Datetime { get; set; } + public DateTime? LineupTimestamp { get; set; } /// /// Gets or sets the list of lineups. diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MetadataScheduleDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MetadataScheduleDto.cs index 68fbeec46d..04560ab55d 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MetadataScheduleDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MetadataScheduleDto.cs @@ -1,3 +1,4 @@ +using System; using System.Text.Json.Serialization; namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos @@ -23,13 +24,13 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the start date. /// [JsonPropertyName("startDate")] - public string? StartDate { get; set; } + public DateTime? StartDate { get; set; } /// /// Gets or sets the end date. /// [JsonPropertyName("endDate")] - public string? EndDate { get; set; } + public DateTime? EndDate { get; set; } /// /// Gets or sets the days count. diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/TokenDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/TokenDto.cs index 561f79c5af..afb9994869 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/TokenDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/TokenDto.cs @@ -36,7 +36,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the current datetime. /// [JsonPropertyName("datetime")] - public DateTime? DateTime { get; set; } + public DateTime? TokenTimestamp { get; set; } /// /// Gets or sets the response message. diff --git a/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/SchedulesDirectDeserializeTests.cs b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/SchedulesDirectDeserializeTests.cs index a494d883ec..3b3e38bd1f 100644 --- a/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/SchedulesDirectDeserializeTests.cs +++ b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/SchedulesDirectDeserializeTests.cs @@ -30,7 +30,7 @@ namespace Jellyfin.Server.Implementations.Tests.LiveTv.SchedulesDirect Assert.Equal(0, tokenDto!.Code); Assert.Equal("OK", tokenDto.Message); Assert.Equal("AWS-SD-web.1", tokenDto.ServerId); - Assert.Equal(new DateTime(2016, 08, 23, 13, 55, 25, DateTimeKind.Utc), tokenDto.DateTime); + Assert.Equal(new DateTime(2016, 08, 23, 13, 55, 25, DateTimeKind.Utc), tokenDto.TokenTimestamp); Assert.Equal("f3fca79989cafe7dead71beefedc812b", tokenDto.Token); } @@ -47,7 +47,7 @@ namespace Jellyfin.Server.Implementations.Tests.LiveTv.SchedulesDirect Assert.Equal(3_000, tokenDto!.Code); Assert.Equal("Server offline for maintenance.", tokenDto.Message); Assert.Equal("20141201.web.1", tokenDto.ServerId); - Assert.Equal(new DateTime(2015, 04, 23, 00, 03, 32, DateTimeKind.Utc), tokenDto.DateTime); + Assert.Equal(new DateTime(2015, 04, 23, 00, 03, 32, DateTimeKind.Utc), tokenDto.TokenTimestamp); Assert.Equal("CAFEDEADBEEFCAFEDEADBEEFCAFEDEADBEEFCAFE", tokenDto.Token); Assert.Equal("SERVICE_OFFLINE", tokenDto.Response); } @@ -207,7 +207,7 @@ namespace Jellyfin.Server.Implementations.Tests.LiveTv.SchedulesDirect Assert.NotNull(lineupsDto); Assert.Equal(0, lineupsDto!.Code); Assert.Equal("20141201.web.1", lineupsDto.ServerId); - Assert.Equal(new DateTime(2015, 04, 17, 14, 22, 17, DateTimeKind.Utc), lineupsDto.Datetime); + Assert.Equal(new DateTime(2015, 04, 17, 14, 22, 17, DateTimeKind.Utc), lineupsDto.LineupTimestamp); Assert.Equal(5, lineupsDto.Lineups.Count); Assert.Equal("GBR-0001317-DEFAULT", lineupsDto.Lineups[0].Lineup); Assert.Equal("Freeview - Carlton - LWT (Southeast)", lineupsDto.Lineups[0].Name); -- cgit v1.2.3 From a6d1e542e62548f177523f0acd67260f58066731 Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Sun, 19 Sep 2021 20:53:31 +0200 Subject: Reduce allocations --- Emby.Dlna/Eventing/DlnaEventManager.cs | 5 +- .../LiveTv/Listings/XmlTvListingsProvider.cs | 7 +-- .../LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs | 59 ++++++++++------------ .../LiveTv/TunerHosts/M3uParser.cs | 2 +- Jellyfin.Api/Controllers/RemoteImageController.cs | 3 +- Jellyfin.Api/Helpers/StreamingHelpers.cs | 3 +- MediaBrowser.Controller/MediaEncoding/JobLogger.cs | 4 +- .../Parsers/BaseItemXmlParser.cs | 3 +- .../Probing/ProbeResultNormalizer.cs | 2 +- MediaBrowser.MediaEncoding/Subtitles/VttWriter.cs | 4 +- MediaBrowser.Model/Net/MimeTypes.cs | 3 +- MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs | 3 +- src/Jellyfin.Extensions/StringExtensions.cs | 34 +++++++++++++ .../StringExtensionsTests.cs | 21 ++++++++ 14 files changed, 105 insertions(+), 48 deletions(-) (limited to 'Emby.Server.Implementations/LiveTv') diff --git a/Emby.Dlna/Eventing/DlnaEventManager.cs b/Emby.Dlna/Eventing/DlnaEventManager.cs index 3c91360904..b39bd5ce9b 100644 --- a/Emby.Dlna/Eventing/DlnaEventManager.cs +++ b/Emby.Dlna/Eventing/DlnaEventManager.cs @@ -11,6 +11,7 @@ using System.Net.Http; using System.Net.Mime; using System.Text; using System.Threading.Tasks; +using Jellyfin.Extensions; using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Net; using Microsoft.Extensions.Logging; @@ -82,9 +83,7 @@ namespace Emby.Dlna.Eventing if (!string.IsNullOrEmpty(header)) { // Starts with SECOND- - header = header.Split('-')[^1]; - - if (int.TryParse(header, NumberStyles.Integer, _usCulture, out var val)) + if (int.TryParse(header.AsSpan().RightPart('-'), NumberStyles.Integer, _usCulture, out var val)) { return val; } diff --git a/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs b/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs index 8202fab861..cb9801c178 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs @@ -10,6 +10,7 @@ using System.Linq; using System.Net.Http; using System.Threading; using System.Threading.Tasks; +using Jellyfin.Extensions; using Jellyfin.XmlTv; using Jellyfin.XmlTv.Entities; using MediaBrowser.Common.Extensions; @@ -89,11 +90,11 @@ namespace Emby.Server.Implementations.LiveTv.Listings return UnzipIfNeeded(path, cacheFile); } - private string UnzipIfNeeded(string originalUrl, string file) + private string UnzipIfNeeded(ReadOnlySpan originalUrl, string file) { - string ext = Path.GetExtension(originalUrl.Split('?')[0]); + ReadOnlySpan ext = Path.GetExtension(originalUrl.LeftPart('?')); - if (string.Equals(ext, ".gz", StringComparison.OrdinalIgnoreCase)) + if (ext.Equals(".gz", StringComparison.OrdinalIgnoreCase)) { try { diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs index 2bd12a9c8f..4d538c6043 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs @@ -36,7 +36,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun private readonly IHttpClientFactory _httpClientFactory; private readonly IServerApplicationHost _appHost; private readonly ISocketFactory _socketFactory; - private readonly INetworkManager _networkManager; private readonly IStreamHelper _streamHelper; private readonly JsonSerializerOptions _jsonOptions; @@ -50,7 +49,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun IHttpClientFactory httpClientFactory, IServerApplicationHost appHost, ISocketFactory socketFactory, - INetworkManager networkManager, IStreamHelper streamHelper, IMemoryCache memoryCache) : base(config, logger, fileSystem, memoryCache) @@ -58,7 +56,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun _httpClientFactory = httpClientFactory; _appHost = appHost; _socketFactory = socketFactory; - _networkManager = networkManager; _streamHelper = streamHelper; _jsonOptions = JsonDefaults.Options; @@ -70,7 +67,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun protected override string ChannelIdPrefix => "hdhr_"; - private string GetChannelId(TunerHostInfo info, Channels i) + private string GetChannelId(Channels i) => ChannelIdPrefix + i.GuideNumber; internal async Task> GetLineup(TunerHostInfo info, CancellationToken cancellationToken) @@ -103,7 +100,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun { Name = i.GuideName, Number = i.GuideNumber, - Id = GetChannelId(tuner, i), + Id = GetChannelId(i), IsFavorite = i.Favorite, TunerHostId = tuner.Id, IsHD = i.HD, @@ -255,7 +252,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun { var model = await GetModelInfo(info, false, cancellationToken).ConfigureAwait(false); - var tuners = new List(); + var tuners = new List(model.TunerCount); var uri = new Uri(GetApiUrl(info)); @@ -264,10 +261,10 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun // Legacy HdHomeruns are IPv4 only var ipInfo = IPAddress.Parse(uri.Host); - for (int i = 0; i < model.TunerCount; ++i) + for (int i = 0; i < model.TunerCount; i++) { var name = string.Format(CultureInfo.InvariantCulture, "Tuner {0}", i + 1); - var currentChannel = "none"; // @todo Get current channel and map back to Station Id + var currentChannel = "none"; // TODO: Get current channel and map back to Station Id var isAvailable = await manager.CheckTunerAvailability(ipInfo, i, cancellationToken).ConfigureAwait(false); var status = isAvailable ? LiveTvTunerStatus.Available : LiveTvTunerStatus.LiveTv; tuners.Add(new LiveTvTunerInfo @@ -455,28 +452,28 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun Path = url, Protocol = MediaProtocol.Udp, MediaStreams = new List - { - new MediaStream - { - Type = MediaStreamType.Video, - // Set the index to -1 because we don't know the exact index of the video stream within the container - Index = -1, - IsInterlaced = isInterlaced, - Codec = videoCodec, - Width = width, - Height = height, - BitRate = videoBitrate, - NalLengthSize = nal - }, - new MediaStream - { - Type = MediaStreamType.Audio, - // Set the index to -1 because we don't know the exact index of the audio stream within the container - Index = -1, - Codec = audioCodec, - BitRate = audioBitrate - } - }, + { + new MediaStream + { + Type = MediaStreamType.Video, + // Set the index to -1 because we don't know the exact index of the video stream within the container + Index = -1, + IsInterlaced = isInterlaced, + Codec = videoCodec, + Width = width, + Height = height, + BitRate = videoBitrate, + NalLengthSize = nal + }, + new MediaStream + { + Type = MediaStreamType.Audio, + // Set the index to -1 because we don't know the exact index of the audio stream within the container + Index = -1, + Codec = audioCodec, + BitRate = audioBitrate + } + }, RequiresOpening = true, RequiresClosing = true, BufferMs = 0, @@ -551,7 +548,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun } } - var profile = streamId.Split('_')[0]; + var profile = streamId.AsSpan().LeftPart('_').ToString(); Logger.LogInformation("GetChannelStream: channel id: {0}. stream id: {1} profile: {2}", channel.Id, streamId, profile); diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs index 23071a4306..506ef5548a 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs @@ -238,7 +238,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts { try { - numberString = Path.GetFileNameWithoutExtension(mediaUrl.Split('/')[^1]); + numberString = Path.GetFileNameWithoutExtension(mediaUrl.AsSpan().RightPart('/')).ToString(); if (!IsValidChannelNumber(numberString)) { diff --git a/Jellyfin.Api/Controllers/RemoteImageController.cs b/Jellyfin.Api/Controllers/RemoteImageController.cs index 7a2c23991b..bcb2b50c7a 100644 --- a/Jellyfin.Api/Controllers/RemoteImageController.cs +++ b/Jellyfin.Api/Controllers/RemoteImageController.cs @@ -7,6 +7,7 @@ using System.Net.Http; using System.Threading; using System.Threading.Tasks; using Jellyfin.Api.Constants; +using Jellyfin.Extensions; using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Net; using MediaBrowser.Controller; @@ -199,7 +200,7 @@ namespace Jellyfin.Api.Controllers throw new ResourceNotFoundException(nameof(response.Content.Headers.ContentType)); } - var ext = response.Content.Headers.ContentType.MediaType.Split('/')[^1]; + var ext = response.Content.Headers.ContentType.MediaType.AsSpan().RightPart('/').ToString(); var fullCachePath = GetFullCachePath(urlHash + "." + ext); var fullCacheDirectory = Path.GetDirectoryName(fullCachePath) ?? throw new ResourceNotFoundException($"Provided path ({fullCachePath}) is not valid."); diff --git a/Jellyfin.Api/Helpers/StreamingHelpers.cs b/Jellyfin.Api/Helpers/StreamingHelpers.cs index 0041251e3d..4fc791665e 100644 --- a/Jellyfin.Api/Helpers/StreamingHelpers.cs +++ b/Jellyfin.Api/Helpers/StreamingHelpers.cs @@ -6,6 +6,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using Jellyfin.Api.Models.StreamingDtos; +using Jellyfin.Extensions; using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Extensions; using MediaBrowser.Controller.Configuration; @@ -81,7 +82,7 @@ namespace Jellyfin.Api.Helpers throw new ResourceNotFoundException(nameof(httpRequest.Path)); } - var url = httpRequest.Path.Value.Split('.')[^1]; + var url = httpRequest.Path.Value.AsSpan().RightPart('.').ToString(); if (string.IsNullOrEmpty(streamingRequest.AudioCodec)) { diff --git a/MediaBrowser.Controller/MediaEncoding/JobLogger.cs b/MediaBrowser.Controller/MediaEncoding/JobLogger.cs index aa5e2c4038..c4ddc5618d 100644 --- a/MediaBrowser.Controller/MediaEncoding/JobLogger.cs +++ b/MediaBrowser.Controller/MediaEncoding/JobLogger.cs @@ -120,7 +120,7 @@ namespace MediaBrowser.Controller.MediaEncoding var size = part.Split('=', 2)[^1]; int? scale = null; - if (size.IndexOf("kb", StringComparison.OrdinalIgnoreCase) != -1) + if (size.Contains("kb", StringComparison.OrdinalIgnoreCase)) { scale = 1024; size = size.Replace("kb", string.Empty, StringComparison.OrdinalIgnoreCase); @@ -139,7 +139,7 @@ namespace MediaBrowser.Controller.MediaEncoding var rate = part.Split('=', 2)[^1]; int? scale = null; - if (rate.IndexOf("kbits/s", StringComparison.OrdinalIgnoreCase) != -1) + if (rate.Contains("kbits/s", StringComparison.OrdinalIgnoreCase)) { scale = 1024; rate = rate.Replace("kbits/s", string.Empty, StringComparison.OrdinalIgnoreCase); diff --git a/MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs b/MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs index ef130ee747..9103bf6476 100644 --- a/MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs +++ b/MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs @@ -6,6 +6,7 @@ using System.Linq; using System.Text; using System.Threading; using System.Xml; +using Jellyfin.Extensions; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; @@ -331,7 +332,7 @@ namespace MediaBrowser.LocalMetadata.Parsers if (!string.IsNullOrWhiteSpace(text)) { - if (int.TryParse(text.Split(' ')[0], NumberStyles.Integer, _usCulture, out var runtime)) + if (int.TryParse(text.AsSpan().LeftPart(' '), NumberStyles.Integer, _usCulture, out var runtime)) { item.RunTimeTicks = TimeSpan.FromMinutes(runtime).Ticks; } diff --git a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs index 2516aad1cc..c377f1720d 100644 --- a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs +++ b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs @@ -1378,7 +1378,7 @@ namespace MediaBrowser.MediaEncoding.Probing { var disc = tags.GetValueOrDefault(tagName); - if (!string.IsNullOrEmpty(disc) && int.TryParse(disc.Split('/')[0], out var discNum)) + if (!string.IsNullOrEmpty(disc) && int.TryParse(disc.AsSpan().LeftPart('/'), out var discNum)) { return discNum; } diff --git a/MediaBrowser.MediaEncoding/Subtitles/VttWriter.cs b/MediaBrowser.MediaEncoding/Subtitles/VttWriter.cs index ad32cb7943..6d56dda91f 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/VttWriter.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/VttWriter.cs @@ -18,14 +18,14 @@ namespace MediaBrowser.MediaEncoding.Subtitles using (var writer = new StreamWriter(stream, Encoding.UTF8, 1024, true)) { writer.WriteLine("WEBVTT"); - writer.WriteLine(string.Empty); + writer.WriteLine(); writer.WriteLine("REGION"); writer.WriteLine("id:subtitle"); writer.WriteLine("width:80%"); writer.WriteLine("lines:3"); writer.WriteLine("regionanchor:50%,100%"); writer.WriteLine("viewportanchor:50%,90%"); - writer.WriteLine(string.Empty); + writer.WriteLine(); foreach (var trackEvent in info.TrackEvents) { cancellationToken.ThrowIfCancellationRequested(); diff --git a/MediaBrowser.Model/Net/MimeTypes.cs b/MediaBrowser.Model/Net/MimeTypes.cs index 96f5ab51ae..7b3c17c85a 100644 --- a/MediaBrowser.Model/Net/MimeTypes.cs +++ b/MediaBrowser.Model/Net/MimeTypes.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; +using Jellyfin.Extensions; namespace MediaBrowser.Model.Net { @@ -221,7 +222,7 @@ namespace MediaBrowser.Model.Net } // handle text/html; charset=UTF-8 - mimeType = mimeType.Split(';')[0]; + mimeType = mimeType.AsSpan().LeftPart(';').ToString(); if (_extensionLookup.TryGetValue(mimeType, out string? result)) { diff --git a/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs b/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs index f975278fbc..b3efb8634f 100644 --- a/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs +++ b/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs @@ -8,6 +8,7 @@ using System.Linq; using System.Text; using System.Threading; using System.Xml; +using Jellyfin.Extensions; using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Providers; using MediaBrowser.Controller.Entities; @@ -474,7 +475,7 @@ namespace MediaBrowser.XbmcMetadata.Parsers if (!string.IsNullOrWhiteSpace(text)) { - if (int.TryParse(text.Split(' ')[0], NumberStyles.Integer, UsCulture, out var runtime)) + if (int.TryParse(text.AsSpan().LeftPart(' '), NumberStyles.Integer, UsCulture, out var runtime)) { item.RunTimeTicks = TimeSpan.FromMinutes(runtime).Ticks; } diff --git a/src/Jellyfin.Extensions/StringExtensions.cs b/src/Jellyfin.Extensions/StringExtensions.cs index acc695ed2f..3a77072539 100644 --- a/src/Jellyfin.Extensions/StringExtensions.cs +++ b/src/Jellyfin.Extensions/StringExtensions.cs @@ -27,5 +27,39 @@ namespace Jellyfin.Extensions return count; } + + /// + /// Returns the part on the left of the needle. + /// + /// The string to seek. + /// The needle to find. + /// The part left of the . + public static ReadOnlySpan LeftPart(this ReadOnlySpan haystack, char needle) + { + var pos = haystack.IndexOf(needle); + return pos == -1 ? haystack : haystack[..pos]; + } + + /// + /// Returns the part on the right of the needle. + /// + /// The string to seek. + /// The needle to find. + /// The part right of the . + public static ReadOnlySpan RightPart(this ReadOnlySpan haystack, char needle) + { + var pos = haystack.LastIndexOf(needle); + if (pos == -1) + { + return haystack; + } + + if (pos == haystack.Length - 1) + { + return ReadOnlySpan.Empty; + } + + return haystack[(pos + 1)..]; + } } } diff --git a/tests/Jellyfin.Extensions.Tests/StringExtensionsTests.cs b/tests/Jellyfin.Extensions.Tests/StringExtensionsTests.cs index d1aa2e4764..17671d13b0 100644 --- a/tests/Jellyfin.Extensions.Tests/StringExtensionsTests.cs +++ b/tests/Jellyfin.Extensions.Tests/StringExtensionsTests.cs @@ -14,5 +14,26 @@ namespace Jellyfin.Extensions.Tests { Assert.Equal(count, str.AsSpan().Count(needle)); } + + [Theory] + [InlineData("", 'q', "")] + [InlineData("Banana split", ' ', "Banana")] + [InlineData("Banana split", 'q', "Banana split")] + public void LeftPart_ValidArgsCharNeedle_Correct(string str, char needle, string expectedResult) + { + var result = str.AsSpan().LeftPart(needle).ToString(); + Assert.Equal(expectedResult, result); + } + + [Theory] + [InlineData("", 'q', "")] + [InlineData("Banana split", ' ', "split")] + [InlineData("Banana split", 'q', "Banana split")] + [InlineData("Banana split.", '.', "")] + public void RightPart_ValidArgsCharNeedle_Correct(string str, char needle, string expectedResult) + { + var result = str.AsSpan().RightPart(needle).ToString(); + Assert.Equal(expectedResult, result); + } } } -- cgit v1.2.3 From 653df7d8e5b3474010b3797d7f15d51225932ca7 Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Tue, 21 Sep 2021 01:21:45 +0200 Subject: Specify DateTimeStyles when possible --- Emby.Server.Implementations/Data/SqliteExtensions.cs | 6 +++--- Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs | 2 +- Jellyfin.Api/Controllers/TimeSyncController.cs | 4 ++-- Jellyfin.Api/Controllers/TvShowsController.cs | 2 +- MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs | 12 ++++++------ MediaBrowser.MediaEncoding/Probing/FFProbeHelpers.cs | 6 +++--- .../Probing/ProbeResultNormalizer.cs | 6 +++--- MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs | 16 ++++++++-------- .../Probing/ProbeResultNormalizerTests.cs | 6 +++--- 9 files changed, 30 insertions(+), 30 deletions(-) (limited to 'Emby.Server.Implementations/LiveTv') diff --git a/Emby.Server.Implementations/Data/SqliteExtensions.cs b/Emby.Server.Implementations/Data/SqliteExtensions.cs index 3289e76098..381eb92a88 100644 --- a/Emby.Server.Implementations/Data/SqliteExtensions.cs +++ b/Emby.Server.Implementations/Data/SqliteExtensions.cs @@ -94,7 +94,7 @@ namespace Emby.Server.Implementations.Data dateText, _datetimeFormats, DateTimeFormatInfo.InvariantInfo, - DateTimeStyles.None).ToUniversalTime(); + DateTimeStyles.AdjustToUniversal); } public static bool TryReadDateTime(this IReadOnlyList reader, int index, out DateTime result) @@ -108,9 +108,9 @@ namespace Emby.Server.Implementations.Data var dateText = item.ToString(); - if (DateTime.TryParseExact(dateText, _datetimeFormats, DateTimeFormatInfo.InvariantInfo, DateTimeStyles.None, out var dateTimeResult)) + if (DateTime.TryParseExact(dateText, _datetimeFormats, DateTimeFormatInfo.InvariantInfo, DateTimeStyles.AdjustToUniversal, out var dateTimeResult)) { - result = dateTimeResult.ToUniversalTime(); + result = dateTimeResult; return true; } diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index 026b6bc0bb..64e54aa99e 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -1990,7 +1990,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV writer.WriteElementString( "dateadded", - DateTime.UtcNow.ToLocalTime().ToString(DateAddedFormat, CultureInfo.InvariantCulture)); + DateTime.Now.ToString(DateAddedFormat, CultureInfo.InvariantCulture)); if (item.ProductionYear.HasValue) { diff --git a/Jellyfin.Api/Controllers/TimeSyncController.cs b/Jellyfin.Api/Controllers/TimeSyncController.cs index 7df51c7afb..e7c5a71257 100644 --- a/Jellyfin.Api/Controllers/TimeSyncController.cs +++ b/Jellyfin.Api/Controllers/TimeSyncController.cs @@ -21,10 +21,10 @@ namespace Jellyfin.Api.Controllers public ActionResult GetUtcTime() { // Important to keep the following line at the beginning - var requestReceptionTime = DateTime.UtcNow.ToUniversalTime(); + var requestReceptionTime = DateTime.UtcNow; // Important to keep the following line at the end - var responseTransmissionTime = DateTime.UtcNow.ToUniversalTime(); + var responseTransmissionTime = DateTime.UtcNow; // Implementing NTP on such a high level results in this useless // information being sent. On the other hand it enables future additions. diff --git a/Jellyfin.Api/Controllers/TvShowsController.cs b/Jellyfin.Api/Controllers/TvShowsController.cs index 7c5b8a43b7..6eada67cf0 100644 --- a/Jellyfin.Api/Controllers/TvShowsController.cs +++ b/Jellyfin.Api/Controllers/TvShowsController.cs @@ -147,7 +147,7 @@ namespace Jellyfin.Api.Controllers ? _userManager.GetUserById(userId.Value) : null; - var minPremiereDate = DateTime.Now.Date.ToUniversalTime().AddDays(-1); + var minPremiereDate = DateTime.UtcNow.Date.AddDays(-1); var parentIdGuid = parentId ?? Guid.Empty; diff --git a/MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs b/MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs index 9103bf6476..7c9e681d6a 100644 --- a/MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs +++ b/MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs @@ -145,9 +145,9 @@ namespace MediaBrowser.LocalMetadata.Parsers if (!string.IsNullOrWhiteSpace(val)) { - if (DateTime.TryParse(val, out var added)) + if (DateTime.TryParse(val, CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal, out var added)) { - item.DateCreated = added.ToUniversalTime(); + item.DateCreated = added; } else { @@ -535,9 +535,9 @@ namespace MediaBrowser.LocalMetadata.Parsers if (!string.IsNullOrWhiteSpace(firstAired)) { - if (DateTime.TryParseExact(firstAired, "yyyy-MM-dd", CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal, out var airDate) && airDate.Year > 1850) + if (DateTime.TryParseExact(firstAired, "yyyy-MM-dd", CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal | DateTimeStyles.AdjustToUniversal, out var airDate) && airDate.Year > 1850) { - item.PremiereDate = airDate.ToUniversalTime(); + item.PremiereDate = airDate; item.ProductionYear = airDate.Year; } } @@ -552,9 +552,9 @@ namespace MediaBrowser.LocalMetadata.Parsers if (!string.IsNullOrWhiteSpace(firstAired)) { - if (DateTime.TryParseExact(firstAired, "yyyy-MM-dd", CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal, out var airDate) && airDate.Year > 1850) + if (DateTime.TryParseExact(firstAired, "yyyy-MM-dd", CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal | DateTimeStyles.AdjustToUniversal, out var airDate) && airDate.Year > 1850) { - item.EndDate = airDate.ToUniversalTime(); + item.EndDate = airDate; } } diff --git a/MediaBrowser.MediaEncoding/Probing/FFProbeHelpers.cs b/MediaBrowser.MediaEncoding/Probing/FFProbeHelpers.cs index 9196fe1397..a9e753726d 100644 --- a/MediaBrowser.MediaEncoding/Probing/FFProbeHelpers.cs +++ b/MediaBrowser.MediaEncoding/Probing/FFProbeHelpers.cs @@ -63,10 +63,10 @@ namespace MediaBrowser.MediaEncoding.Probing public static DateTime? GetDictionaryDateTime(IReadOnlyDictionary tags, string key) { if (tags.TryGetValue(key, out var val) - && (DateTime.TryParse(val, DateTimeFormatInfo.CurrentInfo, DateTimeStyles.AssumeUniversal, out var dateTime) - || DateTime.TryParseExact(val, "yyyy", DateTimeFormatInfo.CurrentInfo, DateTimeStyles.AssumeUniversal, out dateTime))) + && (DateTime.TryParse(val, DateTimeFormatInfo.CurrentInfo, DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal, out var dateTime) + || DateTime.TryParseExact(val, "yyyy", DateTimeFormatInfo.CurrentInfo, DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal, out dateTime))) { - return dateTime.ToUniversalTime(); + return dateTime; } return null; diff --git a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs index c377f1720d..26f629a315 100644 --- a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs +++ b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs @@ -1450,9 +1450,9 @@ namespace MediaBrowser.MediaEncoding.Probing // Credit to MCEBuddy: https://mcebuddy2x.codeplex.com/ // DateTime is reported along with timezone info (typically Z i.e. UTC hence assume None) - if (tags.TryGetValue("WM/MediaOriginalBroadcastDateTime", out var premiereDateString) && DateTime.TryParse(year, null, DateTimeStyles.None, out var parsedDate)) + if (tags.TryGetValue("WM/MediaOriginalBroadcastDateTime", out var premiereDateString) && DateTime.TryParse(year, null, DateTimeStyles.AdjustToUniversal, out var parsedDate)) { - video.PremiereDate = parsedDate.ToUniversalTime(); + video.PremiereDate = parsedDate; } var description = tags.GetValueOrDefault("WM/SubTitleDescription"); @@ -1468,7 +1468,7 @@ namespace MediaBrowser.MediaEncoding.Probing // e.g. -> CBeebies Bedtime Hour. The Mystery: Animated adventures of two friends who live on an island in the middle of the big city. Some of Abney and Teal's favourite objects are missing. [S] if (string.IsNullOrWhiteSpace(subTitle) && !string.IsNullOrWhiteSpace(description) - && description.AsSpan()[0..Math.Min(description.Length, MaxSubtitleDescriptionExtractionLength)].IndexOf(':') != -1) // Check within the Subtitle size limit, otherwise from description it can get too long creating an invalid filename + && description.AsSpan()[..Math.Min(description.Length, MaxSubtitleDescriptionExtractionLength)].Contains(':')) // Check within the Subtitle size limit, otherwise from description it can get too long creating an invalid filename { string[] descriptionParts = description.Split(':'); if (descriptionParts.Length > 0) diff --git a/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs b/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs index b3efb8634f..f7f4ea0652 100644 --- a/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs +++ b/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs @@ -268,9 +268,9 @@ namespace MediaBrowser.XbmcMetadata.Parsers if (!string.IsNullOrWhiteSpace(val)) { - if (DateTime.TryParse(val, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal, out var added)) + if (DateTime.TryParse(val, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal, out var added)) { - item.DateCreated = added.ToUniversalTime(); + item.DateCreated = added; } else { @@ -384,9 +384,9 @@ namespace MediaBrowser.XbmcMetadata.Parsers var val = reader.ReadElementContentAsString(); if (!string.IsNullOrWhiteSpace(val) && userData != null) { - if (DateTime.TryParse(val, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal, out var added)) + if (DateTime.TryParse(val, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal, out var added)) { - userData.LastPlayedDate = added.ToUniversalTime(); + userData.LastPlayedDate = added; } else { @@ -685,9 +685,9 @@ namespace MediaBrowser.XbmcMetadata.Parsers if (!string.IsNullOrWhiteSpace(val)) { - if (DateTime.TryParseExact(val, formatString, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal, out var date) && date.Year > 1850) + if (DateTime.TryParseExact(val, formatString, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal, out var date) && date.Year > 1850) { - item.PremiereDate = date.ToUniversalTime(); + item.PremiereDate = date; item.ProductionYear = date.Year; } } @@ -703,9 +703,9 @@ namespace MediaBrowser.XbmcMetadata.Parsers if (!string.IsNullOrWhiteSpace(val)) { - if (DateTime.TryParseExact(val, formatString, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal, out var date) && date.Year > 1850) + if (DateTime.TryParseExact(val, formatString, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal, out var date) && date.Year > 1850) { - item.EndDate = date.ToUniversalTime(); + item.EndDate = date; } } diff --git a/tests/Jellyfin.MediaEncoding.Tests/Probing/ProbeResultNormalizerTests.cs b/tests/Jellyfin.MediaEncoding.Tests/Probing/ProbeResultNormalizerTests.cs index d002d5a347..d0d472e4d4 100644 --- a/tests/Jellyfin.MediaEncoding.Tests/Probing/ProbeResultNormalizerTests.cs +++ b/tests/Jellyfin.MediaEncoding.Tests/Probing/ProbeResultNormalizerTests.cs @@ -69,7 +69,7 @@ namespace Jellyfin.MediaEncoding.Tests.Probing Assert.Equal("Album", res.Album); Assert.Equal(2021, res.ProductionYear); Assert.True(res.PremiereDate.HasValue); - Assert.Equal(DateTime.Parse("2021-01-01T00:00Z", DateTimeFormatInfo.CurrentInfo).ToUniversalTime(), res.PremiereDate); + Assert.Equal(DateTime.Parse("2021-01-01T00:00Z", DateTimeFormatInfo.CurrentInfo, DateTimeStyles.AdjustToUniversal), res.PremiereDate); } [Fact] @@ -85,7 +85,7 @@ namespace Jellyfin.MediaEncoding.Tests.Probing Assert.Equal("City to City", res.Album); Assert.Equal(1978, res.ProductionYear); Assert.True(res.PremiereDate.HasValue); - Assert.Equal(DateTime.Parse("1978-01-01T00:00Z", DateTimeFormatInfo.CurrentInfo).ToUniversalTime(), res.PremiereDate); + Assert.Equal(DateTime.Parse("1978-01-01T00:00Z", DateTimeFormatInfo.CurrentInfo, DateTimeStyles.AdjustToUniversal), res.PremiereDate); Assert.Contains("Electronic", res.Genres); Assert.Contains("Ambient", res.Genres); Assert.Contains("Pop", res.Genres); @@ -105,7 +105,7 @@ namespace Jellyfin.MediaEncoding.Tests.Probing Assert.Equal("Eyes wide open", res.Album); Assert.Equal(2020, res.ProductionYear); Assert.True(res.PremiereDate.HasValue); - Assert.Equal(DateTime.Parse("2020-10-26T00:00Z", DateTimeFormatInfo.CurrentInfo).ToUniversalTime(), res.PremiereDate); + Assert.Equal(DateTime.Parse("2020-10-26T00:00Z", DateTimeFormatInfo.CurrentInfo, DateTimeStyles.AdjustToUniversal), res.PremiereDate); Assert.Equal(22, res.People.Length); Assert.Equal("Krysta Youngs", res.People[0].Name); Assert.Equal(PersonType.Composer, res.People[0].Type); -- cgit v1.2.3 From f6622bd810fac793829df27f8caf575943b807c5 Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Tue, 21 Sep 2021 13:22:40 +0200 Subject: Fix issue #6587 --- Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Emby.Server.Implementations/LiveTv') diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs index d806a02959..a943efcc70 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs @@ -188,7 +188,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV CultureInfo.InvariantCulture, "-i \"{0}\" {2} -map_metadata -1 -threads {6} {3}{4}{5} -y \"{1}\"", inputTempFile, - targetFile, + targetFile.Replace("\"", "\\\""), // Escape quotes in filename videoArgs, GetAudioArgs(mediaSource), subtitleArgs, -- cgit v1.2.3 From 13fbfe6091e61450aedc07bc78c96bf4c414bc65 Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Sun, 14 Feb 2021 15:11:46 +0100 Subject: Target net6.0 --- DvdLib/DvdLib.csproj | 2 +- DvdLib/Ifo/Dvd.cs | 3 ++- Emby.Dlna/DlnaManager.cs | 2 +- Emby.Dlna/Emby.Dlna.csproj | 2 +- Emby.Dlna/Server/DescriptionXmlBuilder.cs | 3 +-- Emby.Dlna/Service/BaseService.cs | 8 ++++---- Emby.Drawing/Emby.Drawing.csproj | 2 +- Emby.Naming/Emby.Naming.csproj | 2 +- Emby.Notifications/Emby.Notifications.csproj | 2 +- Emby.Photos/Emby.Photos.csproj | 2 +- .../Emby.Server.Implementations.csproj | 2 +- .../LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs | 2 +- .../FirstTimeSetupOrDefaultHandler.cs | 6 +++--- .../FirstTimeSetupOrElevatedHandler.cs | 6 +++--- Jellyfin.Api/Controllers/ImageController.cs | 10 +++++----- Jellyfin.Api/Helpers/FileStreamResponseHelpers.cs | 3 ++- Jellyfin.Api/Jellyfin.Api.csproj | 2 +- Jellyfin.Api/ModelBinders/NullableEnumModelBinder.cs | 5 +++-- Jellyfin.Data/Jellyfin.Data.csproj | 2 +- Jellyfin.Drawing.Skia/Jellyfin.Drawing.Skia.csproj | 7 +------ Jellyfin.Networking/Jellyfin.Networking.csproj | 2 +- .../Jellyfin.Server.Implementations.csproj | 2 +- Jellyfin.Server/Configuration/CorsPolicyProvider.cs | 4 ++-- .../SymlinkFollowingPhysicalFileResultExecutor.cs | 2 +- Jellyfin.Server/Jellyfin.Server.csproj | 2 +- .../Middleware/QueryStringDecodingMiddleware.cs | 6 +++++- MediaBrowser.Common/MediaBrowser.Common.csproj | 2 +- MediaBrowser.Controller/Dlna/IDlnaManager.cs | 2 +- MediaBrowser.Controller/Drawing/IImageProcessor.cs | 2 +- MediaBrowser.Controller/MediaBrowser.Controller.csproj | 2 +- MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs | 7 ++++++- .../MediaBrowser.LocalMetadata.csproj | 2 +- .../MediaBrowser.MediaEncoding.csproj | 2 +- .../Subtitles/SubtitleEditParser.cs | 2 +- MediaBrowser.Model/MediaBrowser.Model.csproj | 2 +- MediaBrowser.Model/Net/MimeTypes.cs | 12 +++++++----- MediaBrowser.Providers/MediaBrowser.Providers.csproj | 2 +- .../Plugins/Omdb/JsonOmdbNotAvailableInt32Converter.cs | 2 +- .../MediaBrowser.XbmcMetadata.csproj | 2 +- RSSDP/DisposableManagedObjectBase.cs | 5 +++-- RSSDP/RSSDP.csproj | 2 +- RSSDP/SsdpDevice.cs | 13 ++++++++----- RSSDP/SsdpDevicePublisher.cs | 15 ++++++++------- tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj | 2 +- tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj | 2 +- .../Jellyfin.Controller.Tests.csproj | 2 +- tests/Jellyfin.Dlna.Tests/Jellyfin.Dlna.Tests.csproj | 2 +- .../Jellyfin.Extensions.Tests.csproj | 2 +- .../Jellyfin.MediaEncoding.Tests.csproj | 2 +- tests/Jellyfin.Model.Tests/Jellyfin.Model.Tests.csproj | 2 +- tests/Jellyfin.Naming.Tests/Jellyfin.Naming.Tests.csproj | 2 +- .../Jellyfin.Networking.Tests.csproj | 2 +- .../Jellyfin.Server.Implementations.Tests.csproj | 2 +- .../Jellyfin.Server.Integration.Tests.csproj | 2 +- tests/Jellyfin.Server.Tests/Jellyfin.Server.Tests.csproj | 2 +- .../Jellyfin.XbmcMetadata.Tests.csproj | 2 +- 56 files changed, 103 insertions(+), 90 deletions(-) (limited to 'Emby.Server.Implementations/LiveTv') diff --git a/DvdLib/DvdLib.csproj b/DvdLib/DvdLib.csproj index b8301e2f27..755d29160c 100644 --- a/DvdLib/DvdLib.csproj +++ b/DvdLib/DvdLib.csproj @@ -10,7 +10,7 @@ - net5.0 + net6.0 false true AllDisabledByDefault diff --git a/DvdLib/Ifo/Dvd.cs b/DvdLib/Ifo/Dvd.cs index b4a11ed5d6..7f8ece47dc 100644 --- a/DvdLib/Ifo/Dvd.cs +++ b/DvdLib/Ifo/Dvd.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.IO; using System.Linq; @@ -76,7 +77,7 @@ namespace DvdLib.Ifo private void ReadVTS(ushort vtsNum, IReadOnlyList allFiles) { - var filename = string.Format("VTS_{0:00}_0.IFO", vtsNum); + var filename = string.Format(CultureInfo.InvariantCulture, "VTS_{0:00}_0.IFO", vtsNum); var vtsPath = allFiles.FirstOrDefault(i => string.Equals(i.Name, filename, StringComparison.OrdinalIgnoreCase)) ?? allFiles.FirstOrDefault(i => string.Equals(i.Name, Path.ChangeExtension(filename, ".bup"), StringComparison.OrdinalIgnoreCase)); diff --git a/Emby.Dlna/DlnaManager.cs b/Emby.Dlna/DlnaManager.cs index 68fc80c0a0..3855504324 100644 --- a/Emby.Dlna/DlnaManager.cs +++ b/Emby.Dlna/DlnaManager.cs @@ -486,7 +486,7 @@ namespace Emby.Dlna } /// - public ImageStream GetIcon(string filename) + public ImageStream? GetIcon(string filename) { var format = filename.EndsWith(".png", StringComparison.OrdinalIgnoreCase) ? ImageFormat.Png diff --git a/Emby.Dlna/Emby.Dlna.csproj b/Emby.Dlna/Emby.Dlna.csproj index 970c16d2e6..1d4e3b047d 100644 --- a/Emby.Dlna/Emby.Dlna.csproj +++ b/Emby.Dlna/Emby.Dlna.csproj @@ -17,7 +17,7 @@ - net5.0 + net6.0 false true AllDisabledByDefault diff --git a/Emby.Dlna/Server/DescriptionXmlBuilder.cs b/Emby.Dlna/Server/DescriptionXmlBuilder.cs index 3f3dfccd3a..09525aae4e 100644 --- a/Emby.Dlna/Server/DescriptionXmlBuilder.cs +++ b/Emby.Dlna/Server/DescriptionXmlBuilder.cs @@ -250,8 +250,7 @@ namespace Emby.Dlna.Server url = _serverAddress.TrimEnd('/') + "/dlna/" + _serverUdn + "/" + url.TrimStart('/'); - // TODO: @bond remove null-coalescing operator when https://github.com/dotnet/runtime/pull/52442 is merged/released - return SecurityElement.Escape(url) ?? string.Empty; + return SecurityElement.Escape(url); } private IEnumerable GetIcons() diff --git a/Emby.Dlna/Service/BaseService.cs b/Emby.Dlna/Service/BaseService.cs index a97c4d63a6..68fd987585 100644 --- a/Emby.Dlna/Service/BaseService.cs +++ b/Emby.Dlna/Service/BaseService.cs @@ -23,14 +23,14 @@ namespace Emby.Dlna.Service return EventManager.CancelEventSubscription(subscriptionId); } - public EventSubscriptionResponse RenewEventSubscription(string subscriptionId, string notificationType, string timeoutString, string callbackUrl) + public EventSubscriptionResponse RenewEventSubscription(string subscriptionId, string notificationType, string requestedTimeoutString, string callbackUrl) { - return EventManager.RenewEventSubscription(subscriptionId, notificationType, timeoutString, callbackUrl); + return EventManager.RenewEventSubscription(subscriptionId, notificationType, requestedTimeoutString, callbackUrl); } - public EventSubscriptionResponse CreateEventSubscription(string notificationType, string timeoutString, string callbackUrl) + public EventSubscriptionResponse CreateEventSubscription(string notificationType, string requestedTimeoutString, string callbackUrl) { - return EventManager.CreateEventSubscription(notificationType, timeoutString, callbackUrl); + return EventManager.CreateEventSubscription(notificationType, requestedTimeoutString, callbackUrl); } } } diff --git a/Emby.Drawing/Emby.Drawing.csproj b/Emby.Drawing/Emby.Drawing.csproj index baf350c6f1..300eea9680 100644 --- a/Emby.Drawing/Emby.Drawing.csproj +++ b/Emby.Drawing/Emby.Drawing.csproj @@ -6,7 +6,7 @@ - net5.0 + net6.0 false true AllDisabledByDefault diff --git a/Emby.Naming/Emby.Naming.csproj b/Emby.Naming/Emby.Naming.csproj index 07d879e96a..96f8f389b3 100644 --- a/Emby.Naming/Emby.Naming.csproj +++ b/Emby.Naming/Emby.Naming.csproj @@ -6,7 +6,7 @@ - net5.0 + net6.0 false true true diff --git a/Emby.Notifications/Emby.Notifications.csproj b/Emby.Notifications/Emby.Notifications.csproj index 5edcf2f295..d200682e65 100644 --- a/Emby.Notifications/Emby.Notifications.csproj +++ b/Emby.Notifications/Emby.Notifications.csproj @@ -6,7 +6,7 @@ - net5.0 + net6.0 false true diff --git a/Emby.Photos/Emby.Photos.csproj b/Emby.Photos/Emby.Photos.csproj index 00b2f0f94c..bf6252c195 100644 --- a/Emby.Photos/Emby.Photos.csproj +++ b/Emby.Photos/Emby.Photos.csproj @@ -19,7 +19,7 @@ - net5.0 + net6.0 false true diff --git a/Emby.Server.Implementations/Emby.Server.Implementations.csproj b/Emby.Server.Implementations/Emby.Server.Implementations.csproj index 769972d8c4..0e1386ef55 100644 --- a/Emby.Server.Implementations/Emby.Server.Implementations.csproj +++ b/Emby.Server.Implementations/Emby.Server.Implementations.csproj @@ -42,7 +42,7 @@ - net5.0 + net6.0 false true diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs index a8f761fdeb..6a2e7f6998 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs @@ -196,7 +196,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun cancellationToken, timeOutSource.Token)) { - var resTask = udpClient.ReceiveAsync(); + var resTask = udpClient.ReceiveAsync(linkedSource.Token).AsTask(); if (await Task.WhenAny(resTask, Task.Delay(30000, linkedSource.Token)).ConfigureAwait(false) != resTask) { resTask.Dispose(); diff --git a/Jellyfin.Api/Auth/FirstTimeSetupOrDefaultPolicy/FirstTimeSetupOrDefaultHandler.cs b/Jellyfin.Api/Auth/FirstTimeSetupOrDefaultPolicy/FirstTimeSetupOrDefaultHandler.cs index 9815e252ee..dd0bd4ec2f 100644 --- a/Jellyfin.Api/Auth/FirstTimeSetupOrDefaultPolicy/FirstTimeSetupOrDefaultHandler.cs +++ b/Jellyfin.Api/Auth/FirstTimeSetupOrDefaultPolicy/FirstTimeSetupOrDefaultHandler.cs @@ -32,18 +32,18 @@ namespace Jellyfin.Api.Auth.FirstTimeSetupOrDefaultPolicy } /// - protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, FirstTimeSetupOrDefaultRequirement firstTimeSetupOrDefaultRequirement) + protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, FirstTimeSetupOrDefaultRequirement requirement) { if (!_configurationManager.CommonConfiguration.IsStartupWizardCompleted) { - context.Succeed(firstTimeSetupOrDefaultRequirement); + context.Succeed(requirement); return Task.CompletedTask; } var validated = ValidateClaims(context.User); if (validated) { - context.Succeed(firstTimeSetupOrDefaultRequirement); + context.Succeed(requirement); } else { diff --git a/Jellyfin.Api/Auth/FirstTimeSetupOrElevatedPolicy/FirstTimeSetupOrElevatedHandler.cs b/Jellyfin.Api/Auth/FirstTimeSetupOrElevatedPolicy/FirstTimeSetupOrElevatedHandler.cs index decbe0c035..90b76ee99a 100644 --- a/Jellyfin.Api/Auth/FirstTimeSetupOrElevatedPolicy/FirstTimeSetupOrElevatedHandler.cs +++ b/Jellyfin.Api/Auth/FirstTimeSetupOrElevatedPolicy/FirstTimeSetupOrElevatedHandler.cs @@ -33,18 +33,18 @@ namespace Jellyfin.Api.Auth.FirstTimeSetupOrElevatedPolicy } /// - protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, FirstTimeSetupOrElevatedRequirement firstTimeSetupOrElevatedRequirement) + protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, FirstTimeSetupOrElevatedRequirement requirement) { if (!_configurationManager.CommonConfiguration.IsStartupWizardCompleted) { - context.Succeed(firstTimeSetupOrElevatedRequirement); + context.Succeed(requirement); return Task.CompletedTask; } var validated = ValidateClaims(context.User); if (validated && context.User.IsInRole(UserRoles.Administrator)) { - context.Succeed(firstTimeSetupOrElevatedRequirement); + context.Succeed(requirement); } else { diff --git a/Jellyfin.Api/Controllers/ImageController.cs b/Jellyfin.Api/Controllers/ImageController.cs index 9dc280e138..b1c860d61f 100644 --- a/Jellyfin.Api/Controllers/ImageController.cs +++ b/Jellyfin.Api/Controllers/ImageController.cs @@ -106,7 +106,7 @@ namespace Jellyfin.Api.Controllers await using var memoryStream = await GetMemoryStream(Request.Body).ConfigureAwait(false); // Handle image/png; charset=utf-8 - var mimeType = Request.ContentType.Split(';').FirstOrDefault(); + var mimeType = Request.ContentType?.Split(';').FirstOrDefault(); var userDataPath = Path.Combine(_serverConfigurationManager.ApplicationPaths.UserConfigurationDirectoryPath, user.Username); if (user.ProfileImage != null) { @@ -153,7 +153,7 @@ namespace Jellyfin.Api.Controllers await using var memoryStream = await GetMemoryStream(Request.Body).ConfigureAwait(false); // Handle image/png; charset=utf-8 - var mimeType = Request.ContentType.Split(';').FirstOrDefault(); + var mimeType = Request.ContentType?.Split(';').FirstOrDefault(); var userDataPath = Path.Combine(_serverConfigurationManager.ApplicationPaths.UserConfigurationDirectoryPath, user.Username); if (user.ProfileImage != null) { @@ -341,7 +341,7 @@ namespace Jellyfin.Api.Controllers await using var memoryStream = await GetMemoryStream(Request.Body).ConfigureAwait(false); // Handle image/png; charset=utf-8 - var mimeType = Request.ContentType.Split(';').FirstOrDefault(); + var mimeType = Request.ContentType?.Split(';').FirstOrDefault(); await _providerManager.SaveImage(item, memoryStream, mimeType, imageType, null, CancellationToken.None).ConfigureAwait(false); await item.UpdateToRepositoryAsync(ItemUpdateType.ImageUpdate, CancellationToken.None).ConfigureAwait(false); @@ -377,7 +377,7 @@ namespace Jellyfin.Api.Controllers await using var memoryStream = await GetMemoryStream(Request.Body).ConfigureAwait(false); // Handle image/png; charset=utf-8 - var mimeType = Request.ContentType.Split(';').FirstOrDefault(); + var mimeType = Request.ContentType?.Split(';').FirstOrDefault(); await _providerManager.SaveImage(item, memoryStream, mimeType, imageType, null, CancellationToken.None).ConfigureAwait(false); await item.UpdateToRepositoryAsync(ItemUpdateType.ImageUpdate, CancellationToken.None).ConfigureAwait(false); @@ -2026,7 +2026,7 @@ namespace Jellyfin.Api.Controllers return NoContent(); } - return PhysicalFile(imagePath, imageContentType); + return PhysicalFile(imagePath, imageContentType ?? MediaTypeNames.Text.Plain); } } } diff --git a/Jellyfin.Api/Helpers/FileStreamResponseHelpers.cs b/Jellyfin.Api/Helpers/FileStreamResponseHelpers.cs index b0fd59e5e3..6385b62c96 100644 --- a/Jellyfin.Api/Helpers/FileStreamResponseHelpers.cs +++ b/Jellyfin.Api/Helpers/FileStreamResponseHelpers.cs @@ -1,6 +1,7 @@ using System; using System.IO; using System.Net.Http; +using System.Net.Mime; using System.Threading; using System.Threading.Tasks; using Jellyfin.Api.Models.PlaybackDtos; @@ -40,7 +41,7 @@ namespace Jellyfin.Api.Helpers // Can't dispose the response as it's required up the call chain. var response = await httpClient.GetAsync(new Uri(state.MediaPath), cancellationToken).ConfigureAwait(false); - var contentType = response.Content.Headers.ContentType?.ToString(); + var contentType = response.Content.Headers.ContentType?.ToString() ?? MediaTypeNames.Text.Plain; httpContext.Response.Headers[HeaderNames.AcceptRanges] = "none"; diff --git a/Jellyfin.Api/Jellyfin.Api.csproj b/Jellyfin.Api/Jellyfin.Api.csproj index 7f4eb0378a..8cc4711a72 100644 --- a/Jellyfin.Api/Jellyfin.Api.csproj +++ b/Jellyfin.Api/Jellyfin.Api.csproj @@ -6,7 +6,7 @@ - net5.0 + net6.0 true AD0001 diff --git a/Jellyfin.Api/ModelBinders/NullableEnumModelBinder.cs b/Jellyfin.Api/ModelBinders/NullableEnumModelBinder.cs index be2045fbab..d2e78ac884 100644 --- a/Jellyfin.Api/ModelBinders/NullableEnumModelBinder.cs +++ b/Jellyfin.Api/ModelBinders/NullableEnumModelBinder.cs @@ -32,7 +32,8 @@ namespace Jellyfin.Api.ModelBinders { try { - var convertedValue = converter.ConvertFromString(valueProviderResult.FirstValue); + // REVIEW: This shouldn't be null here + var convertedValue = converter.ConvertFromString(valueProviderResult.FirstValue!); bindingContext.Result = ModelBindingResult.Success(convertedValue); } catch (FormatException e) @@ -44,4 +45,4 @@ namespace Jellyfin.Api.ModelBinders return Task.CompletedTask; } } -} \ No newline at end of file +} diff --git a/Jellyfin.Data/Jellyfin.Data.csproj b/Jellyfin.Data/Jellyfin.Data.csproj index 65bbd49da2..19aef704c0 100644 --- a/Jellyfin.Data/Jellyfin.Data.csproj +++ b/Jellyfin.Data/Jellyfin.Data.csproj @@ -1,7 +1,7 @@  - net5.0 + net6.0 false true true diff --git a/Jellyfin.Drawing.Skia/Jellyfin.Drawing.Skia.csproj b/Jellyfin.Drawing.Skia/Jellyfin.Drawing.Skia.csproj index 8cee5dcaee..5fa386ecac 100644 --- a/Jellyfin.Drawing.Skia/Jellyfin.Drawing.Skia.csproj +++ b/Jellyfin.Drawing.Skia/Jellyfin.Drawing.Skia.csproj @@ -6,7 +6,7 @@ - net5.0 + net6.0 false true @@ -28,11 +28,6 @@ - - - - - diff --git a/Jellyfin.Networking/Jellyfin.Networking.csproj b/Jellyfin.Networking/Jellyfin.Networking.csproj index 227a41ce44..0cd9a59156 100644 --- a/Jellyfin.Networking/Jellyfin.Networking.csproj +++ b/Jellyfin.Networking/Jellyfin.Networking.csproj @@ -1,6 +1,6 @@ - net5.0 + net6.0 false true diff --git a/Jellyfin.Server.Implementations/Jellyfin.Server.Implementations.csproj b/Jellyfin.Server.Implementations/Jellyfin.Server.Implementations.csproj index 434c414a4a..337f5cb82a 100644 --- a/Jellyfin.Server.Implementations/Jellyfin.Server.Implementations.csproj +++ b/Jellyfin.Server.Implementations/Jellyfin.Server.Implementations.csproj @@ -1,7 +1,7 @@ - net5.0 + net6.0 false true diff --git a/Jellyfin.Server/Configuration/CorsPolicyProvider.cs b/Jellyfin.Server/Configuration/CorsPolicyProvider.cs index 0d04b6bb13..b061be33b5 100644 --- a/Jellyfin.Server/Configuration/CorsPolicyProvider.cs +++ b/Jellyfin.Server/Configuration/CorsPolicyProvider.cs @@ -23,7 +23,7 @@ namespace Jellyfin.Server.Configuration } /// - public Task GetPolicyAsync(HttpContext context, string policyName) + public Task GetPolicyAsync(HttpContext context, string? policyName) { var corsHosts = _serverConfigurationManager.Configuration.CorsHosts; var builder = new CorsPolicyBuilder() @@ -43,7 +43,7 @@ namespace Jellyfin.Server.Configuration .AllowCredentials(); } - return Task.FromResult(builder.Build()); + return Task.FromResult(builder.Build()); } } } diff --git a/Jellyfin.Server/Infrastructure/SymlinkFollowingPhysicalFileResultExecutor.cs b/Jellyfin.Server/Infrastructure/SymlinkFollowingPhysicalFileResultExecutor.cs index e171fc145c..4abd5b36d1 100644 --- a/Jellyfin.Server/Infrastructure/SymlinkFollowingPhysicalFileResultExecutor.cs +++ b/Jellyfin.Server/Infrastructure/SymlinkFollowingPhysicalFileResultExecutor.cs @@ -68,7 +68,7 @@ namespace Jellyfin.Server.Infrastructure } /// - protected override Task WriteFileAsync(ActionContext context, PhysicalFileResult result, RangeItemHeaderValue range, long rangeLength) + protected override Task WriteFileAsync(ActionContext context, PhysicalFileResult result, RangeItemHeaderValue? range, long rangeLength) { if (context == null) { diff --git a/Jellyfin.Server/Jellyfin.Server.csproj b/Jellyfin.Server/Jellyfin.Server.csproj index fc935cecb2..074d43fba8 100644 --- a/Jellyfin.Server/Jellyfin.Server.csproj +++ b/Jellyfin.Server/Jellyfin.Server.csproj @@ -8,7 +8,7 @@ jellyfin Exe - net5.0 + net6.0 false false true diff --git a/Jellyfin.Server/Middleware/QueryStringDecodingMiddleware.cs b/Jellyfin.Server/Middleware/QueryStringDecodingMiddleware.cs index fd0ebbf438..cdd86e28e6 100644 --- a/Jellyfin.Server/Middleware/QueryStringDecodingMiddleware.cs +++ b/Jellyfin.Server/Middleware/QueryStringDecodingMiddleware.cs @@ -27,7 +27,11 @@ namespace Jellyfin.Server.Middleware /// The async task. public async Task Invoke(HttpContext httpContext) { - httpContext.Features.Set(new UrlDecodeQueryFeature(httpContext.Features.Get())); + var feature = httpContext.Features.Get(); + if (feature != null) + { + httpContext.Features.Set(new UrlDecodeQueryFeature(feature)); + } await _next(httpContext).ConfigureAwait(false); } diff --git a/MediaBrowser.Common/MediaBrowser.Common.csproj b/MediaBrowser.Common/MediaBrowser.Common.csproj index 12cfaf9789..6358c00001 100644 --- a/MediaBrowser.Common/MediaBrowser.Common.csproj +++ b/MediaBrowser.Common/MediaBrowser.Common.csproj @@ -29,7 +29,7 @@ - net5.0 + net6.0 false true true diff --git a/MediaBrowser.Controller/Dlna/IDlnaManager.cs b/MediaBrowser.Controller/Dlna/IDlnaManager.cs index a64919700d..cc0a107a81 100644 --- a/MediaBrowser.Controller/Dlna/IDlnaManager.cs +++ b/MediaBrowser.Controller/Dlna/IDlnaManager.cs @@ -74,6 +74,6 @@ namespace MediaBrowser.Controller.Dlna /// /// The filename. /// DlnaIconResponse. - ImageStream GetIcon(string filename); + ImageStream? GetIcon(string filename); } } diff --git a/MediaBrowser.Controller/Drawing/IImageProcessor.cs b/MediaBrowser.Controller/Drawing/IImageProcessor.cs index c7f61a90bb..7ca0e851bd 100644 --- a/MediaBrowser.Controller/Drawing/IImageProcessor.cs +++ b/MediaBrowser.Controller/Drawing/IImageProcessor.cs @@ -58,7 +58,7 @@ namespace MediaBrowser.Controller.Drawing /// Guid. string GetImageCacheTag(BaseItem item, ItemImageInfo image); - string GetImageCacheTag(BaseItem item, ChapterInfo info); + string GetImageCacheTag(BaseItem item, ChapterInfo chapter); string? GetImageCacheTag(User user); diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index 0f697bcccd..47cec7d77f 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -32,7 +32,7 @@ - net5.0 + net6.0 false true true diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs b/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs index b09b7dba6c..e92c4a08a6 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs @@ -541,7 +541,12 @@ namespace MediaBrowser.Controller.MediaEncoding return MimeType; } - return MimeTypes.GetMimeType(outputPath, enableStreamDefault); + if (enableStreamDefault) + { + return MimeTypes.GetMimeType(outputPath); + } + + return MimeTypes.GetMimeType(outputPath, null); } public bool DeInterlace(string videoCodec, bool forceDeinterlaceIfSourceIsInterlaced) diff --git a/MediaBrowser.LocalMetadata/MediaBrowser.LocalMetadata.csproj b/MediaBrowser.LocalMetadata/MediaBrowser.LocalMetadata.csproj index 1cf8fcd1b5..a3db717b9f 100644 --- a/MediaBrowser.LocalMetadata/MediaBrowser.LocalMetadata.csproj +++ b/MediaBrowser.LocalMetadata/MediaBrowser.LocalMetadata.csproj @@ -11,7 +11,7 @@ - net5.0 + net6.0 false true diff --git a/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj b/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj index 5deaecc952..30cfb904e1 100644 --- a/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj +++ b/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj @@ -6,7 +6,7 @@ - net5.0 + net6.0 false true diff --git a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEditParser.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEditParser.cs index 3d864e29ca..20e4be7802 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEditParser.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEditParser.cs @@ -38,7 +38,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles subRip.LoadSubtitle(subtitle, lines, "untitled"); if (subRip.ErrorCount > 0) { - _logger.LogError("{ErrorCount} errors encountered while parsing subtitle."); + _logger.LogError("{ErrorCount} errors encountered while parsing subtitle.", subRip.ErrorCount); } var trackInfo = new SubtitleTrackInfo(); diff --git a/MediaBrowser.Model/MediaBrowser.Model.csproj b/MediaBrowser.Model/MediaBrowser.Model.csproj index a371afc2cf..b0a12a9c90 100644 --- a/MediaBrowser.Model/MediaBrowser.Model.csproj +++ b/MediaBrowser.Model/MediaBrowser.Model.csproj @@ -14,7 +14,7 @@ - net5.0 + net6.0 false true true diff --git a/MediaBrowser.Model/Net/MimeTypes.cs b/MediaBrowser.Model/Net/MimeTypes.cs index 7b3c17c85a..1d9150f02b 100644 --- a/MediaBrowser.Model/Net/MimeTypes.cs +++ b/MediaBrowser.Model/Net/MimeTypes.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; using Jellyfin.Extensions; @@ -164,15 +165,16 @@ namespace MediaBrowser.Model.Net return dict; } - public static string? GetMimeType(string path) => GetMimeType(path, true); + public static string GetMimeType(string path) => GetMimeType(path, "application/octet-stream"); /// /// Gets the type of the MIME. /// /// The filename to find the MIME type of. - /// Whether of not to return a default value if no fitting MIME type is found. - /// The worrect MIME type for the given filename, or `null` if it wasn't found and is false. - public static string? GetMimeType(string filename, bool enableStreamDefault) + /// Theefault value to return if no fitting MIME type is found. + /// The correct MIME type for the given filename, or if it wasn't found. + [return: NotNullIfNotNullAttribute("defaultValue")] + public static string? GetMimeType(string filename, string? defaultValue = null) { if (filename.Length == 0) { @@ -211,7 +213,7 @@ namespace MediaBrowser.Model.Net return "application/octet-stream"; } - return enableStreamDefault ? "application/octet-stream" : null; + return defaultValue; } public static string? ToExtension(string mimeType) diff --git a/MediaBrowser.Providers/MediaBrowser.Providers.csproj b/MediaBrowser.Providers/MediaBrowser.Providers.csproj index 3a6e162746..29d6b01f23 100644 --- a/MediaBrowser.Providers/MediaBrowser.Providers.csproj +++ b/MediaBrowser.Providers/MediaBrowser.Providers.csproj @@ -26,7 +26,7 @@ - net5.0 + net6.0 false true ../jellyfin.ruleset diff --git a/MediaBrowser.Providers/Plugins/Omdb/JsonOmdbNotAvailableInt32Converter.cs b/MediaBrowser.Providers/Plugins/Omdb/JsonOmdbNotAvailableInt32Converter.cs index 268538815e..19d90b9a1b 100644 --- a/MediaBrowser.Providers/Plugins/Omdb/JsonOmdbNotAvailableInt32Converter.cs +++ b/MediaBrowser.Providers/Plugins/Omdb/JsonOmdbNotAvailableInt32Converter.cs @@ -18,7 +18,7 @@ namespace MediaBrowser.Providers.Plugins.Omdb if (reader.TokenType == JsonTokenType.String) { var str = reader.GetString(); - if (str != null && str.Equals("N/A", StringComparison.OrdinalIgnoreCase)) + if (str == null || str.Equals("N/A", StringComparison.OrdinalIgnoreCase)) { return null; } diff --git a/MediaBrowser.XbmcMetadata/MediaBrowser.XbmcMetadata.csproj b/MediaBrowser.XbmcMetadata/MediaBrowser.XbmcMetadata.csproj index 3e2a9bacf1..926be5a927 100644 --- a/MediaBrowser.XbmcMetadata/MediaBrowser.XbmcMetadata.csproj +++ b/MediaBrowser.XbmcMetadata/MediaBrowser.XbmcMetadata.csproj @@ -15,7 +15,7 @@ - net5.0 + net6.0 false true diff --git a/RSSDP/DisposableManagedObjectBase.cs b/RSSDP/DisposableManagedObjectBase.cs index 7d6a471f95..5d7da4124e 100644 --- a/RSSDP/DisposableManagedObjectBase.cs +++ b/RSSDP/DisposableManagedObjectBase.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Text; namespace Rssdp.Infrastructure @@ -45,11 +46,11 @@ namespace Rssdp.Infrastructure const string ArgFormat = "{0}: {1}\r\n"; - builder.AppendFormat("{0}\r\n", header); + builder.AppendFormat(CultureInfo.InvariantCulture, "{0}\r\n", header); foreach (var pair in values) { - builder.AppendFormat(ArgFormat, pair.Key, pair.Value); + builder.AppendFormat(CultureInfo.InvariantCulture, ArgFormat, pair.Key, pair.Value); } builder.Append("\r\n"); diff --git a/RSSDP/RSSDP.csproj b/RSSDP/RSSDP.csproj index 54113d4644..77130983b5 100644 --- a/RSSDP/RSSDP.csproj +++ b/RSSDP/RSSDP.csproj @@ -11,7 +11,7 @@ - net5.0 + net6.0 false AllDisabledByDefault disable diff --git a/RSSDP/SsdpDevice.cs b/RSSDP/SsdpDevice.cs index 4005d836d9..c826830f1d 100644 --- a/RSSDP/SsdpDevice.cs +++ b/RSSDP/SsdpDevice.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.Globalization; using Rssdp.Infrastructure; namespace Rssdp @@ -134,11 +135,13 @@ namespace Rssdp { get { - return String.Format("urn:{0}:{3}:{1}:{2}", - this.DeviceTypeNamespace ?? String.Empty, - this.DeviceType ?? String.Empty, - this.DeviceVersion, - this.DeviceClass ?? "device"); + return String.Format( + CultureInfo.InvariantCulture, + "urn:{0}:{3}:{1}:{2}", + this.DeviceTypeNamespace ?? String.Empty, + this.DeviceType ?? String.Empty, + this.DeviceVersion, + this.DeviceClass ?? "device"); } } diff --git a/RSSDP/SsdpDevicePublisher.cs b/RSSDP/SsdpDevicePublisher.cs index c9e795d565..64d19803df 100644 --- a/RSSDP/SsdpDevicePublisher.cs +++ b/RSSDP/SsdpDevicePublisher.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.Globalization; using System.Linq; using System.Net; using System.Threading; @@ -233,7 +234,7 @@ namespace Rssdp.Infrastructure { if (String.IsNullOrEmpty(searchTarget)) { - WriteTrace(String.Format("Invalid search request received From {0}, Target is null/empty.", remoteEndPoint.ToString())); + WriteTrace(String.Format(CultureInfo.InvariantCulture, "Invalid search request received From {0}, Target is null/empty.", remoteEndPoint.ToString())); return; } @@ -340,7 +341,7 @@ namespace Rssdp.Infrastructure private string GetUsn(string udn, string fullDeviceType) { - return String.Format("{0}::{1}", udn, fullDeviceType); + return String.Format(CultureInfo.InvariantCulture, "{0}::{1}", udn, fullDeviceType); } private async void SendSearchResponse( @@ -363,7 +364,7 @@ namespace Rssdp.Infrastructure values["DATE"] = DateTime.UtcNow.ToString("r"); values["CACHE-CONTROL"] = "max-age = " + rootDevice.CacheLifetime.TotalSeconds; values["ST"] = searchTarget; - values["SERVER"] = string.Format("{0}/{1} UPnP/1.0 RSSDP/{2}", _OSName, _OSVersion, ServerVersion); + values["SERVER"] = string.Format(CultureInfo.InvariantCulture, "{0}/{1} UPnP/1.0 RSSDP/{2}", _OSName, _OSVersion, ServerVersion); values["USN"] = uniqueServiceName; values["LOCATION"] = rootDevice.Location.ToString(); @@ -497,7 +498,7 @@ namespace Rssdp.Infrastructure values["DATE"] = DateTime.UtcNow.ToString("r"); values["CACHE-CONTROL"] = "max-age = " + rootDevice.CacheLifetime.TotalSeconds; values["LOCATION"] = rootDevice.Location.ToString(); - values["SERVER"] = string.Format("{0}/{1} UPnP/1.0 RSSDP/{2}", _OSName, _OSVersion, ServerVersion); + values["SERVER"] = string.Format(CultureInfo.InvariantCulture, "{0}/{1} UPnP/1.0 RSSDP/{2}", _OSName, _OSVersion, ServerVersion); values["NTS"] = "ssdp:alive"; values["NT"] = notificationType; values["USN"] = uniqueServiceName; @@ -522,7 +523,7 @@ namespace Rssdp.Infrastructure } tasks.Add(SendByeByeNotification(device, device.Udn, device.Udn, cancellationToken)); - tasks.Add(SendByeByeNotification(device, String.Format("urn:{0}", device.FullDeviceType), GetUsn(device.Udn, device.FullDeviceType), cancellationToken)); + tasks.Add(SendByeByeNotification(device, String.Format(CultureInfo.InvariantCulture, "urn:{0}", device.FullDeviceType), GetUsn(device.Udn, device.FullDeviceType), cancellationToken)); foreach (var childDevice in device.Devices) { @@ -542,7 +543,7 @@ namespace Rssdp.Infrastructure // If needed later for non-server devices, these headers will need to be dynamic values["HOST"] = "239.255.255.250:1900"; values["DATE"] = DateTime.UtcNow.ToString("r"); - values["SERVER"] = string.Format("{0}/{1} UPnP/1.0 RSSDP/{2}", _OSName, _OSVersion, ServerVersion); + values["SERVER"] = string.Format(CultureInfo.InvariantCulture, "{0}/{1} UPnP/1.0 RSSDP/{2}", _OSName, _OSVersion, ServerVersion); values["NTS"] = "ssdp:byebye"; values["NT"] = notificationType; values["USN"] = uniqueServiceName; @@ -550,7 +551,7 @@ namespace Rssdp.Infrastructure var message = BuildMessage(header, values); var sendCount = IsDisposed ? 1 : 3; - WriteTrace(String.Format("Sent byebye notification"), device); + WriteTrace(String.Format(CultureInfo.InvariantCulture, "Sent byebye notification"), device); return _CommsServer.SendMulticastMessage(message, sendCount, _sendOnlyMatchedHost ? device.ToRootDevice().Address : null, cancellationToken); } diff --git a/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj b/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj index 9dac63e703..b52ea078af 100644 --- a/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj +++ b/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj @@ -6,7 +6,7 @@ - net5.0 + net6.0 false ../jellyfin-tests.ruleset diff --git a/tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj b/tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj index 1619fa89c8..1fe4e25656 100644 --- a/tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj +++ b/tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj @@ -6,7 +6,7 @@ - net5.0 + net6.0 false ../jellyfin-tests.ruleset diff --git a/tests/Jellyfin.Controller.Tests/Jellyfin.Controller.Tests.csproj b/tests/Jellyfin.Controller.Tests/Jellyfin.Controller.Tests.csproj index a5778b59c8..e9a9515710 100644 --- a/tests/Jellyfin.Controller.Tests/Jellyfin.Controller.Tests.csproj +++ b/tests/Jellyfin.Controller.Tests/Jellyfin.Controller.Tests.csproj @@ -6,7 +6,7 @@ - net5.0 + net6.0 false ../jellyfin-tests.ruleset diff --git a/tests/Jellyfin.Dlna.Tests/Jellyfin.Dlna.Tests.csproj b/tests/Jellyfin.Dlna.Tests/Jellyfin.Dlna.Tests.csproj index 5a48631c29..1fb95aab4d 100644 --- a/tests/Jellyfin.Dlna.Tests/Jellyfin.Dlna.Tests.csproj +++ b/tests/Jellyfin.Dlna.Tests/Jellyfin.Dlna.Tests.csproj @@ -1,7 +1,7 @@ - net5.0 + net6.0 false ../jellyfin-tests.ruleset diff --git a/tests/Jellyfin.Extensions.Tests/Jellyfin.Extensions.Tests.csproj b/tests/Jellyfin.Extensions.Tests/Jellyfin.Extensions.Tests.csproj index 20680157f5..2dc4ac19a5 100644 --- a/tests/Jellyfin.Extensions.Tests/Jellyfin.Extensions.Tests.csproj +++ b/tests/Jellyfin.Extensions.Tests/Jellyfin.Extensions.Tests.csproj @@ -1,7 +1,7 @@ - net5.0 + net6.0 false ../jellyfin-tests.ruleset diff --git a/tests/Jellyfin.MediaEncoding.Tests/Jellyfin.MediaEncoding.Tests.csproj b/tests/Jellyfin.MediaEncoding.Tests/Jellyfin.MediaEncoding.Tests.csproj index e9cd8c0623..201f63a2d6 100644 --- a/tests/Jellyfin.MediaEncoding.Tests/Jellyfin.MediaEncoding.Tests.csproj +++ b/tests/Jellyfin.MediaEncoding.Tests/Jellyfin.MediaEncoding.Tests.csproj @@ -6,7 +6,7 @@ - net5.0 + net6.0 false ../jellyfin-tests.ruleset diff --git a/tests/Jellyfin.Model.Tests/Jellyfin.Model.Tests.csproj b/tests/Jellyfin.Model.Tests/Jellyfin.Model.Tests.csproj index 09b8a7a948..a37e5ac920 100644 --- a/tests/Jellyfin.Model.Tests/Jellyfin.Model.Tests.csproj +++ b/tests/Jellyfin.Model.Tests/Jellyfin.Model.Tests.csproj @@ -1,7 +1,7 @@ - net5.0 + net6.0 false ../jellyfin-tests.ruleset diff --git a/tests/Jellyfin.Naming.Tests/Jellyfin.Naming.Tests.csproj b/tests/Jellyfin.Naming.Tests/Jellyfin.Naming.Tests.csproj index a4ebab141e..75d466198a 100644 --- a/tests/Jellyfin.Naming.Tests/Jellyfin.Naming.Tests.csproj +++ b/tests/Jellyfin.Naming.Tests/Jellyfin.Naming.Tests.csproj @@ -6,7 +6,7 @@ - net5.0 + net6.0 false ../jellyfin-tests.ruleset diff --git a/tests/Jellyfin.Networking.Tests/Jellyfin.Networking.Tests.csproj b/tests/Jellyfin.Networking.Tests/Jellyfin.Networking.Tests.csproj index 5fa2ecfe9e..75d9b9ea90 100644 --- a/tests/Jellyfin.Networking.Tests/Jellyfin.Networking.Tests.csproj +++ b/tests/Jellyfin.Networking.Tests/Jellyfin.Networking.Tests.csproj @@ -6,7 +6,7 @@ - net5.0 + net6.0 false ../jellyfin-tests.ruleset diff --git a/tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj b/tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj index 9b6ab7bdf5..5ecd846047 100644 --- a/tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj +++ b/tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj @@ -6,7 +6,7 @@ - net5.0 + net6.0 false ../jellyfin-tests.ruleset Jellyfin.Server.Implementations.Tests diff --git a/tests/Jellyfin.Server.Integration.Tests/Jellyfin.Server.Integration.Tests.csproj b/tests/Jellyfin.Server.Integration.Tests/Jellyfin.Server.Integration.Tests.csproj index 42e60df5fb..7939c7118e 100644 --- a/tests/Jellyfin.Server.Integration.Tests/Jellyfin.Server.Integration.Tests.csproj +++ b/tests/Jellyfin.Server.Integration.Tests/Jellyfin.Server.Integration.Tests.csproj @@ -1,6 +1,6 @@ - net5.0 + net6.0 false ../jellyfin-tests.ruleset diff --git a/tests/Jellyfin.Server.Tests/Jellyfin.Server.Tests.csproj b/tests/Jellyfin.Server.Tests/Jellyfin.Server.Tests.csproj index 4f0bbc36cf..b30e690a5e 100644 --- a/tests/Jellyfin.Server.Tests/Jellyfin.Server.Tests.csproj +++ b/tests/Jellyfin.Server.Tests/Jellyfin.Server.Tests.csproj @@ -1,7 +1,7 @@ - net5.0 + net6.0 false ../jellyfin-tests.ruleset diff --git a/tests/Jellyfin.XbmcMetadata.Tests/Jellyfin.XbmcMetadata.Tests.csproj b/tests/Jellyfin.XbmcMetadata.Tests/Jellyfin.XbmcMetadata.Tests.csproj index e085907583..94294c8bf3 100644 --- a/tests/Jellyfin.XbmcMetadata.Tests/Jellyfin.XbmcMetadata.Tests.csproj +++ b/tests/Jellyfin.XbmcMetadata.Tests/Jellyfin.XbmcMetadata.Tests.csproj @@ -1,7 +1,7 @@ - net5.0 + net6.0 false ../jellyfin-tests.ruleset -- cgit v1.2.3 From f31224fa8f1dccb730703c048c26e14b5d14fa55 Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Sat, 25 Sep 2021 19:44:40 +0200 Subject: Remove sync FileStream hack --- Emby.Dlna/DlnaManager.cs | 2 +- Emby.Drawing/ImageProcessor.cs | 2 +- .../LiveTv/EmbyTV/DirectRecorder.cs | 4 ++-- .../LiveTv/EmbyTV/EncodedRecorder.cs | 2 +- .../LiveTv/Listings/XmlTvListingsProvider.cs | 2 +- .../LiveTv/TunerHosts/LiveStream.cs | 6 +++--- .../LiveTv/TunerHosts/SharedHttpStream.cs | 2 +- Jellyfin.Api/Controllers/RemoteImageController.cs | 2 +- Jellyfin.Api/Controllers/SystemController.cs | 2 +- Jellyfin.Api/Helpers/HlsHelpers.cs | 2 +- Jellyfin.Api/Helpers/ProgressiveFileStream.cs | 24 ++-------------------- Jellyfin.Api/Helpers/TranscodingJobHelper.cs | 2 +- .../SymlinkFollowingPhysicalFileResultExecutor.cs | 2 +- Jellyfin.Server/Program.cs | 2 +- .../Subtitles/SubtitleEncoder.cs | 2 +- MediaBrowser.Model/IO/AsyncFile.cs | 11 ++-------- MediaBrowser.Providers/Manager/ImageSaver.cs | 2 +- .../Manager/ItemImageProvider.cs | 2 +- .../Plugins/AudioDb/AudioDbAlbumProvider.cs | 2 +- .../Plugins/AudioDb/AudioDbArtistProvider.cs | 2 +- .../Plugins/Omdb/OmdbProvider.cs | 4 ++-- .../Studios/StudiosImageProvider.cs | 2 +- .../Subtitles/SubtitleManager.cs | 2 +- 23 files changed, 29 insertions(+), 56 deletions(-) (limited to 'Emby.Server.Implementations/LiveTv') diff --git a/Emby.Dlna/DlnaManager.cs b/Emby.Dlna/DlnaManager.cs index 305e43a3ca..8fe9d484e7 100644 --- a/Emby.Dlna/DlnaManager.cs +++ b/Emby.Dlna/DlnaManager.cs @@ -366,7 +366,7 @@ namespace Emby.Dlna Directory.CreateDirectory(systemProfilesPath); // use FileShare.None as this bypasses dotnet bug dotnet/runtime#42790 . - using (var fileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, AsyncFile.UseAsyncIO)) + using (var fileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous)) { await stream.CopyToAsync(fileStream).ConfigureAwait(false); } diff --git a/Emby.Drawing/ImageProcessor.cs b/Emby.Drawing/ImageProcessor.cs index 0ad8bca314..9b130fdfd8 100644 --- a/Emby.Drawing/ImageProcessor.cs +++ b/Emby.Drawing/ImageProcessor.cs @@ -102,7 +102,7 @@ namespace Emby.Drawing { var file = await ProcessImage(options).ConfigureAwait(false); - using (var fileStream = new FileStream(file.Item1, FileMode.Open, FileAccess.Read, FileShare.Read, IODefaults.FileStreamBufferSize, AsyncFile.UseAsyncIO)) + using (var fileStream = new FileStream(file.Item1, FileMode.Open, FileAccess.Read, FileShare.Read, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous)) { await fileStream.CopyToAsync(toStream).ConfigureAwait(false); } diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs index f6e0111b6d..41381d55bd 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs @@ -47,7 +47,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV Directory.CreateDirectory(Path.GetDirectoryName(targetFile) ?? throw new ArgumentException("Path can't be a root directory.", nameof(targetFile))); // use FileShare.None as this bypasses dotnet bug dotnet/runtime#42790 . - using (var output = new FileStream(targetFile, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, AsyncFile.UseAsyncIO)) + using (var output = new FileStream(targetFile, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous)) { onStarted(); @@ -80,7 +80,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV Directory.CreateDirectory(Path.GetDirectoryName(targetFile) ?? throw new ArgumentException("Path can't be a root directory.", nameof(targetFile))); // use FileShare.None as this bypasses dotnet bug dotnet/runtime#42790 . - await using var output = new FileStream(targetFile, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.CopyToBufferSize, AsyncFile.UseAsyncIO); + await using var output = new FileStream(targetFile, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.CopyToBufferSize, FileOptions.Asynchronous); onStarted(); diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs index a943efcc70..3633fa3e10 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs @@ -94,7 +94,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV Directory.CreateDirectory(Path.GetDirectoryName(logFilePath)); // FFMpeg writes debug/error info to stderr. This is useful when debugging so let's put it in the log directory. - _logFileStream = new FileStream(logFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, IODefaults.FileStreamBufferSize, AsyncFile.UseAsyncIO); + _logFileStream = new FileStream(logFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous); await JsonSerializer.SerializeAsync(_logFileStream, mediaSource, _jsonOptions, cancellationToken).ConfigureAwait(false); await _logFileStream.WriteAsync(Encoding.UTF8.GetBytes(Environment.NewLine + Environment.NewLine + commandLineLogMessage + Environment.NewLine + Environment.NewLine), cancellationToken).ConfigureAwait(false); diff --git a/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs b/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs index cb9801c178..2e51ac8071 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs @@ -82,7 +82,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings using var response = await _httpClientFactory.CreateClient(NamedClient.Default).GetAsync(path, cancellationToken).ConfigureAwait(false); await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); - await using (var fileStream = new FileStream(cacheFile, FileMode.CreateNew, FileAccess.Write, FileShare.None, IODefaults.CopyToBufferSize, AsyncFile.UseAsyncIO)) + await using (var fileStream = new FileStream(cacheFile, FileMode.CreateNew, FileAccess.Write, FileShare.None, IODefaults.CopyToBufferSize, FileOptions.Asynchronous)) { await stream.CopyToAsync(fileStream, cancellationToken).ConfigureAwait(false); } diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs index 817b1f8046..20a9a705b8 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs @@ -97,7 +97,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts public Stream GetStream() { - var stream = GetInputStream(TempFilePath, AsyncFile.UseAsyncIO); + var stream = GetInputStream(TempFilePath); bool seekFile = (DateTime.UtcNow - DateOpened).TotalSeconds > 10; if (seekFile) { @@ -107,14 +107,14 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts return stream; } - protected FileStream GetInputStream(string path, bool allowAsyncFileRead) + protected FileStream GetInputStream(string path) => new FileStream( path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, IODefaults.FileStreamBufferSize, - allowAsyncFileRead ? FileOptions.SequentialScan | FileOptions.Asynchronous : FileOptions.SequentialScan); + FileOptions.SequentialScan | FileOptions.Asynchronous); protected async Task DeleteTempFiles(string path, int retryCount = 0) { diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs index 84a878e517..3b69e55b01 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs @@ -118,7 +118,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts Logger.LogInformation("Beginning {StreamType} stream to {FilePath}", GetType().Name, TempFilePath); using var message = response; await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); - await using var fileStream = new FileStream(TempFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, IODefaults.FileStreamBufferSize, AsyncFile.UseAsyncIO); + await using var fileStream = new FileStream(TempFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous); await StreamHelper.CopyToAsync( stream, fileStream, diff --git a/Jellyfin.Api/Controllers/RemoteImageController.cs b/Jellyfin.Api/Controllers/RemoteImageController.cs index bcb2b50c7a..8a33b12f4c 100644 --- a/Jellyfin.Api/Controllers/RemoteImageController.cs +++ b/Jellyfin.Api/Controllers/RemoteImageController.cs @@ -206,7 +206,7 @@ namespace Jellyfin.Api.Controllers var fullCacheDirectory = Path.GetDirectoryName(fullCachePath) ?? throw new ResourceNotFoundException($"Provided path ({fullCachePath}) is not valid."); Directory.CreateDirectory(fullCacheDirectory); // use FileShare.None as this bypasses dotnet bug dotnet/runtime#42790 . - await using var fileStream = new FileStream(fullCachePath, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, AsyncFile.UseAsyncIO); + await using var fileStream = new FileStream(fullCachePath, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous); await response.Content.CopyToAsync(fileStream).ConfigureAwait(false); var pointerCacheDirectory = Path.GetDirectoryName(pointerCachePath) ?? throw new ArgumentException($"Provided path ({pointerCachePath}) is not valid.", nameof(pointerCachePath)); diff --git a/Jellyfin.Api/Controllers/SystemController.cs b/Jellyfin.Api/Controllers/SystemController.cs index e6584f0fe6..741bdfee97 100644 --- a/Jellyfin.Api/Controllers/SystemController.cs +++ b/Jellyfin.Api/Controllers/SystemController.cs @@ -201,7 +201,7 @@ namespace Jellyfin.Api.Controllers // For older files, assume fully static var fileShare = file.LastWriteTimeUtc < DateTime.UtcNow.AddHours(-1) ? FileShare.Read : FileShare.ReadWrite; - FileStream stream = new FileStream(file.FullName, FileMode.Open, FileAccess.Read, fileShare, IODefaults.FileStreamBufferSize, AsyncFile.UseAsyncIO); + FileStream stream = new FileStream(file.FullName, FileMode.Open, FileAccess.Read, fileShare, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous); return File(stream, "text/plain; charset=utf-8"); } diff --git a/Jellyfin.Api/Helpers/HlsHelpers.cs b/Jellyfin.Api/Helpers/HlsHelpers.cs index f36769dc2a..4567621470 100644 --- a/Jellyfin.Api/Helpers/HlsHelpers.cs +++ b/Jellyfin.Api/Helpers/HlsHelpers.cs @@ -38,7 +38,7 @@ namespace Jellyfin.Api.Helpers FileAccess.Read, FileShare.ReadWrite, IODefaults.FileStreamBufferSize, - (AsyncFile.UseAsyncIO ? FileOptions.Asynchronous : FileOptions.None) | FileOptions.SequentialScan); + FileOptions.Asynchronous | FileOptions.SequentialScan); await using (fileStream.ConfigureAwait(false)) { using var reader = new StreamReader(fileStream); diff --git a/Jellyfin.Api/Helpers/ProgressiveFileStream.cs b/Jellyfin.Api/Helpers/ProgressiveFileStream.cs index c570183514..61e18220a1 100644 --- a/Jellyfin.Api/Helpers/ProgressiveFileStream.cs +++ b/Jellyfin.Api/Helpers/ProgressiveFileStream.cs @@ -17,7 +17,6 @@ namespace Jellyfin.Api.Helpers private readonly TranscodingJobDto? _job; private readonly TranscodingJobHelper? _transcodingJobHelper; private readonly int _timeoutMs; - private readonly bool _allowAsyncFileRead; private int _bytesWritten; private bool _disposed; @@ -34,17 +33,7 @@ namespace Jellyfin.Api.Helpers _transcodingJobHelper = transcodingJobHelper; _timeoutMs = timeoutMs; - var fileOptions = FileOptions.SequentialScan; - _allowAsyncFileRead = false; - - // use non-async filestream along with read due to https://github.com/dotnet/corefx/issues/6039 - if (AsyncFile.UseAsyncIO) - { - fileOptions |= FileOptions.Asynchronous; - _allowAsyncFileRead = true; - } - - _stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, IODefaults.FileStreamBufferSize, fileOptions); + _stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous | FileOptions.SequentialScan); } /// @@ -57,7 +46,6 @@ namespace Jellyfin.Api.Helpers _job = null; _transcodingJobHelper = null; _timeoutMs = timeoutMs; - _allowAsyncFileRead = AsyncFile.UseAsyncIO; _stream = stream; } @@ -103,15 +91,7 @@ namespace Jellyfin.Api.Helpers while (remainingBytesToRead > 0) { cancellationToken.ThrowIfCancellationRequested(); - int bytesRead; - if (_allowAsyncFileRead) - { - bytesRead = await _stream.ReadAsync(buffer, newOffset, remainingBytesToRead, cancellationToken).ConfigureAwait(false); - } - else - { - bytesRead = _stream.Read(buffer, newOffset, remainingBytesToRead); - } + int bytesRead = await _stream.ReadAsync(buffer, newOffset, remainingBytesToRead, cancellationToken).ConfigureAwait(false); remainingBytesToRead -= bytesRead; newOffset += bytesRead; diff --git a/Jellyfin.Api/Helpers/TranscodingJobHelper.cs b/Jellyfin.Api/Helpers/TranscodingJobHelper.cs index 4e1e98df0d..14f287aef6 100644 --- a/Jellyfin.Api/Helpers/TranscodingJobHelper.cs +++ b/Jellyfin.Api/Helpers/TranscodingJobHelper.cs @@ -557,7 +557,7 @@ namespace Jellyfin.Api.Helpers $"{logFilePrefix}{DateTime.Now:yyyy-MM-dd_HH-mm-ss}_{state.Request.MediaSourceId}_{Guid.NewGuid().ToString()[..8]}.log"); // FFmpeg writes debug/error info to stderr. This is useful when debugging so let's put it in the log directory. - Stream logStream = new FileStream(logFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, IODefaults.FileStreamBufferSize, AsyncFile.UseAsyncIO); + Stream logStream = new FileStream(logFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous); var commandLineLogMessageBytes = Encoding.UTF8.GetBytes(request.Path + Environment.NewLine + Environment.NewLine + JsonSerializer.Serialize(state.MediaSource) + Environment.NewLine + Environment.NewLine + commandLineLogMessage + Environment.NewLine + Environment.NewLine); await logStream.WriteAsync(commandLineLogMessageBytes, 0, commandLineLogMessageBytes.Length, cancellationTokenSource.Token).ConfigureAwait(false); diff --git a/Jellyfin.Server/Infrastructure/SymlinkFollowingPhysicalFileResultExecutor.cs b/Jellyfin.Server/Infrastructure/SymlinkFollowingPhysicalFileResultExecutor.cs index 4abd5b36d1..f3fbab77e4 100644 --- a/Jellyfin.Server/Infrastructure/SymlinkFollowingPhysicalFileResultExecutor.cs +++ b/Jellyfin.Server/Infrastructure/SymlinkFollowingPhysicalFileResultExecutor.cs @@ -132,7 +132,7 @@ namespace Jellyfin.Server.Infrastructure FileAccess.Read, FileShare.ReadWrite, bufferSize: BufferSize, - options: (AsyncFile.UseAsyncIO ? FileOptions.Asynchronous : FileOptions.None) | FileOptions.SequentialScan); + options: FileOptions.Asynchronous | FileOptions.SequentialScan); fileStream.Seek(offset, SeekOrigin.Begin); await StreamCopyOperation diff --git a/Jellyfin.Server/Program.cs b/Jellyfin.Server/Program.cs index 1300ce3b67..f36675b955 100644 --- a/Jellyfin.Server/Program.cs +++ b/Jellyfin.Server/Program.cs @@ -547,7 +547,7 @@ namespace Jellyfin.Server ?? throw new InvalidOperationException($"Invalid resource path: '{ResourcePath}'"); // Copy the resource contents to the expected file path for the config file - await using Stream dst = new FileStream(configPath, FileMode.CreateNew, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, AsyncFile.UseAsyncIO); + await using Stream dst = new FileStream(configPath, FileMode.CreateNew, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous); await resource.CopyToAsync(dst).ConfigureAwait(false); } diff --git a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs index f8451e92c3..022cdbe9d3 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs @@ -680,7 +680,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles if (!string.Equals(text, newText, StringComparison.Ordinal)) { // use FileShare.None as this bypasses dotnet bug dotnet/runtime#42790 . - using (var fileStream = new FileStream(file, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, AsyncFile.UseAsyncIO)) + using (var fileStream = new FileStream(file, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous)) using (var writer = new StreamWriter(fileStream, encoding)) { await writer.WriteAsync(newText.AsMemory(), cancellationToken).ConfigureAwait(false); diff --git a/MediaBrowser.Model/IO/AsyncFile.cs b/MediaBrowser.Model/IO/AsyncFile.cs index b888a41639..f38ed9ae3d 100644 --- a/MediaBrowser.Model/IO/AsyncFile.cs +++ b/MediaBrowser.Model/IO/AsyncFile.cs @@ -8,20 +8,13 @@ namespace MediaBrowser.Model.IO /// public static class AsyncFile { - /// - /// Gets a value indicating whether we should use async IO on this platform. - /// . - /// - /// Returns false on Windows; otherwise true. - public static bool UseAsyncIO => !OperatingSystem.IsWindows(); - /// /// Opens an existing file for reading. /// /// The file to be opened for reading. /// A read-only on the specified path. public static FileStream OpenRead(string path) - => new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, IODefaults.FileStreamBufferSize, UseAsyncIO); + => new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous); /// /// Opens an existing file for writing. @@ -29,6 +22,6 @@ namespace MediaBrowser.Model.IO /// The file to be opened for writing. /// An unshared object on the specified path with Write access. public static FileStream OpenWrite(string path) - => new FileStream(path, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, UseAsyncIO); + => new FileStream(path, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous); } } diff --git a/MediaBrowser.Providers/Manager/ImageSaver.cs b/MediaBrowser.Providers/Manager/ImageSaver.cs index 6c14c8de1e..7d259a9d36 100644 --- a/MediaBrowser.Providers/Manager/ImageSaver.cs +++ b/MediaBrowser.Providers/Manager/ImageSaver.cs @@ -264,7 +264,7 @@ namespace MediaBrowser.Providers.Manager _fileSystem.SetAttributes(path, false, false); // use FileShare.None as this bypasses dotnet bug dotnet/runtime#42790 . - await using (var fs = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, AsyncFile.UseAsyncIO)) + await using (var fs = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous)) { await source.CopyToAsync(fs, cancellationToken).ConfigureAwait(false); } diff --git a/MediaBrowser.Providers/Manager/ItemImageProvider.cs b/MediaBrowser.Providers/Manager/ItemImageProvider.cs index 81529e9846..73bca5aa59 100644 --- a/MediaBrowser.Providers/Manager/ItemImageProvider.cs +++ b/MediaBrowser.Providers/Manager/ItemImageProvider.cs @@ -163,7 +163,7 @@ namespace MediaBrowser.Providers.Manager { var mimeType = MimeTypes.GetMimeType(response.Path); - var stream = new FileStream(response.Path, FileMode.Open, FileAccess.Read, FileShare.Read, IODefaults.FileStreamBufferSize, AsyncFile.UseAsyncIO); + var stream = new FileStream(response.Path, FileMode.Open, FileAccess.Read, FileShare.Read, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous); await _providerManager.SaveImage(item, stream, mimeType, imageType, null, cancellationToken).ConfigureAwait(false); } diff --git a/MediaBrowser.Providers/Plugins/AudioDb/AudioDbAlbumProvider.cs b/MediaBrowser.Providers/Plugins/AudioDb/AudioDbAlbumProvider.cs index c1226febfc..3e0b0014eb 100644 --- a/MediaBrowser.Providers/Plugins/AudioDb/AudioDbAlbumProvider.cs +++ b/MediaBrowser.Providers/Plugins/AudioDb/AudioDbAlbumProvider.cs @@ -173,7 +173,7 @@ namespace MediaBrowser.Providers.Plugins.AudioDb using var response = await _httpClientFactory.CreateClient(NamedClient.Default).GetAsync(url, cancellationToken).ConfigureAwait(false); await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); // use FileShare.None as this bypasses dotnet bug dotnet/runtime#42790 . - await using var xmlFileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, AsyncFile.UseAsyncIO); + await using var xmlFileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous); await stream.CopyToAsync(xmlFileStream, cancellationToken).ConfigureAwait(false); } diff --git a/MediaBrowser.Providers/Plugins/AudioDb/AudioDbArtistProvider.cs b/MediaBrowser.Providers/Plugins/AudioDb/AudioDbArtistProvider.cs index 8572b3413d..e0b2f9c588 100644 --- a/MediaBrowser.Providers/Plugins/AudioDb/AudioDbArtistProvider.cs +++ b/MediaBrowser.Providers/Plugins/AudioDb/AudioDbArtistProvider.cs @@ -155,7 +155,7 @@ namespace MediaBrowser.Providers.Plugins.AudioDb Directory.CreateDirectory(Path.GetDirectoryName(path)); // use FileShare.None as this bypasses dotnet bug dotnet/runtime#42790 . - await using var xmlFileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, AsyncFile.UseAsyncIO); + await using var xmlFileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous); await stream.CopyToAsync(xmlFileStream, cancellationToken).ConfigureAwait(false); } diff --git a/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs b/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs index 1dea3dece1..479ae0f391 100644 --- a/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs +++ b/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs @@ -295,7 +295,7 @@ namespace MediaBrowser.Providers.Plugins.Omdb imdbParam)); var rootObject = await GetDeserializedOmdbResponse(_httpClientFactory.CreateClient(NamedClient.Default), url, cancellationToken).ConfigureAwait(false); - await using FileStream jsonFileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, AsyncFile.UseAsyncIO); + await using FileStream jsonFileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous); await JsonSerializer.SerializeAsync(jsonFileStream, rootObject, _jsonOptions, cancellationToken).ConfigureAwait(false); return path; @@ -335,7 +335,7 @@ namespace MediaBrowser.Providers.Plugins.Omdb seasonId)); var rootObject = await GetDeserializedOmdbResponse(_httpClientFactory.CreateClient(NamedClient.Default), url, cancellationToken).ConfigureAwait(false); - await using FileStream jsonFileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, AsyncFile.UseAsyncIO); + await using FileStream jsonFileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous); await JsonSerializer.SerializeAsync(jsonFileStream, rootObject, _jsonOptions, cancellationToken).ConfigureAwait(false); return path; diff --git a/MediaBrowser.Providers/Studios/StudiosImageProvider.cs b/MediaBrowser.Providers/Studios/StudiosImageProvider.cs index 7a057c065f..7b2454efc9 100644 --- a/MediaBrowser.Providers/Studios/StudiosImageProvider.cs +++ b/MediaBrowser.Providers/Studios/StudiosImageProvider.cs @@ -146,7 +146,7 @@ namespace MediaBrowser.Providers.Studios Directory.CreateDirectory(Path.GetDirectoryName(file)); await using var response = await httpClient.GetStreamAsync(url, cancellationToken).ConfigureAwait(false); - await using var fileStream = new FileStream(file, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, AsyncFile.UseAsyncIO); + await using var fileStream = new FileStream(file, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous); await response.CopyToAsync(fileStream, cancellationToken).ConfigureAwait(false); } diff --git a/MediaBrowser.Providers/Subtitles/SubtitleManager.cs b/MediaBrowser.Providers/Subtitles/SubtitleManager.cs index d6c346ba12..772e617abb 100644 --- a/MediaBrowser.Providers/Subtitles/SubtitleManager.cs +++ b/MediaBrowser.Providers/Subtitles/SubtitleManager.cs @@ -245,7 +245,7 @@ namespace MediaBrowser.Providers.Subtitles Directory.CreateDirectory(Path.GetDirectoryName(savePath)); // use FileShare.None as this bypasses dotnet bug dotnet/runtime#42790 . - using var fs = new FileStream(savePath, FileMode.Create, FileAccess.Write, FileShare.None, FileStreamBufferSize, AsyncFile.UseAsyncIO); + using var fs = new FileStream(savePath, FileMode.Create, FileAccess.Write, FileShare.None, FileStreamBufferSize, FileOptions.Asynchronous); await stream.CopyToAsync(fs).ConfigureAwait(false); return; -- cgit v1.2.3 From 79642af3b8a9e2f001ae07902090b68e677bb949 Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Sat, 25 Sep 2021 20:32:53 +0200 Subject: Fix some warnings --- .../Library/LiveStreamHelper.cs | 2 +- .../LiveTv/TunerHosts/BaseTunerHost.cs | 18 ++++++++++-------- .../TunerHosts/HdHomerun/HdHomerunUdpStream.cs | 3 ++- .../LiveTv/TunerHosts/LiveStream.cs | 18 +++++++++--------- .../Playlists/ManualPlaylistsFolder.cs | 18 +++++++++--------- Emby.Server.Implementations/Plugins/PluginManager.cs | 20 ++++++++++---------- 6 files changed, 41 insertions(+), 38 deletions(-) (limited to 'Emby.Server.Implementations/LiveTv') diff --git a/Emby.Server.Implementations/Library/LiveStreamHelper.cs b/Emby.Server.Implementations/Library/LiveStreamHelper.cs index 16b45161fd..83acd8e9f2 100644 --- a/Emby.Server.Implementations/Library/LiveStreamHelper.cs +++ b/Emby.Server.Implementations/Library/LiveStreamHelper.cs @@ -10,9 +10,9 @@ using System.Linq; using System.Text.Json; using System.Threading; using System.Threading.Tasks; +using Jellyfin.Extensions.Json; using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Extensions; -using Jellyfin.Extensions.Json; using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.Model.Dlna; using MediaBrowser.Model.Dto; diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs index 096b7f0454..2b82f24623 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs @@ -23,10 +23,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts { public abstract class BaseTunerHost { - protected readonly IServerConfigurationManager Config; - protected readonly ILogger Logger; - protected readonly IFileSystem FileSystem; - private readonly IMemoryCache _memoryCache; protected BaseTunerHost(IServerConfigurationManager config, ILogger logger, IFileSystem fileSystem, IMemoryCache memoryCache) @@ -37,12 +33,20 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts FileSystem = fileSystem; } - public virtual bool IsSupported => true; + protected IServerConfigurationManager Config { get; } - protected abstract Task> GetChannelsInternal(TunerHostInfo tuner, CancellationToken cancellationToken); + protected ILogger Logger { get; } + + protected IFileSystem FileSystem { get; } + + public virtual bool IsSupported => true; public abstract string Type { get; } + protected virtual string ChannelIdPrefix => Type + "_"; + + protected abstract Task> GetChannelsInternal(TunerHostInfo tuner, CancellationToken cancellationToken); + public async Task> GetChannels(TunerHostInfo tuner, bool enableCache, CancellationToken cancellationToken) { var key = tuner.Id; @@ -217,8 +221,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts throw new LiveTvConflictException(); } - protected virtual string ChannelIdPrefix => Type + "_"; - protected virtual bool IsValidChannelId(string channelId) { if (string.IsNullOrEmpty(channelId)) diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs index 6a2e7f6998..31445e1ecc 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs @@ -101,7 +101,8 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun } } - if (localAddress.IsIPv4MappedToIPv6) { + if (localAddress.IsIPv4MappedToIPv6) + { localAddress = localAddress.MapToIPv4(); } diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs index 817b1f8046..f024e49344 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs @@ -20,14 +20,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts { private readonly IConfigurationManager _configurationManager; - protected readonly IFileSystem FileSystem; - - protected readonly IStreamHelper StreamHelper; - - protected string TempFilePath; - protected readonly ILogger Logger; - protected readonly CancellationTokenSource LiveStreamCancellationTokenSource = new CancellationTokenSource(); - public LiveStream( MediaSourceInfo mediaSource, TunerHostInfo tuner, @@ -55,7 +47,15 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts SetTempFilePath("ts"); } - protected virtual int EmptyReadLimit => 1000; + protected IFileSystem FileSystem { get; } + + protected IStreamHelper StreamHelper { get; } + + protected ILogger Logger { get; } + + protected CancellationTokenSource LiveStreamCancellationTokenSource { get; } = new CancellationTokenSource(); + + protected string TempFilePath { get; set; } public MediaSourceInfo OriginalMediaSource { get; set; } diff --git a/Emby.Server.Implementations/Playlists/ManualPlaylistsFolder.cs b/Emby.Server.Implementations/Playlists/ManualPlaylistsFolder.cs index 4160f3a500..8b1cee89d1 100644 --- a/Emby.Server.Implementations/Playlists/ManualPlaylistsFolder.cs +++ b/Emby.Server.Implementations/Playlists/ManualPlaylistsFolder.cs @@ -17,6 +17,15 @@ namespace Emby.Server.Implementations.Playlists Name = "Playlists"; } + [JsonIgnore] + public override bool IsHidden => true; + + [JsonIgnore] + public override bool SupportsInheritedParentImages => false; + + [JsonIgnore] + public override string CollectionType => MediaBrowser.Model.Entities.CollectionType.Playlists; + public override bool IsVisible(User user) { return base.IsVisible(user) && GetChildren(user, true).Any(); @@ -27,15 +36,6 @@ namespace Emby.Server.Implementations.Playlists return base.GetEligibleChildrenForRecursiveChildren(user).OfType(); } - [JsonIgnore] - public override bool IsHidden => true; - - [JsonIgnore] - public override bool SupportsInheritedParentImages => false; - - [JsonIgnore] - public override string CollectionType => MediaBrowser.Model.Entities.CollectionType.Playlists; - protected override QueryResult GetItemsInternal(InternalItemsQuery query) { if (query.User == null) diff --git a/Emby.Server.Implementations/Plugins/PluginManager.cs b/Emby.Server.Implementations/Plugins/PluginManager.cs index b8e1dc2c05..d52c0b2a14 100644 --- a/Emby.Server.Implementations/Plugins/PluginManager.cs +++ b/Emby.Server.Implementations/Plugins/PluginManager.cs @@ -8,10 +8,10 @@ using System.Reflection; using System.Text; using System.Text.Json; using System.Threading.Tasks; -using MediaBrowser.Common; -using MediaBrowser.Common.Extensions; using Jellyfin.Extensions.Json; using Jellyfin.Extensions.Json.Converters; +using MediaBrowser.Common; +using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Net; using MediaBrowser.Common.Plugins; using MediaBrowser.Model.Configuration; @@ -39,14 +39,6 @@ namespace Emby.Server.Implementations.Plugins private IHttpClientFactory? _httpClientFactory; - private IHttpClientFactory HttpClientFactory - { - get - { - return _httpClientFactory ?? (_httpClientFactory = _appHost.Resolve()); - } - } - /// /// Initializes a new instance of the class. /// @@ -86,6 +78,14 @@ namespace Emby.Server.Implementations.Plugins _plugins = Directory.Exists(_pluginsPath) ? DiscoverPlugins().ToList() : new List(); } + private IHttpClientFactory HttpClientFactory + { + get + { + return _httpClientFactory ??= _appHost.Resolve(); + } + } + /// /// Gets the Plugins. /// -- cgit v1.2.3 From 1ee58bf0200986cbddcab8ce9fd4fa930bee84e1 Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Fri, 1 Oct 2021 11:21:22 +0200 Subject: Enable nullable for ItemDataProvider --- .../LiveTv/EmbyTV/ItemDataProvider.cs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'Emby.Server.Implementations/LiveTv') diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs index 4a031e4752..46979bfc57 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs @@ -1,9 +1,8 @@ -#nullable disable - #pragma warning disable CS1591 using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; using System.Text.Json; @@ -18,7 +17,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV private readonly string _dataPath; private readonly object _fileDataLock = new object(); private readonly JsonSerializerOptions _jsonOptions = JsonDefaults.Options; - private T[] _items; + private T[]? _items; public ItemDataProvider( ILogger logger, @@ -34,6 +33,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV protected Func EqualityComparer { get; } + [MemberNotNull(nameof(_items))] private void EnsureLoaded() { if (_items != null) @@ -49,6 +49,12 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV { var bytes = File.ReadAllBytes(_dataPath); _items = JsonSerializer.Deserialize(bytes, _jsonOptions); + if (_items == null) + { + Logger.LogError("Error deserializing {Path}, data was null", _dataPath); + _items = Array.Empty(); + } + return; } catch (JsonException ex) @@ -62,7 +68,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV private void SaveList() { - Directory.CreateDirectory(Path.GetDirectoryName(_dataPath)); + Directory.CreateDirectory(Path.GetDirectoryName(_dataPath) ?? throw new ArgumentException("Path can't be a root directory.", nameof(_dataPath))); var jsonString = JsonSerializer.Serialize(_items, _jsonOptions); File.WriteAllText(_dataPath, jsonString); } -- cgit v1.2.3 From 9af16fcb6c892238b734c267873b1fc137d38e66 Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Sun, 3 Oct 2021 19:52:38 +0200 Subject: Remove workaround for dotnet/runtime#42790 --- Emby.Dlna/DlnaManager.cs | 9 ++++--- Emby.Drawing/ImageProcessor.cs | 2 +- .../AppBase/ConfigurationHelper.cs | 9 +++---- .../LiveTv/EmbyTV/DirectRecorder.cs | 6 ++--- .../LiveTv/EmbyTV/EmbyTV.cs | 12 +++------ .../LiveTv/EmbyTV/EncodedRecorder.cs | 2 +- Jellyfin.Api/Controllers/RemoteImageController.cs | 31 ---------------------- MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs | 12 +++++++-- .../Subtitles/SubtitleEncoder.cs | 1 - MediaBrowser.Model/IO/AsyncFile.cs | 19 +++++++++++++ MediaBrowser.Providers/Manager/ImageSaver.cs | 6 +++-- .../Manager/ItemImageProvider.cs | 2 +- MediaBrowser.Providers/Manager/ProviderManager.cs | 3 +-- .../Plugins/AudioDb/AudioDbAlbumProvider.cs | 7 +++-- .../Plugins/AudioDb/AudioDbArtistProvider.cs | 6 +++-- .../Studios/StudiosImageProvider.cs | 7 ++--- .../Subtitles/SubtitleManager.cs | 6 +++-- MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs | 11 ++++++-- 18 files changed, 77 insertions(+), 74 deletions(-) (limited to 'Emby.Server.Implementations/LiveTv') diff --git a/Emby.Dlna/DlnaManager.cs b/Emby.Dlna/DlnaManager.cs index 8fe9d484e7..73e8a0008e 100644 --- a/Emby.Dlna/DlnaManager.cs +++ b/Emby.Dlna/DlnaManager.cs @@ -359,14 +359,17 @@ namespace Emby.Dlna // The stream should exist as we just got its name from GetManifestResourceNames using (var stream = _assembly.GetManifestResourceStream(name)!) { + var length = stream.Length; var fileInfo = _fileSystem.GetFileInfo(path); - if (!fileInfo.Exists || fileInfo.Length != stream.Length) + if (!fileInfo.Exists || fileInfo.Length != length) { Directory.CreateDirectory(systemProfilesPath); - // use FileShare.None as this bypasses dotnet bug dotnet/runtime#42790 . - using (var fileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous)) + var fileOptions = AsyncFile.WriteOptions; + fileOptions.Mode = FileMode.CreateNew; + fileOptions.PreallocationSize = length; + using (var fileStream = new FileStream(path, fileOptions)) { await stream.CopyToAsync(fileStream).ConfigureAwait(false); } diff --git a/Emby.Drawing/ImageProcessor.cs b/Emby.Drawing/ImageProcessor.cs index 9b130fdfd8..ac73cfa421 100644 --- a/Emby.Drawing/ImageProcessor.cs +++ b/Emby.Drawing/ImageProcessor.cs @@ -102,7 +102,7 @@ namespace Emby.Drawing { var file = await ProcessImage(options).ConfigureAwait(false); - using (var fileStream = new FileStream(file.Item1, FileMode.Open, FileAccess.Read, FileShare.Read, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous)) + using (var fileStream = AsyncFile.OpenRead(file.Item1)) { await fileStream.CopyToAsync(toStream).ConfigureAwait(false); } diff --git a/Emby.Server.Implementations/AppBase/ConfigurationHelper.cs b/Emby.Server.Implementations/AppBase/ConfigurationHelper.cs index 0308a68e42..3a916e5c01 100644 --- a/Emby.Server.Implementations/AppBase/ConfigurationHelper.cs +++ b/Emby.Server.Implementations/AppBase/ConfigurationHelper.cs @@ -41,20 +41,19 @@ namespace Emby.Server.Implementations.AppBase xmlSerializer.SerializeToStream(configuration, stream); // Take the object we just got and serialize it back to bytes - byte[] newBytes = stream.GetBuffer(); - int newBytesLen = (int)stream.Length; + Span newBytes = stream.GetBuffer().AsSpan(0, (int)stream.Length); // If the file didn't exist before, or if something has changed, re-save - if (buffer == null || !newBytes.AsSpan(0, newBytesLen).SequenceEqual(buffer)) + if (buffer == null || !newBytes.SequenceEqual(buffer)) { var directory = Path.GetDirectoryName(path) ?? throw new ArgumentException($"Provided path ({path}) is not valid.", nameof(path)); Directory.CreateDirectory(directory); + // Save it after load in case we got new items - // use FileShare.None as this bypasses dotnet bug dotnet/runtime#42790 . using (var fs = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None)) { - fs.Write(newBytes, 0, newBytesLen); + fs.Write(newBytes); } } diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs index 41381d55bd..6937cc0971 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs @@ -46,8 +46,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV { Directory.CreateDirectory(Path.GetDirectoryName(targetFile) ?? throw new ArgumentException("Path can't be a root directory.", nameof(targetFile))); - // use FileShare.None as this bypasses dotnet bug dotnet/runtime#42790 . - using (var output = new FileStream(targetFile, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous)) + using (var output = new FileStream(targetFile, FileMode.CreateNew, FileAccess.Write, FileShare.Read, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous)) { onStarted(); @@ -79,8 +78,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV Directory.CreateDirectory(Path.GetDirectoryName(targetFile) ?? throw new ArgumentException("Path can't be a root directory.", nameof(targetFile))); - // use FileShare.None as this bypasses dotnet bug dotnet/runtime#42790 . - await using var output = new FileStream(targetFile, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.CopyToBufferSize, FileOptions.Asynchronous); + await using var output = new FileStream(targetFile, FileMode.CreateNew, FileAccess.Write, FileShare.Read, IODefaults.CopyToBufferSize, FileOptions.Asynchronous); onStarted(); diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index 64e54aa99e..980b42729a 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -1848,14 +1848,12 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV return; } - // use FileShare.None as this bypasses dotnet bug dotnet/runtime#42790 . - using (var stream = new FileStream(nfoPath, FileMode.Create, FileAccess.Write, FileShare.None)) + using (var stream = new FileStream(nfoPath, FileMode.CreateNew, FileAccess.Write, FileShare.None)) { var settings = new XmlWriterSettings { Indent = true, - Encoding = Encoding.UTF8, - CloseOutput = false + Encoding = Encoding.UTF8 }; using (var writer = XmlWriter.Create(stream, settings)) @@ -1913,14 +1911,12 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV return; } - // use FileShare.None as this bypasses dotnet bug dotnet/runtime#42790 . - using (var stream = new FileStream(nfoPath, FileMode.Create, FileAccess.Write, FileShare.None)) + using (var stream = new FileStream(nfoPath, FileMode.CreateNew, FileAccess.Write, FileShare.None)) { var settings = new XmlWriterSettings { Indent = true, - Encoding = Encoding.UTF8, - CloseOutput = false + Encoding = Encoding.UTF8 }; var options = _config.GetNfoConfiguration(); diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs index 3633fa3e10..016a3e83fa 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs @@ -94,7 +94,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV Directory.CreateDirectory(Path.GetDirectoryName(logFilePath)); // FFMpeg writes debug/error info to stderr. This is useful when debugging so let's put it in the log directory. - _logFileStream = new FileStream(logFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous); + _logFileStream = new FileStream(logFilePath, FileMode.CreateNew, FileAccess.Write, FileShare.Read, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous); await JsonSerializer.SerializeAsync(_logFileStream, mediaSource, _jsonOptions, cancellationToken).ConfigureAwait(false); await _logFileStream.WriteAsync(Encoding.UTF8.GetBytes(Environment.NewLine + Environment.NewLine + commandLineLogMessage + Environment.NewLine + Environment.NewLine), cancellationToken).ConfigureAwait(false); diff --git a/Jellyfin.Api/Controllers/RemoteImageController.cs b/Jellyfin.Api/Controllers/RemoteImageController.cs index 8a33b12f4c..35921ede8f 100644 --- a/Jellyfin.Api/Controllers/RemoteImageController.cs +++ b/Jellyfin.Api/Controllers/RemoteImageController.cs @@ -183,36 +183,5 @@ namespace Jellyfin.Api.Controllers { return Path.Combine(_applicationPaths.CachePath, "remote-images", filename.Substring(0, 1), filename); } - - /// - /// Downloads the image. - /// - /// The URL. - /// The URL hash. - /// The pointer cache path. - /// Task. - private async Task DownloadImage(Uri url, Guid urlHash, string pointerCachePath) - { - var httpClient = _httpClientFactory.CreateClient(NamedClient.Default); - using var response = await httpClient.GetAsync(url).ConfigureAwait(false); - if (response.Content.Headers.ContentType?.MediaType == null) - { - throw new ResourceNotFoundException(nameof(response.Content.Headers.ContentType)); - } - - var ext = response.Content.Headers.ContentType.MediaType.AsSpan().RightPart('/').ToString(); - var fullCachePath = GetFullCachePath(urlHash + "." + ext); - - var fullCacheDirectory = Path.GetDirectoryName(fullCachePath) ?? throw new ResourceNotFoundException($"Provided path ({fullCachePath}) is not valid."); - Directory.CreateDirectory(fullCacheDirectory); - // use FileShare.None as this bypasses dotnet bug dotnet/runtime#42790 . - await using var fileStream = new FileStream(fullCachePath, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous); - await response.Content.CopyToAsync(fileStream).ConfigureAwait(false); - - var pointerCacheDirectory = Path.GetDirectoryName(pointerCachePath) ?? throw new ArgumentException($"Provided path ({pointerCachePath}) is not valid.", nameof(pointerCachePath)); - Directory.CreateDirectory(pointerCacheDirectory); - await System.IO.File.WriteAllTextAsync(pointerCachePath, fullCachePath, CancellationToken.None) - .ConfigureAwait(false); - } } } diff --git a/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs b/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs index 6f66fd61b0..5e7af23fc3 100644 --- a/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs +++ b/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs @@ -113,11 +113,19 @@ namespace MediaBrowser.LocalMetadata.Savers { var directory = Path.GetDirectoryName(path) ?? throw new ArgumentException($"Provided path ({path}) is not valid.", nameof(path)); Directory.CreateDirectory(directory); + // On Windows, savint the file will fail if the file is hidden or readonly FileSystem.SetAttributes(path, false, false); - // use FileShare.None as this bypasses dotnet bug dotnet/runtime#42790 . - using (var filestream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None)) + var fileStreamOptions = new FileStreamOptions() + { + Mode = FileMode.Create, + Access = FileAccess.Write, + Share = FileShare.None, + PreallocationSize = stream.Length + }; + + using (var filestream = new FileStream(path, fileStreamOptions)) { stream.CopyTo(filestream); } diff --git a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs index 022cdbe9d3..bfc17904cd 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs @@ -679,7 +679,6 @@ namespace MediaBrowser.MediaEncoding.Subtitles if (!string.Equals(text, newText, StringComparison.Ordinal)) { - // use FileShare.None as this bypasses dotnet bug dotnet/runtime#42790 . using (var fileStream = new FileStream(file, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous)) using (var writer = new StreamWriter(fileStream, encoding)) { diff --git a/MediaBrowser.Model/IO/AsyncFile.cs b/MediaBrowser.Model/IO/AsyncFile.cs index caee9c5289..3c8007d1c4 100644 --- a/MediaBrowser.Model/IO/AsyncFile.cs +++ b/MediaBrowser.Model/IO/AsyncFile.cs @@ -7,6 +7,25 @@ namespace MediaBrowser.Model.IO /// public static class AsyncFile { + /// + /// Gets the default for reading files async. + /// + public static FileStreamOptions ReadOptions => new FileStreamOptions() + { + Options = FileOptions.Asynchronous + }; + + /// + /// Gets the default for writing files async. + /// + public static FileStreamOptions WriteOptions => new FileStreamOptions() + { + Mode = FileMode.OpenOrCreate, + Access = FileAccess.Write, + Share = FileShare.None, + Options = FileOptions.Asynchronous + }; + /// /// Opens an existing file for reading. /// diff --git a/MediaBrowser.Providers/Manager/ImageSaver.cs b/MediaBrowser.Providers/Manager/ImageSaver.cs index 4b05edd67b..3d8dd14860 100644 --- a/MediaBrowser.Providers/Manager/ImageSaver.cs +++ b/MediaBrowser.Providers/Manager/ImageSaver.cs @@ -261,8 +261,10 @@ namespace MediaBrowser.Providers.Manager _fileSystem.SetAttributes(path, false, false); - // use FileShare.None as this bypasses dotnet bug dotnet/runtime#42790 . - await using (var fs = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous)) + var fileStreamOptions = AsyncFile.WriteOptions; + fileStreamOptions.Mode = FileMode.Create; + fileStreamOptions.PreallocationSize = source.Length; + await using (var fs = new FileStream(path, fileStreamOptions)) { await source.CopyToAsync(fs, cancellationToken).ConfigureAwait(false); } diff --git a/MediaBrowser.Providers/Manager/ItemImageProvider.cs b/MediaBrowser.Providers/Manager/ItemImageProvider.cs index 73bca5aa59..3593697d7e 100644 --- a/MediaBrowser.Providers/Manager/ItemImageProvider.cs +++ b/MediaBrowser.Providers/Manager/ItemImageProvider.cs @@ -163,7 +163,7 @@ namespace MediaBrowser.Providers.Manager { var mimeType = MimeTypes.GetMimeType(response.Path); - var stream = new FileStream(response.Path, FileMode.Open, FileAccess.Read, FileShare.Read, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous); + var stream = AsyncFile.OpenRead(response.Path); await _providerManager.SaveImage(item, stream, mimeType, imageType, null, cancellationToken).ConfigureAwait(false); } diff --git a/MediaBrowser.Providers/Manager/ProviderManager.cs b/MediaBrowser.Providers/Manager/ProviderManager.cs index b51a254172..9be887e9c3 100644 --- a/MediaBrowser.Providers/Manager/ProviderManager.cs +++ b/MediaBrowser.Providers/Manager/ProviderManager.cs @@ -210,8 +210,7 @@ namespace MediaBrowser.Providers.Manager throw new ArgumentNullException(nameof(source)); } - var fileStream = new FileStream(source, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); - + var fileStream = AsyncFile.OpenRead(source); return new ImageSaver(_configurationManager, _libraryMonitor, _fileSystem, _logger).SaveImage(item, fileStream, mimeType, type, imageIndex, saveLocallyWithMedia, cancellationToken); } diff --git a/MediaBrowser.Providers/Plugins/AudioDb/AudioDbAlbumProvider.cs b/MediaBrowser.Providers/Plugins/AudioDb/AudioDbAlbumProvider.cs index 3e0b0014eb..ebdcb94eb6 100644 --- a/MediaBrowser.Providers/Plugins/AudioDb/AudioDbAlbumProvider.cs +++ b/MediaBrowser.Providers/Plugins/AudioDb/AudioDbAlbumProvider.cs @@ -172,8 +172,11 @@ namespace MediaBrowser.Providers.Plugins.AudioDb using var response = await _httpClientFactory.CreateClient(NamedClient.Default).GetAsync(url, cancellationToken).ConfigureAwait(false); await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); - // use FileShare.None as this bypasses dotnet bug dotnet/runtime#42790 . - await using var xmlFileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous); + + var fileStreamOptions = AsyncFile.WriteOptions; + fileStreamOptions.Mode = FileMode.Create; + fileStreamOptions.PreallocationSize = stream.Length; + await using var xmlFileStream = new FileStream(path, fileStreamOptions); await stream.CopyToAsync(xmlFileStream, cancellationToken).ConfigureAwait(false); } diff --git a/MediaBrowser.Providers/Plugins/AudioDb/AudioDbArtistProvider.cs b/MediaBrowser.Providers/Plugins/AudioDb/AudioDbArtistProvider.cs index e0b2f9c588..321013b17c 100644 --- a/MediaBrowser.Providers/Plugins/AudioDb/AudioDbArtistProvider.cs +++ b/MediaBrowser.Providers/Plugins/AudioDb/AudioDbArtistProvider.cs @@ -154,8 +154,10 @@ namespace MediaBrowser.Providers.Plugins.AudioDb Directory.CreateDirectory(Path.GetDirectoryName(path)); - // use FileShare.None as this bypasses dotnet bug dotnet/runtime#42790 . - await using var xmlFileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous); + var fileStreamOptions = AsyncFile.WriteOptions; + fileStreamOptions.Mode = FileMode.Create; + fileStreamOptions.PreallocationSize = stream.Length; + await using var xmlFileStream = new FileStream(path, fileStreamOptions); await stream.CopyToAsync(xmlFileStream, cancellationToken).ConfigureAwait(false); } diff --git a/MediaBrowser.Providers/Studios/StudiosImageProvider.cs b/MediaBrowser.Providers/Studios/StudiosImageProvider.cs index 7b2454efc9..a1873eaae4 100644 --- a/MediaBrowser.Providers/Studios/StudiosImageProvider.cs +++ b/MediaBrowser.Providers/Studios/StudiosImageProvider.cs @@ -172,19 +172,16 @@ namespace MediaBrowser.Providers.Studios public IEnumerable GetAvailableImages(string file) { - using var fileStream = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.Read); + using var fileStream = File.OpenRead(file); using var reader = new StreamReader(fileStream); - var lines = new List(); foreach (var line in reader.ReadAllLines()) { if (!string.IsNullOrWhiteSpace(line)) { - lines.Add(line); + yield return line; } } - - return lines; } } } diff --git a/MediaBrowser.Providers/Subtitles/SubtitleManager.cs b/MediaBrowser.Providers/Subtitles/SubtitleManager.cs index 772e617abb..e625b0dd2a 100644 --- a/MediaBrowser.Providers/Subtitles/SubtitleManager.cs +++ b/MediaBrowser.Providers/Subtitles/SubtitleManager.cs @@ -244,8 +244,10 @@ namespace MediaBrowser.Providers.Subtitles { Directory.CreateDirectory(Path.GetDirectoryName(savePath)); - // use FileShare.None as this bypasses dotnet bug dotnet/runtime#42790 . - using var fs = new FileStream(savePath, FileMode.Create, FileAccess.Write, FileShare.None, FileStreamBufferSize, FileOptions.Asynchronous); + var fileOptions = AsyncFile.WriteOptions; + fileOptions.Mode = FileMode.CreateNew; + fileOptions.PreallocationSize = stream.Length; + using var fs = new FileStream(savePath, fileOptions); await stream.CopyToAsync(fs).ConfigureAwait(false); return; diff --git a/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs b/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs index 38726a6f08..594402258a 100644 --- a/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs +++ b/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs @@ -203,8 +203,15 @@ namespace MediaBrowser.XbmcMetadata.Savers // On Windows, saving the file will fail if the file is hidden or readonly FileSystem.SetAttributes(path, false, false); - // use FileShare.None as this bypasses dotnet bug dotnet/runtime#42790 . - using (var filestream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None)) + var fileStreamOptions = new FileStreamOptions() + { + Mode = FileMode.Create, + Access = FileAccess.Write, + Share = FileShare.None, + PreallocationSize = stream.Length + }; + + using (var filestream = new FileStream(path, fileStreamOptions)) { stream.CopyTo(filestream); } -- cgit v1.2.3 From 232e48f5e819afd690069e31f0ec54854292a921 Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Sat, 2 Oct 2021 14:15:33 -0400 Subject: Fix warnings in EmbyTV --- Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs | 4 ++-- Emby.Server.Implementations/LiveTv/EmbyTV/IRecorder.cs | 7 +++++++ 2 files changed, 9 insertions(+), 2 deletions(-) (limited to 'Emby.Server.Implementations/LiveTv') diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs index 3633fa3e10..3060bf2703 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs @@ -205,9 +205,9 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV // var audioChannels = 2; // var audioStream = mediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Audio); // if (audioStream != null) - //{ + // { // audioChannels = audioStream.Channels ?? audioChannels; - //} + // } // return "-codec:a:0 aac -strict experimental -ab 320000"; } diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/IRecorder.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/IRecorder.cs index dfe3517b22..7705132da2 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/IRecorder.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/IRecorder.cs @@ -13,6 +13,13 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV /// /// Records the specified media source. /// + /// The direct stream provider, or null. + /// The media source. + /// The target file. + /// The duration to record. + /// An action to perform when recording starts. + /// The cancellation token. + /// A that represents the recording operation. Task Record(IDirectStreamProvider? directStreamProvider, MediaSourceInfo mediaSource, string targetFile, TimeSpan duration, Action onStarted, CancellationToken cancellationToken); string GetOutputPath(MediaSourceInfo mediaSource, string targetFile); -- cgit v1.2.3 From 03f933aaa07113b0ae6971921249691c8455d5ba Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Wed, 6 Oct 2021 11:30:45 +0200 Subject: Fix the last few warnings Enables TreatWarningsAsErrors for all projects --- Emby.Server.Implementations/ApplicationHost.cs | 38 +++----- .../Data/BaseSqliteRepository.cs | 2 +- .../Emby.Server.Implementations.csproj | 5 -- .../Images/BaseDynamicImageProvider.cs | 4 +- .../Images/BaseFolderImageProvider.cs | 67 ++++++++++++++ .../Images/FolderImageProvider.cs | 69 -------------- .../Images/GenreImageProvider.cs | 41 --------- .../Images/MusicAlbumImageProvider.cs | 19 ++++ .../Images/MusicGenreImageProvider.cs | 59 ++++++++++++ .../Images/PhotoAlbumImageProvider.cs | 19 ++++ .../Library/Resolvers/FolderResolver.cs | 22 +---- .../Library/Resolvers/GenericFolderResolver.cs | 27 ++++++ .../Library/Resolvers/Movies/BoxSetResolver.cs | 2 +- .../Library/Resolvers/PhotoAlbumResolver.cs | 2 +- .../Library/Resolvers/PlaylistResolver.cs | 2 +- .../Library/Resolvers/SpecialFolderResolver.cs | 2 +- .../Library/Resolvers/TV/SeasonResolver.cs | 2 +- .../Library/Resolvers/TV/SeriesResolver.cs | 2 +- .../Listings/SchedulesDirectDtos/ImageDataDto.cs | 2 +- .../Listings/SchedulesDirectDtos/StationDto.cs | 100 ++++++++++----------- .../HdHomerun/HdHomerunChannelCommands.cs | 35 ++++++++ .../LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs | 10 +-- .../TunerHosts/HdHomerun/HdHomerunManager.cs | 66 -------------- .../HdHomerun/IHdHomerunChannelCommands.cs | 11 +++ .../HdHomerun/LegacyHdHomerunChannelCommands.cs | 38 ++++++++ .../MediaBrowser.Controller.csproj | 5 -- MediaBrowser.Model/MediaBrowser.Model.csproj | 5 -- 27 files changed, 353 insertions(+), 303 deletions(-) create mode 100644 Emby.Server.Implementations/Images/BaseFolderImageProvider.cs create mode 100644 Emby.Server.Implementations/Images/MusicAlbumImageProvider.cs create mode 100644 Emby.Server.Implementations/Images/MusicGenreImageProvider.cs create mode 100644 Emby.Server.Implementations/Images/PhotoAlbumImageProvider.cs create mode 100644 Emby.Server.Implementations/Library/Resolvers/GenericFolderResolver.cs create mode 100644 Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunChannelCommands.cs create mode 100644 Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/IHdHomerunChannelCommands.cs create mode 100644 Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/LegacyHdHomerunChannelCommands.cs (limited to 'Emby.Server.Implementations/LiveTv') diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index 3a504d2f43..1f11bdad74 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -306,7 +306,7 @@ namespace Emby.Server.Implementations /// public string Name => ApplicationProductName; - private CertificateInfo CertificateInfo { get; set; } + private string CertificatePath { get; set; } public X509Certificate2 Certificate { get; private set; } @@ -548,12 +548,8 @@ namespace Emby.Server.Implementations HttpsPort = NetworkConfiguration.DefaultHttpsPort; } - CertificateInfo = new CertificateInfo - { - Path = networkConfiguration.CertificatePath, - Password = networkConfiguration.CertificatePassword - }; - Certificate = GetCertificate(CertificateInfo); + CertificatePath = networkConfiguration.CertificatePath; + Certificate = GetCertificate(CertificatePath, networkConfiguration.CertificatePassword); RegisterServices(); @@ -729,30 +725,27 @@ namespace Emby.Server.Implementations logger.LogInformation("Application directory: {ApplicationPath}", appPaths.ProgramSystemPath); } - private X509Certificate2 GetCertificate(CertificateInfo info) + private X509Certificate2 GetCertificate(string path, string password) { - var certificateLocation = info?.Path; - - if (string.IsNullOrWhiteSpace(certificateLocation)) + if (string.IsNullOrWhiteSpace(path)) { return null; } try { - if (!File.Exists(certificateLocation)) + if (!File.Exists(path)) { return null; } // Don't use an empty string password - var password = string.IsNullOrWhiteSpace(info.Password) ? null : info.Password; + password = string.IsNullOrWhiteSpace(password) ? null : password; - var localCert = new X509Certificate2(certificateLocation, password, X509KeyStorageFlags.UserKeySet); - // localCert.PrivateKey = PrivateKey.CreateFromFile(pvk_file).RSA; + var localCert = new X509Certificate2(path, password, X509KeyStorageFlags.UserKeySet); if (!localCert.HasPrivateKey) { - Logger.LogError("No private key included in SSL cert {CertificateLocation}.", certificateLocation); + Logger.LogError("No private key included in SSL cert {CertificateLocation}.", path); return null; } @@ -760,7 +753,7 @@ namespace Emby.Server.Implementations } catch (Exception ex) { - Logger.LogError(ex, "Error loading cert from {CertificateLocation}", certificateLocation); + Logger.LogError(ex, "Error loading cert from {CertificateLocation}", path); return null; } } @@ -882,7 +875,7 @@ namespace Emby.Server.Implementations "http://" + i + ":" + HttpPort + "/" }; - if (CertificateInfo != null) + if (Certificate != null) { prefixes.Add("https://" + i + ":" + HttpsPort + "/"); } @@ -946,7 +939,7 @@ namespace Emby.Server.Implementations var newPath = networkConfig.CertificatePath; if (!string.IsNullOrWhiteSpace(newPath) - && !string.Equals(CertificateInfo?.Path, newPath, StringComparison.Ordinal)) + && !string.Equals(CertificatePath, newPath, StringComparison.Ordinal)) { if (File.Exists(newPath)) { @@ -1293,11 +1286,4 @@ namespace Emby.Server.Implementations _disposed = true; } } - - internal class CertificateInfo - { - public string Path { get; set; } - - public string Password { get; set; } - } } diff --git a/Emby.Server.Implementations/Data/BaseSqliteRepository.cs b/Emby.Server.Implementations/Data/BaseSqliteRepository.cs index 4f6c811028..73c31f49d1 100644 --- a/Emby.Server.Implementations/Data/BaseSqliteRepository.cs +++ b/Emby.Server.Implementations/Data/BaseSqliteRepository.cs @@ -98,7 +98,7 @@ namespace Emby.Server.Implementations.Data /// The write connection. protected SQLiteDatabaseConnection WriteConnection { get; set; } - protected ManagedConnection GetConnection(bool _ = false) + protected ManagedConnection GetConnection(bool readOnly = false) { WriteLock.Wait(); if (WriteConnection != null) diff --git a/Emby.Server.Implementations/Emby.Server.Implementations.csproj b/Emby.Server.Implementations/Emby.Server.Implementations.csproj index 428cad0715..82e4c3d697 100644 --- a/Emby.Server.Implementations/Emby.Server.Implementations.csproj +++ b/Emby.Server.Implementations/Emby.Server.Implementations.csproj @@ -47,11 +47,6 @@ true AD0001 - false - - - - true diff --git a/Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs b/Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs index 4a026fd218..7589869457 100644 --- a/Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs +++ b/Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs @@ -65,13 +65,13 @@ namespace Emby.Server.Implementations.Images if (SupportedImages.Contains(ImageType.Primary)) { var primaryResult = await FetchAsync(item, ImageType.Primary, options, cancellationToken).ConfigureAwait(false); - updateType = updateType | primaryResult; + updateType |= primaryResult; } if (SupportedImages.Contains(ImageType.Thumb)) { var thumbResult = await FetchAsync(item, ImageType.Thumb, options, cancellationToken).ConfigureAwait(false); - updateType = updateType | thumbResult; + updateType |= thumbResult; } return updateType; diff --git a/Emby.Server.Implementations/Images/BaseFolderImageProvider.cs b/Emby.Server.Implementations/Images/BaseFolderImageProvider.cs new file mode 100644 index 0000000000..1c69056d20 --- /dev/null +++ b/Emby.Server.Implementations/Images/BaseFolderImageProvider.cs @@ -0,0 +1,67 @@ +#nullable disable + +#pragma warning disable CS1591 + +using System.Collections.Generic; +using Jellyfin.Data.Enums; +using MediaBrowser.Common.Configuration; +using MediaBrowser.Controller.Drawing; +using MediaBrowser.Controller.Dto; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities.Audio; +using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Providers; +using MediaBrowser.Model.Entities; +using MediaBrowser.Model.IO; +using MediaBrowser.Model.Querying; + +namespace Emby.Server.Implementations.Images +{ + public abstract class BaseFolderImageProvider : BaseDynamicImageProvider + where T : Folder, new() + { + private readonly ILibraryManager _libraryManager; + + public BaseFolderImageProvider(IFileSystem fileSystem, IProviderManager providerManager, IApplicationPaths applicationPaths, IImageProcessor imageProcessor, ILibraryManager libraryManager) + : base(fileSystem, providerManager, applicationPaths, imageProcessor) + { + _libraryManager = libraryManager; + } + + protected override IReadOnlyList GetItemsWithImages(BaseItem item) + { + return _libraryManager.GetItemList(new InternalItemsQuery + { + Parent = item, + DtoOptions = new DtoOptions(true), + ImageTypes = new ImageType[] { ImageType.Primary }, + OrderBy = new (string, SortOrder)[] + { + (ItemSortBy.IsFolder, SortOrder.Ascending), + (ItemSortBy.SortName, SortOrder.Ascending) + }, + Limit = 1 + }); + } + + protected override string CreateImage(BaseItem item, IReadOnlyCollection itemsWithImages, string outputPathWithoutExtension, ImageType imageType, int imageIndex) + { + return CreateSingleImage(itemsWithImages, outputPathWithoutExtension, ImageType.Primary); + } + + protected override bool Supports(BaseItem item) + { + return item is T; + } + + protected override bool HasChangedByDate(BaseItem item, ItemImageInfo image) + { + if (item is MusicAlbum) + { + return false; + } + + return base.HasChangedByDate(item, image); + } + } +} diff --git a/Emby.Server.Implementations/Images/FolderImageProvider.cs b/Emby.Server.Implementations/Images/FolderImageProvider.cs index 859017f869..4376bd356c 100644 --- a/Emby.Server.Implementations/Images/FolderImageProvider.cs +++ b/Emby.Server.Implementations/Images/FolderImageProvider.cs @@ -2,69 +2,16 @@ #pragma warning disable CS1591 -using System.Collections.Generic; -using Jellyfin.Data.Enums; using MediaBrowser.Common.Configuration; using MediaBrowser.Controller.Drawing; -using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Providers; -using MediaBrowser.Model.Entities; using MediaBrowser.Model.IO; -using MediaBrowser.Model.Querying; namespace Emby.Server.Implementations.Images { - public abstract class BaseFolderImageProvider : BaseDynamicImageProvider - where T : Folder, new() - { - protected ILibraryManager _libraryManager; - - public BaseFolderImageProvider(IFileSystem fileSystem, IProviderManager providerManager, IApplicationPaths applicationPaths, IImageProcessor imageProcessor, ILibraryManager libraryManager) - : base(fileSystem, providerManager, applicationPaths, imageProcessor) - { - _libraryManager = libraryManager; - } - - protected override IReadOnlyList GetItemsWithImages(BaseItem item) - { - return _libraryManager.GetItemList(new InternalItemsQuery - { - Parent = item, - DtoOptions = new DtoOptions(true), - ImageTypes = new ImageType[] { ImageType.Primary }, - OrderBy = new System.ValueTuple[] - { - new System.ValueTuple(ItemSortBy.IsFolder, SortOrder.Ascending), - new System.ValueTuple(ItemSortBy.SortName, SortOrder.Ascending) - }, - Limit = 1 - }); - } - - protected override string CreateImage(BaseItem item, IReadOnlyCollection itemsWithImages, string outputPathWithoutExtension, ImageType imageType, int imageIndex) - { - return CreateSingleImage(itemsWithImages, outputPathWithoutExtension, ImageType.Primary); - } - - protected override bool Supports(BaseItem item) - { - return item is T; - } - - protected override bool HasChangedByDate(BaseItem item, ItemImageInfo image) - { - if (item is MusicAlbum) - { - return false; - } - - return base.HasChangedByDate(item, image); - } - } - public class FolderImageProvider : BaseFolderImageProvider { public FolderImageProvider(IFileSystem fileSystem, IProviderManager providerManager, IApplicationPaths applicationPaths, IImageProcessor imageProcessor, ILibraryManager libraryManager) @@ -87,20 +34,4 @@ namespace Emby.Server.Implementations.Images return true; } } - - public class MusicAlbumImageProvider : BaseFolderImageProvider - { - public MusicAlbumImageProvider(IFileSystem fileSystem, IProviderManager providerManager, IApplicationPaths applicationPaths, IImageProcessor imageProcessor, ILibraryManager libraryManager) - : base(fileSystem, providerManager, applicationPaths, imageProcessor, libraryManager) - { - } - } - - public class PhotoAlbumImageProvider : BaseFolderImageProvider - { - public PhotoAlbumImageProvider(IFileSystem fileSystem, IProviderManager providerManager, IApplicationPaths applicationPaths, IImageProcessor imageProcessor, ILibraryManager libraryManager) - : base(fileSystem, providerManager, applicationPaths, imageProcessor, libraryManager) - { - } - } } diff --git a/Emby.Server.Implementations/Images/GenreImageProvider.cs b/Emby.Server.Implementations/Images/GenreImageProvider.cs index 6da431c68e..1f5090f7f5 100644 --- a/Emby.Server.Implementations/Images/GenreImageProvider.cs +++ b/Emby.Server.Implementations/Images/GenreImageProvider.cs @@ -8,7 +8,6 @@ using MediaBrowser.Common.Configuration; using MediaBrowser.Controller.Drawing; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Library; @@ -19,46 +18,6 @@ using MediaBrowser.Model.Querying; namespace Emby.Server.Implementations.Images { - /// - /// Class MusicGenreImageProvider. - /// - public class MusicGenreImageProvider : BaseDynamicImageProvider - { - /// - /// The library manager. - /// - private readonly ILibraryManager _libraryManager; - - public MusicGenreImageProvider(IFileSystem fileSystem, IProviderManager providerManager, IApplicationPaths applicationPaths, IImageProcessor imageProcessor, ILibraryManager libraryManager) : base(fileSystem, providerManager, applicationPaths, imageProcessor) - { - _libraryManager = libraryManager; - } - - /// - /// Get children objects used to create an music genre image. - /// - /// The music genre used to create the image. - /// Any relevant children objects. - protected override IReadOnlyList GetItemsWithImages(BaseItem item) - { - return _libraryManager.GetItemList(new InternalItemsQuery - { - Genres = new[] { item.Name }, - IncludeItemTypes = new[] - { - nameof(MusicAlbum), - nameof(MusicVideo), - nameof(Audio) - }, - OrderBy = new[] { (ItemSortBy.Random, SortOrder.Ascending) }, - Limit = 4, - Recursive = true, - ImageTypes = new[] { ImageType.Primary }, - DtoOptions = new DtoOptions(false) - }); - } - } - /// /// Class GenreImageProvider. /// diff --git a/Emby.Server.Implementations/Images/MusicAlbumImageProvider.cs b/Emby.Server.Implementations/Images/MusicAlbumImageProvider.cs new file mode 100644 index 0000000000..ce83673638 --- /dev/null +++ b/Emby.Server.Implementations/Images/MusicAlbumImageProvider.cs @@ -0,0 +1,19 @@ +#pragma warning disable CS1591 + +using MediaBrowser.Common.Configuration; +using MediaBrowser.Controller.Drawing; +using MediaBrowser.Controller.Entities.Audio; +using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Providers; +using MediaBrowser.Model.IO; + +namespace Emby.Server.Implementations.Images +{ + public class MusicAlbumImageProvider : BaseFolderImageProvider + { + public MusicAlbumImageProvider(IFileSystem fileSystem, IProviderManager providerManager, IApplicationPaths applicationPaths, IImageProcessor imageProcessor, ILibraryManager libraryManager) + : base(fileSystem, providerManager, applicationPaths, imageProcessor, libraryManager) + { + } + } +} diff --git a/Emby.Server.Implementations/Images/MusicGenreImageProvider.cs b/Emby.Server.Implementations/Images/MusicGenreImageProvider.cs new file mode 100644 index 0000000000..baf1c90517 --- /dev/null +++ b/Emby.Server.Implementations/Images/MusicGenreImageProvider.cs @@ -0,0 +1,59 @@ +#nullable disable + +#pragma warning disable CS1591 + +using System.Collections.Generic; +using Jellyfin.Data.Enums; +using MediaBrowser.Common.Configuration; +using MediaBrowser.Controller.Drawing; +using MediaBrowser.Controller.Dto; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities.Audio; +using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Providers; +using MediaBrowser.Model.Entities; +using MediaBrowser.Model.IO; +using MediaBrowser.Model.Querying; + +namespace Emby.Server.Implementations.Images +{ + /// + /// Class MusicGenreImageProvider. + /// + public class MusicGenreImageProvider : BaseDynamicImageProvider + { + /// + /// The library manager. + /// + private readonly ILibraryManager _libraryManager; + + public MusicGenreImageProvider(IFileSystem fileSystem, IProviderManager providerManager, IApplicationPaths applicationPaths, IImageProcessor imageProcessor, ILibraryManager libraryManager) : base(fileSystem, providerManager, applicationPaths, imageProcessor) + { + _libraryManager = libraryManager; + } + + /// + /// Get children objects used to create an music genre image. + /// + /// The music genre used to create the image. + /// Any relevant children objects. + protected override IReadOnlyList GetItemsWithImages(BaseItem item) + { + return _libraryManager.GetItemList(new InternalItemsQuery + { + Genres = new[] { item.Name }, + IncludeItemTypes = new[] + { + nameof(MusicAlbum), + nameof(MusicVideo), + nameof(Audio) + }, + OrderBy = new[] { (ItemSortBy.Random, SortOrder.Ascending) }, + Limit = 4, + Recursive = true, + ImageTypes = new[] { ImageType.Primary }, + DtoOptions = new DtoOptions(false) + }); + } + } +} diff --git a/Emby.Server.Implementations/Images/PhotoAlbumImageProvider.cs b/Emby.Server.Implementations/Images/PhotoAlbumImageProvider.cs new file mode 100644 index 0000000000..1ddb4c7579 --- /dev/null +++ b/Emby.Server.Implementations/Images/PhotoAlbumImageProvider.cs @@ -0,0 +1,19 @@ +#pragma warning disable CS1591 + +using MediaBrowser.Common.Configuration; +using MediaBrowser.Controller.Drawing; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Providers; +using MediaBrowser.Model.IO; + +namespace Emby.Server.Implementations.Images +{ + public class PhotoAlbumImageProvider : BaseFolderImageProvider + { + public PhotoAlbumImageProvider(IFileSystem fileSystem, IProviderManager providerManager, IApplicationPaths applicationPaths, IImageProcessor imageProcessor, ILibraryManager libraryManager) + : base(fileSystem, providerManager, applicationPaths, imageProcessor, libraryManager) + { + } + } +} diff --git a/Emby.Server.Implementations/Library/Resolvers/FolderResolver.cs b/Emby.Server.Implementations/Library/Resolvers/FolderResolver.cs index 7aaee017dd..db7703cd60 100644 --- a/Emby.Server.Implementations/Library/Resolvers/FolderResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/FolderResolver.cs @@ -9,7 +9,7 @@ namespace Emby.Server.Implementations.Library.Resolvers /// /// Class FolderResolver. /// - public class FolderResolver : FolderResolver + public class FolderResolver : GenericFolderResolver { /// /// Gets the priority. @@ -32,24 +32,4 @@ namespace Emby.Server.Implementations.Library.Resolvers return null; } } - - /// - /// Class FolderResolver. - /// - /// The type of the T item type. - public abstract class FolderResolver : ItemResolver - where TItemType : Folder, new() - { - /// - /// Sets the initial item values. - /// - /// The item. - /// The args. - protected override void SetInitialItemValues(TItemType item, ItemResolveArgs args) - { - base.SetInitialItemValues(item, args); - - item.IsRoot = args.Parent == null; - } - } } diff --git a/Emby.Server.Implementations/Library/Resolvers/GenericFolderResolver.cs b/Emby.Server.Implementations/Library/Resolvers/GenericFolderResolver.cs new file mode 100644 index 0000000000..f109a5e9a2 --- /dev/null +++ b/Emby.Server.Implementations/Library/Resolvers/GenericFolderResolver.cs @@ -0,0 +1,27 @@ +#nullable disable + +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Library; + +namespace Emby.Server.Implementations.Library.Resolvers +{ + /// + /// Class FolderResolver. + /// + /// The type of the T item type. + public abstract class GenericFolderResolver : ItemResolver + where TItemType : Folder, new() + { + /// + /// Sets the initial item values. + /// + /// The item. + /// The args. + protected override void SetInitialItemValues(TItemType item, ItemResolveArgs args) + { + base.SetInitialItemValues(item, args); + + item.IsRoot = args.Parent == null; + } + } +} diff --git a/Emby.Server.Implementations/Library/Resolvers/Movies/BoxSetResolver.cs b/Emby.Server.Implementations/Library/Resolvers/Movies/BoxSetResolver.cs index 69d71d0d9a..e7abe1e6da 100644 --- a/Emby.Server.Implementations/Library/Resolvers/Movies/BoxSetResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/Movies/BoxSetResolver.cs @@ -12,7 +12,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies /// /// Class BoxSetResolver. /// - public class BoxSetResolver : FolderResolver + public class BoxSetResolver : GenericFolderResolver { /// /// Resolves the specified args. diff --git a/Emby.Server.Implementations/Library/Resolvers/PhotoAlbumResolver.cs b/Emby.Server.Implementations/Library/Resolvers/PhotoAlbumResolver.cs index 534bc80ddc..1c560e8a6e 100644 --- a/Emby.Server.Implementations/Library/Resolvers/PhotoAlbumResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/PhotoAlbumResolver.cs @@ -12,7 +12,7 @@ namespace Emby.Server.Implementations.Library.Resolvers /// /// Class PhotoAlbumResolver. /// - public class PhotoAlbumResolver : FolderResolver + public class PhotoAlbumResolver : GenericFolderResolver { private readonly IImageProcessor _imageProcessor; private readonly ILibraryManager _libraryManager; diff --git a/Emby.Server.Implementations/Library/Resolvers/PlaylistResolver.cs b/Emby.Server.Implementations/Library/Resolvers/PlaylistResolver.cs index 2c4ead7198..8ce59717d0 100644 --- a/Emby.Server.Implementations/Library/Resolvers/PlaylistResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/PlaylistResolver.cs @@ -16,7 +16,7 @@ namespace Emby.Server.Implementations.Library.Resolvers /// /// for library items. /// - public class PlaylistResolver : FolderResolver + public class PlaylistResolver : GenericFolderResolver { private string[] _musicPlaylistCollectionTypes = { diff --git a/Emby.Server.Implementations/Library/Resolvers/SpecialFolderResolver.cs b/Emby.Server.Implementations/Library/Resolvers/SpecialFolderResolver.cs index a42ac41446..6bb9996415 100644 --- a/Emby.Server.Implementations/Library/Resolvers/SpecialFolderResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/SpecialFolderResolver.cs @@ -13,7 +13,7 @@ using MediaBrowser.Model.IO; namespace Emby.Server.Implementations.Library.Resolvers { - public class SpecialFolderResolver : FolderResolver + public class SpecialFolderResolver : GenericFolderResolver { private readonly IFileSystem _fileSystem; private readonly IServerApplicationPaths _appPaths; diff --git a/Emby.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs b/Emby.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs index 7d707df182..063f67543f 100644 --- a/Emby.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs @@ -12,7 +12,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV /// /// Class SeasonResolver. /// - public class SeasonResolver : FolderResolver + public class SeasonResolver : GenericFolderResolver { private readonly ILibraryManager _libraryManager; private readonly ILocalizationManager _localization; diff --git a/Emby.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs b/Emby.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs index 4d8a6494c7..b7fbe01c5a 100644 --- a/Emby.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs @@ -18,7 +18,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV /// /// Class SeriesResolver. /// - public class SeriesResolver : FolderResolver + public class SeriesResolver : GenericFolderResolver { private readonly ILogger _logger; private readonly ILibraryManager _libraryManager; diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ImageDataDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ImageDataDto.cs index 912e680dd7..4e9efc60f4 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ImageDataDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ImageDataDto.cs @@ -37,7 +37,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the aspect. /// [JsonPropertyName("aspect")] - public string aspect { get; set; } + public string Aspect { get; set; } /// /// Gets or sets the category. diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/StationDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/StationDto.cs index 12f3576c65..c37f19678f 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/StationDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/StationDto.cs @@ -6,62 +6,62 @@ using System.Text.Json.Serialization; namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos { /// - /// Station dto. - /// - public class StationDto - { - /// - /// Gets or sets the station id. - /// - [JsonPropertyName("stationID")] - public string StationId { get; set; } + /// Station dto. + /// + public class StationDto + { + /// + /// Gets or sets the station id. + /// + [JsonPropertyName("stationID")] + public string StationId { get; set; } - /// - /// Gets or sets the name. - /// - [JsonPropertyName("name")] - public string Name { get; set; } + /// + /// Gets or sets the name. + /// + [JsonPropertyName("name")] + public string Name { get; set; } - /// - /// Gets or sets the callsign. - /// - [JsonPropertyName("callsign")] - public string Callsign { get; set; } + /// + /// Gets or sets the callsign. + /// + [JsonPropertyName("callsign")] + public string Callsign { get; set; } - /// - /// Gets or sets the broadcast language. - /// - [JsonPropertyName("broadcastLanguage")] - public List BroadcastLanguage { get; set; } + /// + /// Gets or sets the broadcast language. + /// + [JsonPropertyName("broadcastLanguage")] + public List BroadcastLanguage { get; set; } - /// - /// Gets or sets the description language. - /// - [JsonPropertyName("descriptionLanguage")] - public List DescriptionLanguage { get; set; } + /// + /// Gets or sets the description language. + /// + [JsonPropertyName("descriptionLanguage")] + public List DescriptionLanguage { get; set; } - /// - /// Gets or sets the broadcaster. - /// - [JsonPropertyName("broadcaster")] - public BroadcasterDto Broadcaster { get; set; } + /// + /// Gets or sets the broadcaster. + /// + [JsonPropertyName("broadcaster")] + public BroadcasterDto Broadcaster { get; set; } - /// - /// Gets or sets the affiliate. - /// - [JsonPropertyName("affiliate")] - public string Affiliate { get; set; } + /// + /// Gets or sets the affiliate. + /// + [JsonPropertyName("affiliate")] + public string Affiliate { get; set; } - /// - /// Gets or sets the logo. - /// - [JsonPropertyName("logo")] - public LogoDto Logo { get; set; } + /// + /// Gets or sets the logo. + /// + [JsonPropertyName("logo")] + public LogoDto Logo { get; set; } - /// - /// Gets or set a value indicating whether it is commercial free. - /// - [JsonPropertyName("isCommercialFree")] - public bool? IsCommercialFree { get; set; } - } + /// + /// Gets or sets a value indicating whether it is commercial free. + /// + [JsonPropertyName("isCommercialFree")] + public bool? IsCommercialFree { get; set; } + } } diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunChannelCommands.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunChannelCommands.cs new file mode 100644 index 0000000000..069b4fab6b --- /dev/null +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunChannelCommands.cs @@ -0,0 +1,35 @@ +#pragma warning disable CS1591 + +using System; +using System.Collections.Generic; + +namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun +{ + public class HdHomerunChannelCommands : IHdHomerunChannelCommands + { + private string? _channel; + private string? _profile; + + public HdHomerunChannelCommands(string? channel, string? profile) + { + _channel = channel; + _profile = profile; + } + + public IEnumerable<(string, string)> GetCommands() + { + if (!string.IsNullOrEmpty(_channel)) + { + if (!string.IsNullOrEmpty(_profile) + && !string.Equals(_profile, "native", StringComparison.OrdinalIgnoreCase)) + { + yield return ("vchannel", $"{_channel} transcode={_profile}"); + } + else + { + yield return ("vchannel", _channel); + } + } + } + } +} diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs index 4d538c6043..78ea7bd0f5 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs @@ -87,11 +87,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun return lineup.Where(i => !i.DRM).ToList(); } - private class HdHomerunChannelInfo : ChannelInfo - { - public bool IsLegacyTuner { get; set; } - } - protected override async Task> GetChannelsInternal(TunerHostInfo tuner, CancellationToken cancellationToken) { var lineup = await GetLineup(tuner, cancellationToken).ConfigureAwait(false); @@ -715,5 +710,10 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun return hostInfo; } + + private class HdHomerunChannelInfo : ChannelInfo + { + public bool IsLegacyTuner { get; set; } + } } } diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunManager.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunManager.cs index b2e555c7dc..f0f61297f6 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunManager.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunManager.cs @@ -5,12 +5,10 @@ using System; using System.Buffers; using System.Buffers.Binary; -using System.Collections.Generic; using System.Globalization; using System.Net; using System.Net.Sockets; using System.Text; -using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; using MediaBrowser.Common; @@ -18,70 +16,6 @@ using MediaBrowser.Controller.LiveTv; namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun { - public interface IHdHomerunChannelCommands - { - IEnumerable<(string, string)> GetCommands(); - } - - public class LegacyHdHomerunChannelCommands : IHdHomerunChannelCommands - { - private string _channel; - private string _program; - - public LegacyHdHomerunChannelCommands(string url) - { - // parse url for channel and program - var regExp = new Regex(@"\/ch([0-9]+)-?([0-9]*)"); - var match = regExp.Match(url); - if (match.Success) - { - _channel = match.Groups[1].Value; - _program = match.Groups[2].Value; - } - } - - public IEnumerable<(string, string)> GetCommands() - { - if (!string.IsNullOrEmpty(_channel)) - { - yield return ("channel", _channel); - } - - if (!string.IsNullOrEmpty(_program)) - { - yield return ("program", _program); - } - } - } - - public class HdHomerunChannelCommands : IHdHomerunChannelCommands - { - private string _channel; - private string _profile; - - public HdHomerunChannelCommands(string channel, string profile) - { - _channel = channel; - _profile = profile; - } - - public IEnumerable<(string, string)> GetCommands() - { - if (!string.IsNullOrEmpty(_channel)) - { - if (!string.IsNullOrEmpty(_profile) - && !string.Equals(_profile, "native", StringComparison.OrdinalIgnoreCase)) - { - yield return ("vchannel", $"{_channel} transcode={_profile}"); - } - else - { - yield return ("vchannel", _channel); - } - } - } - } - public sealed class HdHomerunManager : IDisposable { public const int HdHomeRunPort = 65001; diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/IHdHomerunChannelCommands.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/IHdHomerunChannelCommands.cs new file mode 100644 index 0000000000..1533549320 --- /dev/null +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/IHdHomerunChannelCommands.cs @@ -0,0 +1,11 @@ +#pragma warning disable CS1591 + +using System.Collections.Generic; + +namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun +{ + public interface IHdHomerunChannelCommands + { + IEnumerable<(string, string)> GetCommands(); + } +} diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/LegacyHdHomerunChannelCommands.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/LegacyHdHomerunChannelCommands.cs new file mode 100644 index 0000000000..26627b8aa6 --- /dev/null +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/LegacyHdHomerunChannelCommands.cs @@ -0,0 +1,38 @@ +#pragma warning disable CS1591 + +using System.Collections.Generic; +using System.Text.RegularExpressions; + +namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun +{ + public class LegacyHdHomerunChannelCommands : IHdHomerunChannelCommands + { + private string? _channel; + private string? _program; + + public LegacyHdHomerunChannelCommands(string url) + { + // parse url for channel and program + var regExp = new Regex(@"\/ch([0-9]+)-?([0-9]*)"); + var match = regExp.Match(url); + if (match.Success) + { + _channel = match.Groups[1].Value; + _program = match.Groups[2].Value; + } + } + + public IEnumerable<(string, string)> GetCommands() + { + if (!string.IsNullOrEmpty(_channel)) + { + yield return ("channel", _channel); + } + + if (!string.IsNullOrEmpty(_program)) + { + yield return ("program", _program); + } + } + } +} diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index 47cec7d77f..4b3a75b90b 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -39,11 +39,6 @@ true true snupkg - false - - - - true diff --git a/MediaBrowser.Model/MediaBrowser.Model.csproj b/MediaBrowser.Model/MediaBrowser.Model.csproj index b0a12a9c90..91803ade6e 100644 --- a/MediaBrowser.Model/MediaBrowser.Model.csproj +++ b/MediaBrowser.Model/MediaBrowser.Model.csproj @@ -21,11 +21,6 @@ true true snupkg - false - - - - true -- cgit v1.2.3 From d05062fec06ecba1049beefffe8d8f521d3e1881 Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Fri, 8 Oct 2021 15:40:13 +0200 Subject: Use new Random.Shared instead of creating new instances --- Emby.Server.Implementations/Dto/DtoService.cs | 2 +- .../LiveTv/TunerHosts/HdHomerun/HdHomerunManager.cs | 3 +-- Jellyfin.Api/Controllers/MediaInfoController.cs | 2 +- tests/Jellyfin.Extensions.Tests/ShuffleExtensionsTests.cs | 4 +--- 4 files changed, 4 insertions(+), 7 deletions(-) (limited to 'Emby.Server.Implementations/LiveTv') diff --git a/Emby.Server.Implementations/Dto/DtoService.cs b/Emby.Server.Implementations/Dto/DtoService.cs index 74400b5128..ad76f3d6d4 100644 --- a/Emby.Server.Implementations/Dto/DtoService.cs +++ b/Emby.Server.Implementations/Dto/DtoService.cs @@ -420,7 +420,7 @@ namespace Emby.Server.Implementations.Dto // Just return something so that apps that are expecting a value won't think the folders are empty if (folder is ICollectionFolder || folder is UserView) { - return new Random().Next(1, 10); + return Random.Shared.Next(1, 10); } return folder.GetChildCount(user); diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunManager.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunManager.cs index b2e555c7dc..08ed1a32ac 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunManager.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunManager.cs @@ -150,8 +150,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun if (!_lockkey.HasValue) { - var rand = new Random(); - _lockkey = (uint)rand.Next(); + _lockkey = (uint)Random.Shared.Next(); } var lockKeyValue = _lockkey.Value; diff --git a/Jellyfin.Api/Controllers/MediaInfoController.cs b/Jellyfin.Api/Controllers/MediaInfoController.cs index 96ef2d678b..b422eb78c6 100644 --- a/Jellyfin.Api/Controllers/MediaInfoController.cs +++ b/Jellyfin.Api/Controllers/MediaInfoController.cs @@ -316,7 +316,7 @@ namespace Jellyfin.Api.Controllers byte[] buffer = ArrayPool.Shared.Rent(size); try { - new Random().NextBytes(buffer); + Random.Shared.NextBytes(buffer); return File(buffer, MediaTypeNames.Application.Octet); } finally diff --git a/tests/Jellyfin.Extensions.Tests/ShuffleExtensionsTests.cs b/tests/Jellyfin.Extensions.Tests/ShuffleExtensionsTests.cs index c72216d94b..a73cfb0781 100644 --- a/tests/Jellyfin.Extensions.Tests/ShuffleExtensionsTests.cs +++ b/tests/Jellyfin.Extensions.Tests/ShuffleExtensionsTests.cs @@ -5,13 +5,11 @@ namespace Jellyfin.Extensions.Tests { public static class ShuffleExtensionsTests { - private static readonly Random _rng = new Random(); - [Fact] public static void Shuffle_Valid_Correct() { byte[] original = new byte[1 << 6]; - _rng.NextBytes(original); + Random.Shared.NextBytes(original); byte[] shuffled = (byte[])original.Clone(); shuffled.Shuffle(); -- cgit v1.2.3 From a81dfabdb649b98e1a809dfee941b75637623e9e Mon Sep 17 00:00:00 2001 From: Cody Robibero Date: Sat, 9 Oct 2021 07:16:50 -0600 Subject: Fix indentation and build errors --- .../LiveTv/Listings/SchedulesDirectDtos/MapDto.cs | 2 +- .../Listings/SchedulesDirectDtos/StationDto.cs | 100 ++++++++++----------- 2 files changed, 51 insertions(+), 51 deletions(-) (limited to 'Emby.Server.Implementations/LiveTv') diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MapDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MapDto.cs index 2420307b4f..ffd02d474b 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MapDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MapDto.cs @@ -53,6 +53,6 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the match type. /// [JsonPropertyName("matchType")] - public string? MatchType { get;set; } + public string? MatchType { get; set; } } } diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/StationDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/StationDto.cs index 1b76b22e32..d797fd49b1 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/StationDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/StationDto.cs @@ -5,62 +5,62 @@ using System.Text.Json.Serialization; namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos { /// - /// Station dto. - /// - public class StationDto - { - /// - /// Gets or sets the station id. - /// - [JsonPropertyName("stationID")] - public string? StationId { get; set; } + /// Station dto. + /// + public class StationDto + { + /// + /// Gets or sets the station id. + /// + [JsonPropertyName("stationID")] + public string? StationId { get; set; } - /// - /// Gets or sets the name. - /// - [JsonPropertyName("name")] - public string? Name { get; set; } + /// + /// Gets or sets the name. + /// + [JsonPropertyName("name")] + public string? Name { get; set; } - /// - /// Gets or sets the callsign. - /// - [JsonPropertyName("callsign")] - public string? Callsign { get; set; } + /// + /// Gets or sets the callsign. + /// + [JsonPropertyName("callsign")] + public string? Callsign { get; set; } - /// - /// Gets or sets the broadcast language. - /// - [JsonPropertyName("broadcastLanguage")] - public IReadOnlyList BroadcastLanguage { get; set; } = Array.Empty(); + /// + /// Gets or sets the broadcast language. + /// + [JsonPropertyName("broadcastLanguage")] + public IReadOnlyList BroadcastLanguage { get; set; } = Array.Empty(); - /// - /// Gets or sets the description language. - /// - [JsonPropertyName("descriptionLanguage")] - public IReadOnlyList DescriptionLanguage { get; set; } = Array.Empty(); + /// + /// Gets or sets the description language. + /// + [JsonPropertyName("descriptionLanguage")] + public IReadOnlyList DescriptionLanguage { get; set; } = Array.Empty(); - /// - /// Gets or sets the broadcaster. - /// - [JsonPropertyName("broadcaster")] - public BroadcasterDto? Broadcaster { get; set; } + /// + /// Gets or sets the broadcaster. + /// + [JsonPropertyName("broadcaster")] + public BroadcasterDto? Broadcaster { get; set; } - /// - /// Gets or sets the affiliate. - /// - [JsonPropertyName("affiliate")] - public string? Affiliate { get; set; } + /// + /// Gets or sets the affiliate. + /// + [JsonPropertyName("affiliate")] + public string? Affiliate { get; set; } - /// - /// Gets or sets the logo. - /// - [JsonPropertyName("logo")] - public LogoDto? Logo { get; set; } + /// + /// Gets or sets the logo. + /// + [JsonPropertyName("logo")] + public LogoDto? Logo { get; set; } - /// - /// Gets or set a value indicating whether it is commercial free. - /// - [JsonPropertyName("isCommercialFree")] - public bool? IsCommercialFree { get; set; } - } + /// + /// Gets or sets a value indicating whether it is commercial free. + /// + [JsonPropertyName("isCommercialFree")] + public bool? IsCommercialFree { get; set; } + } } -- cgit v1.2.3