Merge pull request #10141 from Bond-009/nullable3

pull/10158/head
Bond-009 1 year ago committed by GitHub
commit 9ae429b6f6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1006,7 +1006,7 @@ namespace Emby.Server.Implementations
if (ConfigurationManager.GetNetworkConfiguration().EnablePublishedServerUriByRequest) if (ConfigurationManager.GetNetworkConfiguration().EnablePublishedServerUriByRequest)
{ {
int? requestPort = request.Host.Port; int? requestPort = request.Host.Port;
if (requestPort == null if (requestPort is null
|| (requestPort == 80 && string.Equals(request.Scheme, "http", StringComparison.OrdinalIgnoreCase)) || (requestPort == 80 && string.Equals(request.Scheme, "http", StringComparison.OrdinalIgnoreCase))
|| (requestPort == 443 && string.Equals(request.Scheme, "https", StringComparison.OrdinalIgnoreCase))) || (requestPort == 443 && string.Equals(request.Scheme, "https", StringComparison.OrdinalIgnoreCase)))
{ {
@ -1190,7 +1190,7 @@ namespace Emby.Server.Implementations
} }
} }
if (_sessionManager != null) if (_sessionManager is not null)
{ {
// used for closing websockets // used for closing websockets
foreach (var session in _sessionManager.Sessions) foreach (var session in _sessionManager.Sessions)

@ -1971,19 +1971,8 @@ namespace Emby.Server.Implementations.Data
if (reader.TryGetString(2, out var imagePath)) if (reader.TryGetString(2, out var imagePath))
{ {
chapter.ImagePath = imagePath; chapter.ImagePath = imagePath;
if (!string.IsNullOrEmpty(chapter.ImagePath))
{
try
{
chapter.ImageTag = _imageProcessor.GetImageCacheTag(item, chapter); chapter.ImageTag = _imageProcessor.GetImageCacheTag(item, chapter);
} }
catch (Exception ex)
{
Logger.LogError(ex, "Failed to create image cache tag.");
}
}
}
if (reader.TryReadDateTime(3, out var imageDateModified)) if (reader.TryReadDateTime(3, out var imageDateModified))
{ {

@ -693,7 +693,7 @@ public class DynamicHlsHelper
// Currently we only transcode to 8 bits AV1 // Currently we only transcode to 8 bits AV1
int bitDepth = 8; int bitDepth = 8;
if (EncodingHelper.IsCopyCodec(state.OutputVideoCodec) if (EncodingHelper.IsCopyCodec(state.OutputVideoCodec)
&& state.VideoStream != null && state.VideoStream is not null
&& state.VideoStream.BitDepth.HasValue) && state.VideoStream.BitDepth.HasValue)
{ {
bitDepth = state.VideoStream.BitDepth.Value; bitDepth = state.VideoStream.BitDepth.Value;

@ -77,7 +77,7 @@ public class CommaDelimitedArrayModelBinder : IModelBinder
var typedValueIndex = 0; var typedValueIndex = 0;
for (var i = 0; i < parsedValues.Length; i++) for (var i = 0; i < parsedValues.Length; i++)
{ {
if (parsedValues[i] != null) if (parsedValues[i] is not null)
{ {
typedValues.SetValue(parsedValues[i], typedValueIndex); typedValues.SetValue(parsedValues[i], typedValueIndex);
typedValueIndex++; typedValueIndex++;

@ -77,7 +77,7 @@ public class PipeDelimitedArrayModelBinder : IModelBinder
var typedValueIndex = 0; var typedValueIndex = 0;
for (var i = 0; i < parsedValues.Length; i++) for (var i = 0; i < parsedValues.Length; i++)
{ {
if (parsedValues[i] != null) if (parsedValues[i] is not null)
{ {
typedValues.SetValue(parsedValues[i], typedValueIndex); typedValues.SetValue(parsedValues[i], typedValueIndex);
typedValueIndex++; typedValueIndex++;

@ -276,7 +276,7 @@ namespace Jellyfin.Server.Extensions
} }
else if (NetworkExtensions.TryParseToSubnet(allowedProxies[i], out var subnet)) else if (NetworkExtensions.TryParseToSubnet(allowedProxies[i], out var subnet))
{ {
if (subnet != null) if (subnet is not null)
{ {
AddIPAddress(config, options, subnet.Prefix, subnet.PrefixLength); AddIPAddress(config, options, subnet.Prefix, subnet.PrefixLength);
} }

@ -66,7 +66,7 @@ namespace MediaBrowser.Controller.Drawing
/// <returns>Guid.</returns> /// <returns>Guid.</returns>
string GetImageCacheTag(BaseItem item, ItemImageInfo image); string GetImageCacheTag(BaseItem item, ItemImageInfo image);
string GetImageCacheTag(BaseItem item, ChapterInfo chapter); string? GetImageCacheTag(BaseItem item, ChapterInfo chapter);
string? GetImageCacheTag(User user); string? GetImageCacheTag(User user);

@ -1864,7 +1864,7 @@ namespace MediaBrowser.Controller.Entities
/// <exception cref="ArgumentException">Backdrops should be accessed using Item.Backdrops.</exception> /// <exception cref="ArgumentException">Backdrops should be accessed using Item.Backdrops.</exception>
public bool HasImage(ImageType type, int imageIndex) public bool HasImage(ImageType type, int imageIndex)
{ {
return GetImageInfo(type, imageIndex) != null; return GetImageInfo(type, imageIndex) is not null;
} }
public void SetImage(ItemImageInfo image, int index) public void SetImage(ItemImageInfo image, int index)

@ -1,5 +1,3 @@
#nullable disable
#pragma warning disable CS1591 #pragma warning disable CS1591
using System; using System;
@ -14,7 +12,7 @@ namespace MediaBrowser.Controller.Entities
/// Gets or sets the path. /// Gets or sets the path.
/// </summary> /// </summary>
/// <value>The path.</value> /// <value>The path.</value>
public string Path { get; set; } public required string Path { get; set; }
/// <summary> /// <summary>
/// Gets or sets the type. /// Gets or sets the type.
@ -36,9 +34,9 @@ namespace MediaBrowser.Controller.Entities
/// Gets or sets the blurhash. /// Gets or sets the blurhash.
/// </summary> /// </summary>
/// <value>The blurhash.</value> /// <value>The blurhash.</value>
public string BlurHash { get; set; } public string? BlurHash { get; set; }
[JsonIgnore] [JsonIgnore]
public bool IsLocalFile => Path is null || !Path.StartsWith("http", StringComparison.OrdinalIgnoreCase); public bool IsLocalFile => !Path.StartsWith("http", StringComparison.OrdinalIgnoreCase);
} }
} }

@ -99,7 +99,7 @@ namespace MediaBrowser.Controller.Entities.TV
} }
[JsonIgnore] [JsonIgnore]
public bool IsInSeasonFolder => FindParent<Season>() != null; public bool IsInSeasonFolder => FindParent<Season>() is not null;
[JsonIgnore] [JsonIgnore]
public string SeriesPresentationUniqueKey { get; set; } public string SeriesPresentationUniqueKey { get; set; }

@ -333,7 +333,7 @@ namespace MediaBrowser.Controller.Entities
protected override bool IsActiveRecording() protected override bool IsActiveRecording()
{ {
return LiveTvManager.GetActiveRecordingInfo(Path) != null; return LiveTvManager.GetActiveRecordingInfo(Path) is not null;
} }
public override bool CanDelete() public override bool CanDelete()

@ -217,7 +217,7 @@ namespace MediaBrowser.Controller.Library
/// <returns><c>true</c> if [contains file system entry by name] [the specified name]; otherwise, <c>false</c>.</returns> /// <returns><c>true</c> if [contains file system entry by name] [the specified name]; otherwise, <c>false</c>.</returns>
public bool ContainsFileSystemEntryByName(string name) public bool ContainsFileSystemEntryByName(string name)
{ {
return GetFileSystemEntryByName(name) != null; return GetFileSystemEntryByName(name) is not null;
} }
public string GetCollectionType() public string GetCollectionType()

@ -2692,7 +2692,7 @@ namespace MediaBrowser.Controller.MediaEncoding
string args = string.Empty; string args = string.Empty;
// http://ffmpeg.org/ffmpeg-all.html#toc-Complex-filtergraphs-1 // http://ffmpeg.org/ffmpeg-all.html#toc-Complex-filtergraphs-1
if (state.VideoStream != null && videoProcessFilters.Contains("-filter_complex", StringComparison.Ordinal)) if (state.VideoStream is not null && videoProcessFilters.Contains("-filter_complex", StringComparison.Ordinal))
{ {
int videoStreamIndex = FindIndex(state.MediaSource.MediaStreams, state.VideoStream); int videoStreamIndex = FindIndex(state.MediaSource.MediaStreams, state.VideoStream);

@ -1,6 +1,4 @@
#nullable enable using System.Collections.Generic;
using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace MediaBrowser.Controller.Security namespace MediaBrowser.Controller.Security

@ -135,7 +135,7 @@ namespace MediaBrowser.Model.Dlna
} }
} }
if (transcodingProfile != null) if (transcodingProfile is not null)
{ {
if (!item.SupportsTranscoding) if (!item.SupportsTranscoding)
{ {
@ -759,7 +759,7 @@ namespace MediaBrowser.Model.Dlna
{ {
// prefer direct copy profile // prefer direct copy profile
float videoFramerate = videoStream?.AverageFrameRate ?? videoStream?.RealFrameRate ?? 0; float videoFramerate = videoStream?.AverageFrameRate ?? videoStream?.RealFrameRate ?? 0;
TransportStreamTimestamp? timestamp = videoStream == null ? TransportStreamTimestamp.None : item.Timestamp; TransportStreamTimestamp? timestamp = videoStream is null ? TransportStreamTimestamp.None : item.Timestamp;
int? numAudioStreams = item.GetStreamCount(MediaStreamType.Audio); int? numAudioStreams = item.GetStreamCount(MediaStreamType.Audio);
int? numVideoStreams = item.GetStreamCount(MediaStreamType.Video); int? numVideoStreams = item.GetStreamCount(MediaStreamType.Video);

@ -1,4 +1,3 @@
#nullable disable
#pragma warning disable CS1591 #pragma warning disable CS1591
using System; using System;
@ -20,16 +19,16 @@ namespace MediaBrowser.Model.Entities
/// Gets or sets the name. /// Gets or sets the name.
/// </summary> /// </summary>
/// <value>The name.</value> /// <value>The name.</value>
public string Name { get; set; } public string? Name { get; set; }
/// <summary> /// <summary>
/// Gets or sets the image path. /// Gets or sets the image path.
/// </summary> /// </summary>
/// <value>The image path.</value> /// <value>The image path.</value>
public string ImagePath { get; set; } public string? ImagePath { get; set; }
public DateTime ImageDateModified { get; set; } public DateTime ImageDateModified { get; set; }
public string ImageTag { get; set; } public string? ImageTag { get; set; }
} }
} }

@ -1,11 +1,8 @@
#nullable disable
#pragma warning disable CA1068, CS1591 #pragma warning disable CA1068, CS1591
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.IO;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -83,9 +80,9 @@ namespace MediaBrowser.Providers.MediaInfo
CancellationToken cancellationToken) CancellationToken cancellationToken)
where T : Video where T : Video
{ {
BlurayDiscInfo blurayDiscInfo = null; BlurayDiscInfo? blurayDiscInfo = null;
Model.MediaInfo.MediaInfo mediaInfoResult = null; Model.MediaInfo.MediaInfo? mediaInfoResult = null;
if (!item.IsShortcut || options.EnableRemoteContentProbe) if (!item.IsShortcut || options.EnableRemoteContentProbe)
{ {
@ -131,7 +128,7 @@ namespace MediaBrowser.Providers.MediaInfo
var m2ts = _mediaEncoder.GetPrimaryPlaylistM2tsFiles(item.Path); var m2ts = _mediaEncoder.GetPrimaryPlaylistM2tsFiles(item.Path);
// Return if no playable .m2ts files are found // Return if no playable .m2ts files are found
if (blurayDiscInfo.Files.Length == 0 || m2ts.Count == 0) if (blurayDiscInfo is null || blurayDiscInfo.Files.Length == 0 || m2ts.Count == 0)
{ {
_logger.LogError("No playable .m2ts files found in Blu-ray structure, skipping FFprobe."); _logger.LogError("No playable .m2ts files found in Blu-ray structure, skipping FFprobe.");
return ItemUpdateType.MetadataImport; return ItemUpdateType.MetadataImport;
@ -192,16 +189,14 @@ namespace MediaBrowser.Providers.MediaInfo
protected async Task Fetch( protected async Task Fetch(
Video video, Video video,
CancellationToken cancellationToken, CancellationToken cancellationToken,
Model.MediaInfo.MediaInfo mediaInfo, Model.MediaInfo.MediaInfo? mediaInfo,
BlurayDiscInfo blurayInfo, BlurayDiscInfo? blurayInfo,
MetadataRefreshOptions options) MetadataRefreshOptions options)
{ {
List<MediaStream> mediaStreams; List<MediaStream> mediaStreams = new List<MediaStream>();
IReadOnlyList<MediaAttachment> mediaAttachments; IReadOnlyList<MediaAttachment> mediaAttachments;
ChapterInfo[] chapters; ChapterInfo[] chapters;
mediaStreams = new List<MediaStream>();
// Add external streams before adding the streams from the file to preserve stream IDs on remote videos // Add external streams before adding the streams from the file to preserve stream IDs on remote videos
await AddExternalSubtitlesAsync(video, mediaStreams, options, cancellationToken).ConfigureAwait(false); await AddExternalSubtitlesAsync(video, mediaStreams, options, cancellationToken).ConfigureAwait(false);
@ -221,18 +216,6 @@ namespace MediaBrowser.Providers.MediaInfo
video.TotalBitrate = mediaInfo.Bitrate; video.TotalBitrate = mediaInfo.Bitrate;
video.RunTimeTicks = mediaInfo.RunTimeTicks; video.RunTimeTicks = mediaInfo.RunTimeTicks;
video.Size = mediaInfo.Size; video.Size = mediaInfo.Size;
if (video.VideoType == VideoType.VideoFile)
{
var extension = (Path.GetExtension(video.Path) ?? string.Empty).TrimStart('.');
video.Container = extension;
}
else
{
video.Container = null;
}
video.Container = mediaInfo.Container; video.Container = mediaInfo.Container;
chapters = mediaInfo.Chapters ?? Array.Empty<ChapterInfo>(); chapters = mediaInfo.Chapters ?? Array.Empty<ChapterInfo>();
@ -243,8 +226,7 @@ namespace MediaBrowser.Providers.MediaInfo
} }
else else
{ {
var currentMediaStreams = video.GetMediaStreams(); foreach (var mediaStream in video.GetMediaStreams())
foreach (var mediaStream in currentMediaStreams)
{ {
if (!mediaStream.IsExternal) if (!mediaStream.IsExternal)
{ {
@ -295,8 +277,8 @@ namespace MediaBrowser.Providers.MediaInfo
_itemRepo.SaveMediaAttachments(video.Id, mediaAttachments, cancellationToken); _itemRepo.SaveMediaAttachments(video.Id, mediaAttachments, cancellationToken);
} }
if (options.MetadataRefreshMode == MetadataRefreshMode.FullRefresh || if (options.MetadataRefreshMode == MetadataRefreshMode.FullRefresh
options.MetadataRefreshMode == MetadataRefreshMode.Default) || options.MetadataRefreshMode == MetadataRefreshMode.Default)
{ {
if (_config.Configuration.DummyChapterDuration > 0 && chapters.Length == 0 && mediaStreams.Any(i => i.Type == MediaStreamType.Video)) if (_config.Configuration.DummyChapterDuration > 0 && chapters.Length == 0 && mediaStreams.Any(i => i.Type == MediaStreamType.Video))
{ {
@ -321,11 +303,11 @@ namespace MediaBrowser.Providers.MediaInfo
{ {
for (int i = 0; i < chapters.Length; i++) for (int i = 0; i < chapters.Length; i++)
{ {
string name = chapters[i].Name; string? name = chapters[i].Name;
// Check if the name is empty and/or if the name is a time // Check if the name is empty and/or if the name is a time
// Some ripping programs do that. // Some ripping programs do that.
if (string.IsNullOrWhiteSpace(name) || if (string.IsNullOrWhiteSpace(name)
TimeSpan.TryParse(name, out _)) || TimeSpan.TryParse(name, out _))
{ {
chapters[i].Name = string.Format( chapters[i].Name = string.Format(
CultureInfo.InvariantCulture, CultureInfo.InvariantCulture,
@ -384,23 +366,18 @@ namespace MediaBrowser.Providers.MediaInfo
// Use the ffprobe values if these are empty // Use the ffprobe values if these are empty
if (videoStream is not null) if (videoStream is not null)
{ {
videoStream.BitRate = IsEmpty(videoStream.BitRate) ? currentBitRate : videoStream.BitRate; videoStream.BitRate = videoStream.BitRate.GetValueOrDefault() == 0 ? currentBitRate : videoStream.BitRate;
videoStream.Width = IsEmpty(videoStream.Width) ? currentWidth : videoStream.Width; videoStream.Width = videoStream.Width.GetValueOrDefault() == 0 ? currentWidth : videoStream.Width;
videoStream.Height = IsEmpty(videoStream.Height) ? currentHeight : videoStream.Height; videoStream.Height = videoStream.Height.GetValueOrDefault() == 0 ? currentHeight : videoStream.Height;
} }
} }
private bool IsEmpty(int? num)
{
return !num.HasValue || num.Value == 0;
}
/// <summary> /// <summary>
/// Gets information about the longest playlist on a bdrom. /// Gets information about the longest playlist on a bdrom.
/// </summary> /// </summary>
/// <param name="path">The path.</param> /// <param name="path">The path.</param>
/// <returns>VideoStream.</returns> /// <returns>VideoStream.</returns>
private BlurayDiscInfo GetBDInfo(string path) private BlurayDiscInfo? GetBDInfo(string path)
{ {
ArgumentException.ThrowIfNullOrEmpty(path); ArgumentException.ThrowIfNullOrEmpty(path);
@ -527,11 +504,14 @@ namespace MediaBrowser.Providers.MediaInfo
private void FetchPeople(Video video, Model.MediaInfo.MediaInfo data, MetadataRefreshOptions options) private void FetchPeople(Video video, Model.MediaInfo.MediaInfo data, MetadataRefreshOptions options)
{ {
var replaceData = options.ReplaceAllMetadata; if (video.IsLocked
|| video.LockedFields.Contains(MetadataField.Cast)
if (!video.IsLocked && !video.LockedFields.Contains(MetadataField.Cast)) || data.People.Length == 0)
{ {
if (replaceData || _libraryManager.GetPeople(video).Count == 0) return;
}
if (options.ReplaceAllMetadata || _libraryManager.GetPeople(video).Count == 0)
{ {
var people = new List<PersonInfo>(); var people = new List<PersonInfo>();
@ -548,12 +528,6 @@ namespace MediaBrowser.Providers.MediaInfo
_libraryManager.UpdatePeople(video, people); _libraryManager.UpdatePeople(video, people);
} }
} }
}
private SubtitleOptions GetOptions()
{
return _config.GetConfiguration<SubtitleOptions>("subtitles");
}
/// <summary> /// <summary>
/// Adds the external subtitles. /// Adds the external subtitles.
@ -575,7 +549,7 @@ namespace MediaBrowser.Providers.MediaInfo
var enableSubtitleDownloading = options.MetadataRefreshMode == MetadataRefreshMode.Default || var enableSubtitleDownloading = options.MetadataRefreshMode == MetadataRefreshMode.Default ||
options.MetadataRefreshMode == MetadataRefreshMode.FullRefresh; options.MetadataRefreshMode == MetadataRefreshMode.FullRefresh;
var subtitleOptions = GetOptions(); var subtitleOptions = _config.GetConfiguration<SubtitleOptions>("subtitles");
var libraryOptions = _libraryManager.GetLibraryOptions(video); var libraryOptions = _libraryManager.GetLibraryOptions(video);
@ -659,9 +633,9 @@ namespace MediaBrowser.Providers.MediaInfo
/// </summary> /// </summary>
/// <param name="video">The video.</param> /// <param name="video">The video.</param>
/// <returns>An array of dummy chapters.</returns> /// <returns>An array of dummy chapters.</returns>
private ChapterInfo[] CreateDummyChapters(Video video) internal ChapterInfo[] CreateDummyChapters(Video video)
{ {
var runtime = video.RunTimeTicks ?? 0; var runtime = video.RunTimeTicks.GetValueOrDefault();
// Only process files with a runtime higher than 0 and lower than 12h. The latter are likely corrupted. // Only process files with a runtime higher than 0 and lower than 12h. The latter are likely corrupted.
if (runtime < 0 || runtime > TimeSpan.FromHours(12).Ticks) if (runtime < 0 || runtime > TimeSpan.FromHours(12).Ticks)
@ -671,12 +645,15 @@ namespace MediaBrowser.Providers.MediaInfo
CultureInfo.InvariantCulture, CultureInfo.InvariantCulture,
"{0} has an invalid runtime of {1} minutes", "{0} has an invalid runtime of {1} minutes",
video.Name, video.Name,
TimeSpan.FromTicks(runtime).Minutes)); TimeSpan.FromTicks(runtime).TotalMinutes));
} }
long dummyChapterDuration = TimeSpan.FromSeconds(_config.Configuration.DummyChapterDuration).Ticks; long dummyChapterDuration = TimeSpan.FromSeconds(_config.Configuration.DummyChapterDuration).Ticks;
if (runtime > dummyChapterDuration) if (runtime <= dummyChapterDuration)
{ {
return Array.Empty<ChapterInfo>();
}
int chapterCount = (int)(runtime / dummyChapterDuration); int chapterCount = (int)(runtime / dummyChapterDuration);
var chapters = new ChapterInfo[chapterCount]; var chapters = new ChapterInfo[chapterCount];
@ -693,8 +670,5 @@ namespace MediaBrowser.Providers.MediaInfo
return chapters; return chapters;
} }
return Array.Empty<ChapterInfo>();
}
} }
} }

@ -13,7 +13,6 @@ using MediaBrowser.Controller;
using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Drawing; using MediaBrowser.Controller.Drawing;
using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.Model.Drawing; using MediaBrowser.Model.Drawing;
using MediaBrowser.Model.Entities; using MediaBrowser.Model.Entities;
using MediaBrowser.Model.IO; using MediaBrowser.Model.IO;
@ -437,8 +436,13 @@ public sealed class ImageProcessor : IImageProcessor, IDisposable
=> (item.Path + image.DateModified.Ticks).GetMD5().ToString("N", CultureInfo.InvariantCulture); => (item.Path + image.DateModified.Ticks).GetMD5().ToString("N", CultureInfo.InvariantCulture);
/// <inheritdoc /> /// <inheritdoc />
public string GetImageCacheTag(BaseItem item, ChapterInfo chapter) public string? GetImageCacheTag(BaseItem item, ChapterInfo chapter)
{ {
if (chapter.ImagePath is null)
{
return null;
}
return GetImageCacheTag(item, new ItemImageInfo return GetImageCacheTag(item, new ItemImageInfo
{ {
Path = chapter.ImagePath, Path = chapter.ImagePath,

@ -59,7 +59,7 @@ namespace Jellyfin.Extensions.Json.Converters
var typedValueIndex = 0; var typedValueIndex = 0;
for (var i = 0; i < stringEntries.Length; i++) for (var i = 0; i < stringEntries.Length; i++)
{ {
if (parsedValues[i] != null) if (parsedValues[i] is not null)
{ {
typedValues.SetValue(parsedValues[i], typedValueIndex); typedValues.SetValue(parsedValues[i], typedValueIndex);
typedValueIndex++; typedValueIndex++;

@ -40,7 +40,7 @@ namespace Jellyfin.Extensions
public static IEnumerable<string> ReadAllLines(this TextReader reader) public static IEnumerable<string> ReadAllLines(this TextReader reader)
{ {
string? line; string? line;
while ((line = reader.ReadLine()) != null) while ((line = reader.ReadLine()) is not null)
{ {
yield return line; yield return line;
} }
@ -54,7 +54,7 @@ namespace Jellyfin.Extensions
public static async IAsyncEnumerable<string> ReadAllLinesAsync(this TextReader reader) public static async IAsyncEnumerable<string> ReadAllLinesAsync(this TextReader reader)
{ {
string? line; string? line;
while ((line = await reader.ReadLineAsync().ConfigureAwait(false)) != null) while ((line = await reader.ReadLineAsync().ConfigureAwait(false)) is not null)
{ {
yield return line; yield return line;
} }

@ -7,6 +7,9 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="AutoFixture" />
<PackageReference Include="AutoFixture.AutoMoq" />
<PackageReference Include="AutoFixture.Xunit2" />
<PackageReference Include="Microsoft.NET.Test.Sdk" /> <PackageReference Include="Microsoft.NET.Test.Sdk" />
<PackageReference Include="Moq" /> <PackageReference Include="Moq" />
<PackageReference Include="xunit" /> <PackageReference Include="xunit" />

@ -0,0 +1,61 @@
using System;
using AutoFixture;
using AutoFixture.AutoMoq;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Model.Configuration;
using MediaBrowser.Providers.MediaInfo;
using Moq;
using Xunit;
namespace Jellyfin.Providers.Tests.MediaInfo;
public class FFProbeVideoInfoTests
{
private readonly FFProbeVideoInfo _fFProbeVideoInfo;
public FFProbeVideoInfoTests()
{
var serverConfiguration = new ServerConfiguration()
{
DummyChapterDuration = (int)TimeSpan.FromMinutes(5).TotalSeconds
};
var serverConfig = new Mock<IServerConfigurationManager>();
serverConfig.Setup(c => c.Configuration)
.Returns(serverConfiguration);
IFixture fixture = new Fixture().Customize(new AutoMoqCustomization { ConfigureMembers = true });
fixture.Inject(serverConfig);
_fFProbeVideoInfo = fixture.Create<FFProbeVideoInfo>();
}
[Theory]
[InlineData(-1L)]
[InlineData(long.MinValue)]
[InlineData(long.MaxValue)]
public void CreateDummyChapters_InvalidRuntime_ThrowsArgumentException(long? runtime)
{
Assert.Throws<ArgumentException>(
() => _fFProbeVideoInfo.CreateDummyChapters(new Video()
{
RunTimeTicks = runtime
}));
}
[Theory]
[InlineData(null, 0)]
[InlineData(0L, 0)]
[InlineData(1L, 0)]
[InlineData(TimeSpan.TicksPerMinute * 5, 0)]
[InlineData((TimeSpan.TicksPerMinute * 5) + 1, 1)]
[InlineData(TimeSpan.TicksPerMinute * 50, 10)]
public void CreateDummyChapters_ValidRuntime_CorrectChaptersCount(long? runtime, int chaptersCount)
{
var chapters = _fFProbeVideoInfo.CreateDummyChapters(new Video()
{
RunTimeTicks = runtime
});
Assert.Equal(chaptersCount, chapters.Length);
}
}
Loading…
Cancel
Save